Your saved Remmina connections in Quick Settings, following the profile folder as it changes.
Open the system menu, click the Remmina tile, pick a saved connection. The list is read from Remmina's own profile directory and follows it as it changes, so a connection saved in Remmina shows up here without a reload.
Documentation → — profiles, launching, secrets, architecture, testing, packaging and releasing.
- Lists every saved
.remminaprofile, sorted by name, with an icon per protocol. - Watches the profile directory, so adding, editing or removing a profile
updates the menu straight away. It also watches where detection looks, so
installing Remmina after the extension, or setting
datadir_pathin Remmina's preferences, is picked up without logging out. - Scrolls the list once it outgrows the screen, capped at half the work area. Short lists are untouched — no scrollbar appears until there is something to scroll.
- Opens a profile through the application registered for
application/x-remmina— Remmina's own connect action. That works the same for a Flatpak and a distribution package, reuses an already-running Remmina, and lets the portal map the path into the Flatpak sandbox. - Finds the profile directory on its own, honoring
datadir_pathinremmina.pref, and falls back to the Flatpak or native data directory. - Reads only regular files, a symlink to one included, and at most 256 KiB of each, so nothing stray in the profile directory can stall or exhaust the Shell.
It never reads Remmina's stored passwords. password, ssh_passphrase and the
rest are encrypted with a key in remmina.pref, and modules/profiles.js drops
them while parsing rather than filtering them later.
just prefs, or the Settings entry at the bottom of the menu. The first row
shows which directory QuickRem resolved and how, so a wrong guess is visible
rather than silent.
| Setting | Empty means |
|---|---|
| Profile directory | Detect it: datadir_path, then a native install, then the Flatpak |
| Launch command | Open a profile through the handler registered for application/x-remmina |
A profile directory must be an absolute path or start with ~/; anything else
is reported in that first row rather than guessed at.
Launch command is the escape hatch for an unusual install. The profile path is
appended as a separate argument, never interpolated into the string. With it
empty, opening a profile goes through the application/x-remmina handler and
Open Remmina… goes through org.remmina.Remmina.desktop via
Shell.AppSystem; a command set here is used for both instead.
| File | Platform imports | Job |
|---|---|---|
extension.js |
Shell (Extension, Main) | Pair construction with teardown, nothing else |
modules/keyfile.js |
none | Read one group of a GKeyFile, exact keys only |
modules/profiles.js |
none | Parse a .remmina file, sort, map protocol to icon |
modules/paths.js |
none | Decide which directory to read |
modules/io.js |
Gio, GLib | Asynchronous probes, and bounded reads of text files |
modules/detect.js |
GLib | Probe the system and apply the rules in paths.js |
modules/store.js |
Gio, GLib, GObject | Scan and watch it; publish profiles and source |
modules/launch.js |
Gio, GLib, Shell | Decide what to run, and with which arguments |
modules/panel.js |
Clutter, Gio, GObject, Pango, St, … | The tile, its menu and its rows |
prefs.js |
Adw, Gio, GObject | Preferences, in its own process |
"none" means the module imports only other modules that import none, which is
what lets Vitest run it on plain Node and the preferences process load it. The
… for modules/panel.js is the Shell's own UI modules: Main, PopupMenu,
QuickSettings and animationUtils.
The store owns the data and the panel owns the widgets; the panel rebuilds on
the store's changed signal and holds no profile state of its own.
QuickToggleMenu has no scrolling of its own. Measured on a 1080p screen, 30
profiles want 1296px of a 1048px work area and the surplus is simply clipped.
GNOME's own Wi-Fi menu answers this by showing eight networks and sending you to
Settings for the rest, which suits a list you skim but not one you pick from.
So modules/panel.js subclasses PopupMenuSection and swaps its actor for an
St.ScrollView around the same box. PopupMenuBase.addMenuItem() adds
section.actor and does its bookkeeping against the section object, so key
navigation, open-state propagation and activation all survive the swap. The cap
is recomputed just before every open and on a rebuild while the menu is open,
which picks up a monitor or text-scaling change without watching for either. It
has to come before the open: the menu measures the height it animates to first
and only then says it is opening.
Everything lands through a pull request whose title is a Conventional Commit. See AGENTS.md for the repository's conventions.
git switch -c type/short-description
just ci
gh pr create --fill
gh pr merge --squash --autoRequires GNOME Shell 49 or 50. Requires Remmina and its saved connection profiles.
Download the latest release ZIP and install it for your user. xh is a download tool; you can also download the ZIP from GitHub in a browser. Installing compiles the settings schema.
xh --download GET https://github.com/Ghost-Assembly/quickrem/releases/latest/download/quickrem@napalm255.github.io.shell-extension.zip
gnome-extensions install --force quickrem@napalm255.github.io.shell-extension.zipLog out and back in so GNOME discovers the extension, then enable it:
gnome-extensions enable quickrem@napalm255.github.ioInstall mise and activate it in your shell. Clone the repository, install its pinned tools, and build and install the same ZIP used for releases:
git clone https://github.com/Ghost-Assembly/quickrem.git
cd quickrem
mise install
mise exec -- just setup
mise exec -- just installLog out and back in, then run just enable. Run just prefs to open preferences. After updating a loaded extension, start a new session to load its new code; opening preferences does not reload GNOME Shell.
Disable and uninstall the extension for your user. These commands preserve saved settings and other user data.
gnome-extensions disable quickrem@napalm255.github.io
gnome-extensions uninstall quickrem@napalm255.github.ioFrom a clone, just uninstall performs the same steps. Disabling with just disable leaves the extension installed.
just test runs the JavaScript suite with Vitest, the shared tooling tests, and any project-specific offline suites. just coverage reports runtime JavaScript and Python tooling coverage, including untested files. Test stubs and generated reports are not runtime source.
just test-docs runs Playwright and axe in Chromium and Firefox: dark and light accessibility checks, keyboard navigation, mobile layout, reduced motion, links, metadata, local assets, and no page JavaScript. Automated accessibility checks still require human review of reading and focus order.
just test-live checks the package and runs isolated GNOME lifecycle checks. It is a separate local check, not proof of compatibility from a hosted runner. Verify each declared GNOME version and complete the project's manual checks before releasing.
The offline suite verifies file-watcher coalescing, unsafe file types, argument-vector launching, preferences, and menu lifetimes. The isolated Shell check adds and removes profiles across enable/disable/re-enable. Use just fixtures 5 for throwaway profiles, then just fixtures-clean to remove them. Verify real Remmina launching manually.
just build
just pack-checkThe output is quickrem@napalm255.github.io.shell-extension.zip at the repository root, with metadata.json at the archive root. Python's standard library packages the explicit runtimeFiles allowlist in quick-project.json, using stable file order and timestamps.
just pack-check compares both filenames and file contents with GNOME's official packer and validates shipped icons. Docs, tests, dependencies, credentials, downloaded binaries, and development artifacts stay outside the ZIP. Update the runtime allowlist when adding a runtime file.
Run just ci, just test-live, and the project manual checklist. Set metadata.json version-name and package.json version to the same new version. The GNOME Extensions website assigns the numeric metadata.json version during submission. Update the npm lockfile, regenerate the docs, and commit the reviewed changes to main through a passing pull request.
Create and push a v-prefixed tag for that version. The release workflow verifies the version, main ancestry, and successful required checks for the tagged commit, then attaches its tested ZIP to a GitHub release. It does not upload to extensions.gnome.org; that submission and its review remain manual.
mise.toml pins runtime and CLI versions; justfile owns commands; npm owns development dependencies and the lockfile. GNOME libraries come from the host. On image-based Fedora, use the host's available tools or a toolbox/distrobox for missing system packages; do not layer packages onto the OS.
just setup # install pinned tools, dependencies, and browsers
just fmt # format source and configuration
just lint # verify template, generated docs, source, and schemas
just test # JavaScript, Python, and project offline tests
just coverage # report JavaScript and Python coverage without source exclusions
just test-docs # Chromium and Firefox documentation checks
just security # dependencies, secrets, and workflow checks
just build # build the runtime-only extension ZIP
just pack-check # compare files and contents with GNOME's packer
just ci # complete local verification and packaging
just test-live # isolated GNOME lifecycle and project integration checks
just docs # serve the static site at localhost:8000
just template-check # verify the pinned canonical template
just template-status # report a newer approved template revisionGitHub requires local verification, security analysis, and completed Sonar analysis. The shared Sonar policy requires zero security, reliability, and maintainability issues and zero duplicated lines. PR checks cover changed code; main checks cover the entire project. Missing configuration fails instead of silently skipping analysis. Pages publishes the tested docs only after the required checks pass on main.
Common tooling and these instructions are generated from a pinned canonical template. Change that source and synchronize its approved revision; do not edit generated sections or locally bless drift. Extension-specific behavior belongs in project configuration and project.just.
GPL-3.0-or-later.