Skip to main content

Custom Widgets

Wave allows users to create their own widgets to uniquely customize their experience for what works for them. While we plan on greatly expanding on this in the future, it is already possible to make some widgets that you can access at the press of a button. All widgets can be created by modifying the <WAVETERM_HOME>/config/widgets.json file. By adding a widget to this file, it is possible to add widgets to the widget bar. By default, the widget bar looks like this: The default widget bar

By adding additional widgets, it is possible to get a widget bar that looks like this:

A widget bar with custom widgets added

The Structure of a Widget

All widgets share a similar structure that roughly looks like the example below:

"<widget name>": {
"icon": "<font awesome icon name>",
"label": "<the text label of the widget>",
"color": "<the color of the label>",
"blockdef": {
"meta": {
"view": "term",
"controller": "cmd",
"cmd": "<the actual cli command>"
}
}
}

This consists of a couple different parts. First and foremost, each widget has a unique identifying name. The value associated with this name is the outer WidgetConfigType. It is outlined in red below:

An example of a widget with outer keys labeled as WidgetConfigType and inner keys labeled as MetaTSType. In the example, the outer keys are icon, label, color, and blockdef. The inner keys are view, controller, and cmd.

This WidgetConfigType is shared between all types of widgets. That is to say, all widgets—regardless of type— will use the same keys for this. The accepted keys are:

KeyDescription
"display:order"(optional) Overrides the order of widgets with a number in case you want the widget to be different than the order provided in the widgets.json file. Defaults to 0.
"icon"(optional) The name of a font awesome icon. Defaults to "browser".
"color"(optional) A string representing a color as would be used in CSS. Hex codes and custom CSS properties are included. This defaults to "var(--secondary-text-color)" which is a color wave uses for text that should be differentiated from other text. Out of the box, it is "#c3c8c2".
"label"(optional) A string representing the label that appears underneath the widget. It will also act as a tooltip on hover if the "description" key isn't filled out. It is null by default.
"description"(optional) A description of what the widget does. If it is specified, this serves as a tooltip on hover. It is null by default.
"blockdef"This is where the the non-visual portion of the widget is defined. Note that all further definition takes place inside a meta object inside this one.
info

Font Awesome Icons

Font Awesome provides a ton of useful icons that you can use as a widget icon in your app. At its simplest, you can just provide the icon name and it will be used. For example, the string "house", will provide an icon containing a house. We also allow you to apply a few different styles to your icon by modifying the name as follows:

formatdescription
<icon name>The plain icon with no additional styles applied.
solid@<icon name>Adds the fa-solid class to the icon to fill in the content with a fill color rather than leaving it a background.
regular@<icon name>Adds the fa-regular class to the icon to ensure the content will not have a fill color and will use a standard outline instead.
brands@<icon name>This is required to add the required fa-brands class to an icon associated with a brand. Without this, brand icons will not render properly. This will not work with icons that aren't brand icons.

The other options are part of the inner MetaTSType (outlined in blue in the image). This contains all of the details about how the widget actually works. The valid keys vary with each type of widget. They will be individually explored in more detail below.

Terminal and CLI Widgets

A terminal widget, or CLI widget, is a widget that simply opens a terminal and runs a CLI command. They tend to look something like the example below:

{
<... other widgets go here ...>,
"<widget name>": {
"icon": "<font awesome icon name>",
"label": "<the text label of the widget>",
"color": "<the color of the label>",
"blockdef": {
"meta": {
"view": "term",
"controller": "cmd"
"cmd": "<the actual cli command>"
}
}
},
<... other widgets go here ...>
}

The WidgetConfigType takes the usual options common to all widgets. The MetaTSType can include the keys listed below:

KeyDescription
"view"A string that specifies the general type of widget. In the case of custom terminal widgets, this must be set to "term".
"controller"A string that specifies the type of command being used. For more persistent shell sessions, set it to "shell". For one off commands, set it to "cmd". When "cmd" is set, the widget has an additional refresh button in its header that allows the command to be re-run.
"cmd"(optional) When the "controller" is set to "cmd", this option provides the actual command to be run. Note that because it is run as a command, there is no shell session unless you are launching a command that contains a shell session itself. Defaults to an empty string.
"cmd:interactive"(optional) When the "controller" is set to `"term", this boolean adds the interactive flag to the launched terminal. Defaults to false.
"cmd:login"(optional) When the "controller" is set to "term", this boolean adds the login flag to the term command. Defaults to false.
"cmd:runonstart"(optional) The command will rerun when the app is started. Without it, you must manually run the command. Defaults to true.
"cmd:runonce"(optional) Runs on start, but then sets "cmd:runonce" and "cmd:runonstart" to false (so future runs require manual restarts)
"cmd:clearonstart"(optional) When the cmd runs, the contents of the block are cleared out. Defaults to false.
"cmd:closeonexit"(optional) Automatically closes the block if the command successfully exits (exit code = 0)
"cmd:closeonexitforce"(optional) Automatically closes the block if when the command exits (success or failure)
"cmd:closeonexitdelay(optional) Change the delay between when the command exits and when the block gets closed, in milliseconds, default 2000
"cmd:env"(optional) A key-value object represting environment variables to be run with the command. Currently only works locally. Defaults to an empty object.
"cmd:cwd"(optional) A string representing the current working directory to be run with the command. Currently only works locally. Defaults to the home directory.
"cmd:nowsh"(optional) A boolean that will turn off wsh integration for the command. Defaults to false.
"term:localshellpath"(optional) Sets the shell used for running your widget command. Only works locally. If left blank, wave will determine your system default instead.
"term:localshellopts"(optional) Sets the shell options meant to be used with "term:localshellpath". This is useful if you are using a nonstandard shell and need to provide a specific option that we do not cover. Only works locally. Defaults to an empty string.

Example Shell Widgets

If you have multiple shells installed on your machine, there may be times when you want to use a non-default shell. For cases like this, it is easy to create a widget for each.

Suppose you want a widget to launch a fish shell. Once you have fish installed on your system, you can define a widget as

{
<... other widgets go here ...>,
"fish" : {
"icon": "fish",
"color": "#4abc39",
"label": "fish",
"blockdef": {
"meta": {
"view": "term",
"controller": "shell",
"term:localshellpath": "/usr/local/bin/fish",
"term:localshellopts": "-i -l"
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch a terminal running the fish shell. The example fish widget

info

It is possible that fish is not in your path. If this is true, using "fish" as the value of "term:localshellpath" will not work. In these cases, you will need to provide a direct path to it. This is often somewhere like "/usr/local/bin/fish", but it may be different on your system.

If you want to do the same for something like Powershell Core, or pwsh, you can define the widget as

{
<... other widgets go here ...>,
"pwsh" : {
"icon": "rectangle-terminal",
"color": "#2671be",
"label": "pwsh",
"blockdef": {
"meta": {
"view": "term",
"controller": "shell",
"term:localshellpath": "pwsh"
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch a terminal running the pwsh shell. The example pwsh widget

info

It is possible that pwsh is not in your path. If this is true, using "pwsh" as the value of "term:localshellpath" will not work. In these cases, you will need to provide a direct path to it. This could be somewhere like "/usr/local/bin/pwsh" on a Unix system or "C:\Program Files\PowerShell\7\pwsh.exe" on Windows. but it may be different on your system. Also note that both pwsh.exe and pwsh work on Windows, but only pwsh works on Unix systems.

Example Cmd Widgets

Here are a few simple cmd widgets to serve as examples.

Suppose I want a widget that will run speedtest-go when opened. Then, I can define a widget as

{
<... other widgets go here ...>,
"speedtest" : {
"icon": "gauge-high",
"label": "speed",
"blockdef": {
"meta": {
"view": "term",
"controller": "cmd",
"cmd": "speedtest-go --unix",
"cmd:clearonstart": true
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch a terminal running the speedtest-go --unix command. The example speedtest widget

Using "cmd" for the "controller" is the simplest way to accomplish this. "cmd:clearonstart" isn't necessary, but it makes it so every time the command is run (which can be done by right clicking the header and selecting Force Controller Restart), the previous contents are cleared out.

Now suppose I wanted to run a TUI app, for instance, dua. Well, it turns out that you can more or less do the same thing:

{
<... other widgets go here ...>,
"dua" : {
"icon": "brands@linux",
"label": "dua",
"blockdef": {
"meta": {
"view": "term",
"controller": "cmd",
"cmd": "dua"
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch a terminal running the dua command. The example speedtest widget

Because this is a TUI app that does not return anything when closed, the "cmd:clearonstart" option doesn't change the behavior, so it has been excluded.

Web Widgets

Sometimes, it is desireable to open a page directly to a website. That can easily be accomplished by creating a custom "web" widget. They have the following form in general:

{
<... other widgets go here ...>,
"<widget name>": {
"icon": "<font awesome icon name>",
"label": "<the text label of the widget>",
"color": "<the color of the label>",
"blockdef": {
"meta": {
"view": "web",
"url": "<url of the first webpage>"
}
}
},
<... other widgets go here ...>
}

The WidgetConfigType takes the usual options common to all widgets. The MetaTSType can include the keys listed below:

KeyDescription
"view"A string that specifies the general type of widget. In the case of custom web widgets, this must be set to "web".
"url"This string is the url of the current page. As part of a widget, it will serve as the page the widget starts at. If not specified, this will default to the globally configurable "web:defaulturl" which is https://github.com/wavetermdev/waveterm on a fresh install.
"pinnedurl"(optional) This string is the url the homepage button will take you to. If not specified, this will default to the globally configurable "web:defaulturl" which is https://github.com/wavetermdev/waveterm on a fresh install.

Example Web Widgets

Say you want a widget that automatically starts at YouTube and will use YouTube as the home page. This can be done using:

{
<... other widgets go here ...>,
"youtube" : {
"icon": "brands@youtube",
"label": "youtube",
"blockdef": {
"meta": {
"view": "web",
"url": "https://youtube.com",
"pinnedurl": "https://youtube.com"
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch a web widget on the youtube homepage. The example speedtest widget

Alternatively, say you want a web widget that opens to github as if it were a bookmark, but will use google as its home page after that. This can easily be done with:

{
<... other widgets go here ...>,
"github" : {
"icon": "brands@github",
"label": "github",
"blockdef": {
"meta": {
"view": "web",
"url": "https://github.com",
"pinnedurl": "https://google.com"
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch a web widget on the github homepage. The example speedtest widget

Sysinfo Widgets

The Sysinfo Widget is intentionally kept to a very small subset of possible values that we will expand over time. But it is still possible to configure your own version of it—for instance, if you want to load a different plot by default. The general form of this widget is:

{
<... other widgets go here ...>,
"<widget name>": {
"icon": "<font awesome icon name>",
"label": "<the text label of the widget>",
"color": "<the color of the label>",
"blockdef": {
"meta": {
"view": "sysinfo",
"graph:numpoints": <the max number of points in the graph>,
"sysinfo:type": <the name of the plot collection>,
}
}
},
<... other widgets go here ...>
}

The WidgetConfigType takes the usual options common to all widgets. The MetaTSType can include the keys listed below:

KeyDescription
"view"A string that specifies the general type of widget. In the case of custom sysinfo widgets, this must be set to "sysinfo".
"graph:numpoints"The maximum amount of points that can be shown on the graph. Equivalently, the number of seconds the graph window covers. This defaults to 100.
"sysinfo:type"A string representing the collection of types to show on the graph. Valid values for this are "CPU", "Mem", "CPU + Mem", and All CPU. Note that these are case sensitive. If no value is provided, the plot will default to showing "CPU".

Example Sysinfo Widgets

Suppose you have a build process that lasts 3 minutes and you'd like to be able to see the entire build on the sysinfo graph. Also, you would really like to view both the cpu and memory since both are impacted by this process. In that case, you can set up a widget as follows:

{
<... other widgets go here ...>,
"3min-info" : {
"icon": "circle-3",
"label": "3mininfo",
"blockdef": {
"meta": {
"view": "sysinfo",
"graph:numpoints": 180,
"sysinfo:type": "CPU + Mem"
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch the CPU and Memory plots by default with 180 seconds of data. The example speedtest widget

Now, suppose you are fine with the default 100 points (and 100 seconds) but would like to show all of the CPU data when launched. In that case, you can write:

{
<... other widgets go here ...>,
"all-cpu" : {
"icon": "chart-scatter",
"label": "all-cpu",
"blockdef": {
"meta": {
"view": "sysinfo",
"sysinfo:type": "All CPU"
}
}
},
<... other widgets go here ...>
}

This adds an icon to the widget bar that you can press to launch All CPU plots by default.

The example speedtest widget