Compare commits

...

91 commits
v19 ... main

Author SHA1 Message Date
Exidex
ca066da5c9
Update README.md
Some checks failed
format / rust (push) Failing after 1s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 3s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-10-02 18:55:18 +02:00
Exidex
ce76f8211c
GitHub Actions workflow to bump Gauntlet version in WinGet
Some checks failed
format / rust (push) Failing after 3s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 3s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-08-24 18:21:19 +02:00
Exidex
e62a89f45e Prepare for v21 release
Some checks failed
format / rust (push) Failing after 3s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 4s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-08-16 15:39:58 +00:00
Exidex
1e8bd2eca9
Update CHANGELOG.md 2025-08-16 17:37:07 +02:00
Exidex
de5166ccae
Remove padding from content paragraph text
Some checks failed
build / build-linux (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-windows (push) Waiting to run
format / rust (push) Failing after 3s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 3s
2025-08-15 18:23:24 +02:00
Exidex
1116190f7d
Use lucide icons for shortcuts widget 2025-08-15 18:13:53 +02:00
Exidex
3516d35a35
Fix windows build 2025-08-15 17:24:49 +02:00
Exidex
a577202ec9
Implement native hud notifications on Linux, enable by default 2025-08-15 17:00:24 +02:00
Exidex
b008fcd907
Focus second item in Opened windows view as an alternative window 2025-08-15 16:04:47 +02:00
Exidex
1a2368ffde
Fix Opened Windows view often not showing any windows 2025-08-15 16:00:06 +02:00
Exidex
24405c92bc
Extend focusedItemId description
Some checks failed
format / rust (push) Failing after 2s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 4s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-08-10 21:30:20 +02:00
Exidex
204de4d88c
Add ability to programmatically control focus on list and grid 2025-08-10 21:24:08 +02:00
Exidex
4721a70111
Restrict js heap memory size to 50 mb per plugin
Some checks failed
build / build-linux (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-windows (push) Waiting to run
format / rust (push) Failing after 3s
format / nix (push) Failing after 4s
nix build / all (push) Failing after 5s
2025-08-10 13:13:08 +02:00
Exidex
204e4182c9
Make text smaller in a main view search results, plugin view, action panel and bottom panel right side 2025-08-10 11:39:55 +02:00
Exidex
62a16d04e0
Fix hud view being shown in a main window sometimes
Some checks failed
build / build-linux (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-windows (push) Waiting to run
format / rust (push) Failing after 2s
format / nix (push) Failing after 2s
nix build / all (push) Failing after 4s
2025-08-10 10:50:29 +02:00
Exidex
41f0fb460a
Fix action execution from inline view not being executed after some refactor
Some checks failed
build / build-linux (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-windows (push) Waiting to run
format / rust (push) Failing after 3s
format / nix (push) Failing after 2s
nix build / all (push) Failing after 3s
2025-08-09 19:23:29 +02:00
Exidex
e7c1f0343e
Rework viewport scrolling when using keyboard navigation
Some checks failed
build / build-linux (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-windows (push) Waiting to run
format / rust (push) Failing after 4s
format / nix (push) Failing after 2s
nix build / all (push) Failing after 4s
2025-08-08 22:02:41 +02:00
Exidex
32bf43438c
Pin windows version to 2022 in github actions
Some checks failed
format / rust (push) Failing after 2s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 3s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-08-02 15:40:39 +02:00
Exidex
0528b96fae
Fix back navigation being treated as whole separate view open session
Some checks failed
format / rust (push) Failing after 3s
format / nix (push) Failing after 2s
nix build / all (push) Failing after 4s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-07-31 21:25:57 +02:00
Exidex
39bf811b11
Fix main window disappearing and reappearing when opening a plugin view 2025-07-31 20:18:56 +02:00
Exidex
f82841aad4
Refactor react view container
Some checks failed
build / build-linux (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-windows (push) Waiting to run
format / rust (push) Failing after 3s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 3s
2025-07-30 21:11:23 +02:00
Exidex
35afc3b0cd
Update winit fork, viewport handling fix to layer shell
Some checks failed
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
format / rust (push) Failing after 3s
format / nix (push) Failing after 3s
nix build / all (push) Failing after 3s
2025-07-27 18:23:07 +02:00
Exidex
dea6aee03a
Fix formatting 2025-07-27 17:34:08 +02:00
Exidex
3245dcee96
Focus setting window after it as created 2025-07-27 17:16:00 +02:00
Exidex
f41ab9233b
Merge settings app into the main app 2025-07-27 16:50:07 +02:00
Exidex
136b2c2ab6
Fix more bundled plugins and examples after breaking change
Some checks failed
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
format / rust (push) Failing after 2s
format / nix (push) Failing after 2s
nix build / all (push) Failing after 3s
2025-07-25 22:11:28 +02:00
Exidex
b4340f4c10
Fix bundled plugins and examples after breaking change 2025-07-25 22:06:17 +02:00
Exidex
72123db351
Refine nullability of event arguments. Distinguish between null and undefined properties when parsing react component tree 2025-07-25 20:11:32 +02:00
Exidex
e1f2ca85ec
Update winit fork, fix fractional scaling for layershell
Some checks failed
format / rust (push) Failing after 2s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 3s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-07-21 21:32:43 +02:00
Exidex
242f5a2eea
Rewrite react component parser into procmacros, better error reporting 2025-07-21 21:16:53 +02:00
Exidex
729b4f695f
Clean up couple of things
Some checks failed
format / rust (push) Failing after 3s
format / nix (push) Failing after 2s
nix build / all (push) Failing after 3s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-07-18 17:44:51 +02:00
Exidex
3cdd16cfb3
Fix panic if state of the widget under specific id changed type
Some checks failed
format / rust (push) Failing after 2s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 3s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-07-17 08:10:05 +02:00
Exidex
21f8ab6d09
Fix some screenshots from screenshot generator being blank
Some checks failed
format / rust (push) Failing after 2s
format / nix (push) Failing after 1s
nix build / all (push) Failing after 2s
build / build-linux (push) Has been cancelled
build / build-macos (push) Has been cancelled
build / build-windows (push) Has been cancelled
2025-07-15 19:48:02 +02:00
Exidex
b7b8413146
Fix inline view being recreated each time key is pressed in search bar, causing useRef not preserving value
Some checks failed
build / build-linux (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-windows (push) Waiting to run
format / rust (push) Failing after 2s
format / nix (push) Failing after 2s
nix build / all (push) Failing after 3s
2025-07-14 22:07:09 +02:00
dennkaii
97fc6360ea
Fix nix build (#85) 2025-07-11 18:00:46 +02:00
Exidex
e643dcc4f7
Update README.md 2025-07-07 22:04:14 +02:00
Exidex
771e2f95d7 Prepare for v20 release 2025-07-07 19:01:00 +00:00
Exidex
5c2db4d048
Update CHANGELOG.md 2025-07-07 20:57:54 +02:00
Exidex
6bb5f40065
Change action panel shortcut to Ctrl/Cmd + K, to match similar pattern in other apps 2025-07-07 19:37:45 +02:00
Exidex
94c8984649
Disable global shortcuts by default on wayland, add config option to enable if legacy x11 api is supported 2025-07-07 19:26:00 +02:00
Exidex
1c23514aac
Fix formatting 2025-07-06 13:15:14 +02:00
Exidex
08c5bb2c49
Fix sys tray open main and settings windows actions causing deadlock 2025-07-06 13:13:42 +02:00
Exidex
a8287ede60
Update iced and winit fork 2025-07-06 12:02:33 +02:00
Exidex
3a457450cb
Relax layer_shell requirement on linux wayland. Add config file setting to choose between normal and layer shell window 2025-07-04 19:50:55 +02:00
Exidex
bced4daedd
Cli gauntlet open now hides window when pressed while window is open, matching behavior of global shortcut 2025-07-03 18:59:24 +02:00
Exidex
283285c317
Replace iced_layer shell with layer_shell implementation from winit fork 2025-07-01 23:24:22 +02:00
Exidex
70e815b795
Fix formatting 2025-06-24 21:00:23 +02:00
Exidex
9111dd074b
Fix build on non-linux systems 2025-06-24 20:57:43 +02:00
Exidex
d1e61d4d19
Massively simplify scenario runner 2025-06-22 20:35:31 +02:00
Exidex
f529d061ff
Fix layershell taking exclusive keyboard focus, preventing from clicking anything else 2025-06-19 20:07:49 +02:00
Exidex
6645ce21ad
Refactor server and window state of ui into separate modules 2025-06-19 19:39:33 +02:00
Exidex
a0bbad9fea
Slightly refactor window management behaviour into separate module 2025-06-19 16:24:55 +02:00
Exidex
f20537181e
Bump npm dependencies 2025-06-19 15:03:41 +02:00
Exidex
71e8adf44d
Pin ubuntu version in github actions to lower glibc requirement from 2.38 to 2.35 2025-06-19 14:32:52 +02:00
Exidex
f51a123411
Change layershell namespace from Gauntlet to gauntlet, set hud to gauntlet-hud 2025-06-19 14:28:19 +02:00
Exidex
0d7a9db4d9
Fix icons font not being loaded in main window 2025-06-19 14:21:15 +02:00
Exidex
2afecf3b80
Fix padding on grid component after dependency updates 2025-06-19 12:05:10 +02:00
Exidex
29b1a4ab36
Fix useStorage and useCache hooks crashing plugin runtime when closing the view 2025-06-19 11:48:53 +02:00
Exidex
75fa1f3af5
Bump a lot of rust dependencies 2025-06-19 11:18:51 +02:00
Exidex
e7f621018c
Move GlobalHotkeyManager out of ApplicationManger to make it Send. Fixes build on Windows 2025-06-19 11:10:02 +02:00
Gabriel Berto
3d1beaca15 fix: show full cause when printing error 2025-06-18 21:38:37 +02:00
Exidex
8fd14b4dab
Replace usages of BackendForFrontendApi with direct calls to ApplicationManager 2025-06-16 21:28:35 +02:00
Exidex
e1787e7dc8
Fix macOS build 2025-06-15 19:54:25 +02:00
Exidex
9021f0580e
Bump iced_fonts version with fix for release build 2025-06-15 19:10:13 +02:00
Exidex
a91bf3066f
Explicitly add some iced features 2025-06-15 16:21:49 +02:00
Exidex
f2fadf8b70
Update iced to latest master. Remove iced_aw, iced_table dependencies. Remove DatePicker component 2025-06-15 14:29:19 +02:00
Philippe Loctaux
924fe69069 github actions: formatting: nix with alejandra, remove verbose for rustfmt 2025-06-14 20:39:50 +02:00
Philippe Loctaux
9fe9ccdb6b added editorconfig, with yaml 2025-06-14 20:39:50 +02:00
Philippe Loctaux
bce1969610 plugins/gauntlet: applications/macos: follow symlinks inside /Applications
Symlinks are not followed by default in function `walk` in the package deno @std/fs
2025-06-12 20:33:26 +02:00
Exidex
f7d7022000
Fix build 2025-06-04 22:14:46 +02:00
Exidex
e13ff1d688
Fix scenario runner build 2025-06-04 21:53:51 +02:00
Exidex
04e0dfd44a
Update settings ui screenshot in README.md 2025-06-02 20:13:39 +02:00
Exidex
547f502030
Fix deadlock during database call while typing in main search bar 2025-06-02 20:01:36 +02:00
Exidex
d5b4c71a61
Add missing focus screenshot scenarios for documentation 2025-06-01 13:24:47 +02:00
Exidex
41107d2043
Update README.md 2025-06-01 13:10:43 +02:00
Exidex
fee4e9a18b
Fix macos build 2025-05-31 21:35:42 +02:00
Exidex
747cb9435d
Fix windows build 2025-05-31 20:31:05 +02:00
Exidex
901f8fdfa3
Explicitly add bundled rusqlite feature 2025-05-31 19:34:22 +02:00
Exidex
30963ffd73
Fix nix hash mismatch. Add nix build to github actions 2025-05-31 19:23:23 +02:00
Exidex
1706840b8b
Migrate sqlite db migrations from sqlx migrations to rusqlite migrations 2025-05-30 23:50:23 +02:00
Exidex
7e46395152
Fix deno runtime not starting 2025-05-29 19:22:13 +02:00
Exidex
5181a366e7
Update lots of dependencies in Cargo.lock 2025-05-28 20:06:16 +02:00
Exidex
c0f61f444d
WIP Migration from sqlx to rusqlite. No sql migrations yet. Doesn't compile 2025-05-27 22:44:24 +02:00
Exidex
b0fdaa6b9e
Switch edition 2024 again after revert 2025-05-25 15:00:29 +02:00
Exidex
a0275cce28
Revert plugin runtime --extern rustc flag 2025-05-25 14:36:07 +02:00
Exidex
80bb33690b
Run cargo fmt 2025-05-24 14:15:12 +02:00
Exidex
a8182f4b2e
Switch to edition 2024, resolve all cargo warnings 2025-05-24 11:01:03 +02:00
Exidex
3599837033
Split plugin runtime (specifically deno) into separate workspace, and include it via --extern rustc flag 2025-05-23 20:59:04 +02:00
Exidex
2a80b51ff5
Update package-lock.json 2025-05-22 20:34:53 +02:00
Exidex
7a47cdb941
Change screenshot generator theme to macos dark 2025-05-22 15:22:59 +02:00
Exidex
c9019ca772
Svg component plugin examples 2025-05-22 15:22:02 +02:00
323 changed files with 16363 additions and 15297 deletions

14
.editorconfig Normal file
View file

@ -0,0 +1,14 @@
# EditorConfig is awesome: https://editorconfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
[*.yaml]
indent_style = space
indent_size = 2

View file

@ -1,12 +1,19 @@
name: Format
name: format
on: [push, pull_request]
jobs:
all:
runs-on: ubuntu-latest
rust:
runs-on: ubuntu-22.04
steps:
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- uses: actions/checkout@v4
- name: Check format
run: cargo +nightly fmt --all -- --check --verbose
- name: rustfmt
run: cargo +nightly fmt --all -- --check
nix:
runs-on: ubuntu-22.04
steps:
- uses: cachix/install-nix-action@v31
- uses: actions/checkout@v4
- name: alejandra
run: nix shell nixpkgs#alejandra -c alejandra -c .

11
.github/workflows/nix.yaml vendored Normal file
View file

@ -0,0 +1,11 @@
name: nix build
on: [push, pull_request]
jobs:
all:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v25
with:
nix_path: nixpkgs=channel:nixos-unstable
- run: nix-build

View file

@ -25,7 +25,7 @@ on:
jobs:
publish-init:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
github-release-id: ${{ steps.init-step.outputs.github-release-id }}
steps:

View file

@ -14,7 +14,7 @@ on:
jobs:
run-on-linux:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- run: sudo apt-get update

View file

@ -14,7 +14,7 @@ on:
jobs:
run-on-windows:
runs-on: windows-latest
runs-on: windows-2022
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

27
.github/workflows/winget.yaml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Publish to WinGet
on:
release:
types: [published]
env:
VERSION_REGEX: '^v(\d+)$'
# winget-create will read the following environment variable to access the GitHub token needed for submitting a PR
# See https://aka.ms/winget-create-token
WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_TOKEN }}
jobs:
publish:
runs-on: windows-latest # Action can only run on Windows
steps:
- name: Publish To WinGet
run: |
$release = '${{ toJSON(github.event.release) }}' | ConvertFrom-Json
$wingetRelevantAsset = $release | Select-Object -Property assets | Where-Object { $_.name -like '*.msi' } | Select-Object -First 1
$regex = [Regex]::New($env:VERSION_REGEX)
$version = $regex.Match($release.tag_name).Groups[1].Value
$wingetPackage = "Exidex.Gauntlet"
& curl.exe -JLO https://aka.ms/wingetcreate/latest
& .\wingetcreate.exe update $wingetPackage -s -v $version -u $wingetRelevantAsset.browser_download_url

View file

@ -3,12 +3,90 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project doesn't adhere to Semantic Versioning, see [Versioning](./README.md#versioning)
and this project doesn't adhere to Semantic Versioning, see [Versioning](https://gauntlet.sh/docs/information/versioning)
For changes in `@project-gauntlet/tools` see [separate CHANGELOG.md](https://github.com/project-gauntlet/tools/blob/main/CHANGELOG.md)
## [Unreleased]
## [21] - 2025-08-16
### General
- When opening `Opened windows` view second item is now focused by default
- Because the window ordering is "most recently focused on the top", second can be considered as an "alternative" application that was focused before the last one
- Implemented native hud notifications on Linux
- Enabled by default
- `linux.native_hud` boolean configuration option is available to disable this
- Restricted JavaScript runtime heap size to 50 MB per plugin
### Plugins
- It is now possible to programmatically control which item in grid/list is focused
- `<List/>` and `<Grid/>` now have new property `focusedItemId`
- If `focusedItemId` property is `undefined` the focus is uncontrolled
- if `focusedItemId` property is `null` the focus is controlled and unset
- if `focusedItemId` property is `string` the focus is controlled and set to item with specified `id`
- Refine nullability of event function arguments on React components
- **BREAKING CHANGE**: Following function properties now return `null` as an argument instead of `undefined`
- `<Action/>`'s `onAction`
- `<List/>`'s `onItemFocusChange`
- `<Gird/>`'s `onItemFocusChange`
- For following function property arguments `undefined` was removed from type signature
- `<SearchBar/>`'s `onChange`
- `<TextField/>`'s `onChange`
- `<PasswordField/>`'s `onChange`
- `<Select/>`'s `onChange`
### UI/UX improvements
- Text in main view search results, plugin view, action panel and bottom panel right side is now smaller
- Removed padding from content paragraph text
- Keyboard shortcuts in UI now use Lucide icons
### Fixes
- Settings are now part of the main application instead of the separate process
- Only single settings window can now exist at the same time.
- Fixed inline view being recreated each time key is pressed in search bar, causing useRef not preserve the value
- Fixed back navigation being treated as whole separate view session
- This also fixed state leaking between views when changing views very quickly
- Fixed panic if state of the widget under specific id changed type
- Fixed blurry window on Linux Wayland LayerShell due to missing fractional scaling support
- Reworked viewport scrolling when using keyboard navigation
- Fixed incorrect scrolling distance for long lists/grids
- Fixed scrolling position sometimes not being reset correctly
- Fixed `Opened Windows` view often not showing any windows
## [20] - 2025-07-07
### General
- Linux Gnome Wayland support
- `zwlr_layer_shell_v1` Wayland protocol is no longer required. It is still preferred, but if not supported application falls back to regular `xdg_shell` window
- Added `wayland.main_window_surface` config option to allow customization of this behavior
- Linux Wayland LayerShell improvements
- **BREAKING CHANGE**: Changed LayerShell surface namespace from `Gauntlet` to `gauntlet` for main window, and set namespace to `gauntlet-hud` for hud window
- Migrated to yet another LayerShell implementation
- Fixes event/keystroke duplication after suspend
- Disabled global shortcuts by default on Linux Wayland
- Added `wayland.global_shortcuts_api` config option to allow usage of legacy x11 api if supported by given environment
- Global Shortcuts XDG Portal is not and will not be supported until there will be major changes to it
- Input Method Editor (IME) support for input fields
- Changed action panel shortcut from <kbd>ALT</kbd> + <kbd>K</kbd> to <kbd>CTRL</kbd> + <kbd>K</kbd> (Windows/Linux) and <kbd>CMD</kbd> + <kbd>K</kbd> (macOS), to match similar pattern in other apps
- `gauntlet open` CLI command now hides window when executed while window is open, matching behavior of global shortcut
- Lots of internal dependency updates
### Plugins
- Updated Deno to 2.3.3
- **BREAKING CHANGE**: Remove `<DatePicker/>` component
- It caused difficulties when updating dependencies and needs a complete rework
### Fixes
- Reduced glibc requirement from 2.38 to 2.35
- Fixed systray open main and settings windows actions causing deadlock
- Fixed LayerShell window taking exclusive keyboard focus preventing any desktop interactions while window was open
- Fixed `useStorage` and `useCache` hooks crashing plugin runtime when closing the view
- Fixed `npm run dev` not showing full error cause (contributed by @Gabrielbdd)
- Fixed nix applications not being detected on macOS by following links inside `/Applications` (contributed by @deadbaed)
## [19] - 2025-05-11
### General

5955
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,44 +5,39 @@ repository = "https://github.com/project-gauntlet/gauntlet"
[workspace]
members = [
"rust/management_client",
"rust/client",
"rust/server",
"rust/common",
"rust/common_ui",
"rust/common_plugin_runtime",
"rust/utils",
"rust/utils_macros",
"rust/cli",
"rust/component_model",
"rust/scenario_runner",
"rust/plugin_runtime",
"rust/manifest_schema",
"rust/plugin_runtime",
]
[workspace.package]
edition = "2021"
edition = "2024"
[workspace.dependencies]
# iced
#iced = { version = "0.13.99", features = ["tiny-skia", "wgpu", "tokio", "lazy", "advanced", "image", "web-colors", "svg"] }
iced = { git = "https://github.com/project-gauntlet/iced.git", branch = "gauntlet-0.13", default-features = false, features = ["tiny-skia", "wgpu", "tokio", "advanced", "image", "web-colors", "svg"] }
#iced_aw = { version = "0.11.99", features = ["date_picker", "wrap", "number_input", "grid", "spinner"] }
iced_aw = { git = "https://github.com/project-gauntlet/iced_aw.git", branch = "gauntlet-0.13", default-features = false, features = ["date_picker", "wrap", "number_input", "grid", "spinner"] }
#iced_table = "0.13.99"
iced_table = { git = "https://github.com/project-gauntlet/iced_table.git", branch = "gauntlet-0.13" }
#iced_fonts = { version = "0.1.99", features = ["bootstrap"] }
iced_fonts = { git = "https://github.com/project-gauntlet/iced_fonts.git", branch = "gauntlet-0.13", features = ["bootstrap"] }
#iced_layershell = "0.13.99"
iced_layershell = { git = "https://github.com/project-gauntlet/exwlshelleventloop.git", branch = "gauntlet-0.13" }
#iced = { version = "0.13.99", features = ["wgpu", "tiny-skia", "web-colors", "tokio", "lazy", "advanced", "image", "svg"] }
iced = { git = "https://github.com/project-gauntlet/iced.git", branch = "gauntlet-0.13.1", features = ["wgpu", "tiny-skia", "web-colors", "tokio", "lazy", "advanced", "image", "svg"] }
#iced_fonts = { version = "0.2.99", features = ["bootstrap", "lucide"] }
iced_fonts = { git = "https://github.com/project-gauntlet/iced_fonts.git", branch = "gauntlet-0.13.1", features = ["bootstrap", "lucide"] }
# workspaces
gauntlet-common = { path = "./rust/common" }
gauntlet-common-ui = { path = "./rust/common_ui" }
gauntlet-management-client = { path = "./rust/management_client" }
gauntlet-common-plugin-runtime = { path = "./rust/common_plugin_runtime" }
gauntlet-plugin-runtime = { path = "./rust/plugin_runtime" }
gauntlet-client = { path = "./rust/client" }
gauntlet-server = { path = "./rust/server" }
gauntlet-utils = { path = "./rust/utils" }
gauntlet-utils-macros = { path = "./rust/utils_macros" }
gauntlet-plugin-runtime = { path = "./rust/plugin_runtime" }
gauntlet-component-model = { path = "./rust/component_model" }
gauntlet-scenario-runner = { path = "./rust/scenario_runner" }
@ -51,7 +46,7 @@ anyhow = { version = "1", features = ["backtrace"] }
tracing = { version = "0.1" }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tokio = { version = "1.42" }
tokio-util = "0.7"
tokio-util = { version = "0.7" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
bincode = { version = "2.0.0-rc.3" }
@ -70,13 +65,16 @@ walkdir = { version = "2.4.0" }
typed-path = { version = "0.10.0" }
interprocess = { version = "2.2.2", features = ["tokio"] }
toml = "0.8"
x11rb = { version = "0.13", features = ["extra-traits"] }
x11rb-async = { version = "0.13", features = ["extra-traits"] }
x11rb-protocol = { version = "0.13" }
smithay-client-toolkit = { version = "0.19.2" }
[dependencies]
gauntlet-cli = { path = "rust/cli" }
[features]
release = ["gauntlet-cli/release"]
scenario_runner = ["gauntlet-cli/scenario_runner"]
[profile.release-size]
inherits = "release"
@ -84,6 +82,18 @@ opt-level = "s"
lto = "thin"
strip = true
[patch.crates-io]
# NOTE https://github.com/ipetkov/crane/issues/336
libffi-sys = { git = "https://github.com/tov/libffi-rs", rev = "d0704d634b6f3ffef5b6fc7e07fe965a1cff5c7b" }
#[patch.crates-io]
#iced_fonts = { path = "../iced_fonts" }
#iced = { path = "../iced" }
#iced_debug = { path = "../iced/debug" }
#iced_program = { path = "../iced/program" }
#iced_core = { path = "../iced/core" }
#iced_futures = { path = "../iced/futures" }
#iced_graphics = { path = "../iced/graphics" }
#iced_renderer = { path = "../iced/renderer" }
#iced_runtime = { path = "../iced/runtime" }
#iced_tiny_skia = { path = "../iced/tiny_skia" }
#iced_wgpu = { path = "../iced/wgpu" }
#iced_widget = { path = "../iced/widget" }
#iced_winit = { path = "../iced/winit" }
#winit = { path = "../winit" }

454
README.md
View file

@ -7,404 +7,97 @@
Web-first cross-platform application launcher with React-based plugins
> [!WARNING]
> Launcher is being developed by single developer in their free time.
> Changes may be few and far between.
>
> There will probably be breaking changes which will be documented in [changelog](CHANGELOG.md).
> The project is no longer being developed.
![image](https://github.com/user-attachments/assets/81339462-9cc3-469e-8cdc-ca74918bceab)
## Demo
Slightly outdated demo
https://github.com/user-attachments/assets/19964ed6-9cd9-48d4-9835-6be04de14b66
## Features
- Plugin-first
- Plugins are written in TypeScript
- Plugins can have the following functionality
- Create UI
- One-shot commands
- Dynamically provide list of one-shot commands
- Render quick "inline" content directly under main search bar based on value in it
- Get content from and add to Clipboard
- Plugins are distributed as separate branch in Git repository, meaning plugin distribution doesn't need any central
server
- Plugins IDs are just Git Repository URLs
- Built-in functionality is provided by bundled plugin
- Plugins are written in TypeScript
- Extensive plugin API
- Create UI views
- One-shot commands
- Dynamically provide list of one-shot commands
- Render quick "inline" content directly under main search bar based on value in it
- Get content from and add to Clipboard
- Plugins are distributed as separate branch in Git repository, meaning plugin distribution doesn't need any central
server
- Plugins IDs are just Git Repository URLs
- [React](https://github.com/facebook/react)-based UI for plugins
- Implemented using custom React Reconciler (no Electron)
- [Deno JavaScript Runtime](https://github.com/denoland/deno)
- Deno allows to sandbox JavaScript plugin code for better security
- Plugins are required to explicitly specify what permissions they need to work
- Node.js is used to run plugin tooling, but as a plugin developer you will always write code that runs on Deno
- Designed with cross-platform in mind from the beginning
- Commands and Views can be run/opened using custom global shortcuts
- Custom search alias can be assigned to Commands or Views
- Custom theme support
- Built-in functionality is provided by bundled plugins
- Applications: shows applications installed on the system in search results
- Plugin also tracks windows and which application they belong to, so opening already opened application will by default bring up previously created window
- Not all systems are supported at the moment. See [feature support](https://gauntlet.sh/docs/feature-support)
- Calculator: shows result of mathematical operations directly under main search bar
- Includes converting currency using exchange rates
- Powered by [Numbat](https://github.com/sharkdp/numbat)
- Settings: open Gauntlet Settings
- More to come, see [#15](https://github.com/project-gauntlet/gauntlet/issues/15)
- [React](https://github.com/facebook/react)-based UI for plugins
- Implemented using custom React Reconciler (no Electron)
- [iced-rs](https://github.com/iced-rs/iced) is used for UI
- [Deno JavaScript Runtime](https://github.com/denoland/deno)
- Deno allows us to sandbox JavaScript code for better security
- Plugins are required to explicitly specify what permissions they need to work
- NodeJS is used to run plugin tooling, but as a plugin developer you will always write code that runs on Deno
- Frecency-based search result ordering
- Frecency is a combination of frequency and recency
- More often the item is used the higher in the result list it will be, but items used a lot in the past will be ranked lower than items used the same amount of times recently
- Currently, there is no fuzzy matching. Results are matched per word by substring
- Designed with cross-platform in mind
- Permissions
- By default, plugins do not have access to host system
- If plugin asked for access to filesystem, env variables or running commands, it is required to specify
which operating systems it supports.
- If plugin doesn't use filesystem, env variables or running commands and just uses network and/or UI, it
is cross-platform
- Shortcuts
- Plugins are allowed to use only limited set of keys for shortcuts to support widest possible range of keyboards
- Only upper and lower-case letters, symbols and numbers
- Shortcut can have either `"main"` or `"alternative"` kind so plugins do not need to specify shortcut separately for each OS
- `"main"` shortcut requires following modifiers
- Windows and Linux: <kbd>CTRL</kbd>
- macOS: <kbd>CMD</kbd>
- `"alternative"` shortcut requires following modifiers
- Windows and Linux: <kbd>ALT</kbd>
- macOS: <kbd>OPT</kbd>
- Whether <kbd>SHIFT</kbd> is also required depends on character specified for shortcut, e.g `$` will
require <kbd>SHIFT</kbd> to be pressed, while `4` will not
- Results are matched per word by substring
##### OS Support
##### Official
- <img src="https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/linux.svg" width="18" height="18" /> Linux X11
- Application plugin depends on `gtk-launch`
- <img src="https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/apple.svg" width="18" height="18" /> macOS M1
##### Best-effort
- <img src="https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/linux.svg" width="18" height="18" /> Linux Wayland
- LayerShell support required
- Application plugin depends on `gtk-launch`
- <img src="https://img.icons8.com/windows/32/windows-11.png" width="18" height="18" /> Windows
- <img src="https://cdn.jsdelivr.net/gh/simple-icons/simple-icons@develop/icons/apple.svg" width="18" height="18" /> macOS Intel
##### Planned features
- See [#13](https://github.com/project-gauntlet/gauntlet/issues/13)
- See [#15](https://github.com/project-gauntlet/gauntlet/issues/15)
- See [#16](https://github.com/project-gauntlet/gauntlet/issues/16)
##### Plugin APIs
- UI
- Detail
- Form
- Action Panel
- List
- Grid
- Inline
- View directly under main search bar
- Requires separate permission to be explicitly specified in manifest because it reads everything user enters in main search bar
- Stack-based Navigation
- Assets
- Files placed into `assets` directory in root of plugin repository are accessible at plugin runtime using `assetData` function
- Preferences
- Preferences defined in plugin manifest can be set by user and are accessible at plugin runtime using `pluginPreferences` and `entrypointPreferences` functions
- Clipboard
- Accessible via `Clipboard` api
- Requires separate permission to be explicitly specified in manifest
- HUD
- Shows small popup window with feedback information
- Accessible via `showHud` function
- React Helper Hooks
- `usePromise`
- Helper to run promises in a context of React view
- Returns `AsyncState` object which contains `isLoading`, `error` and `data` properties
- `useStorage`
- Helper to store data between entrypoint, plugin and application runs
- Follows API similar to `useState` built-in React Hook
- Uses `localStorage` internally
- `useCache`
- Helper to store data between entrypoint runs but will be reset when plugin or application is restarted
- Follows API similar to `useState` built-in React Hook
- Uses `sessionStorage` internally
- `useCachedPromise`
- Helper to run promises with caching done automatically
- Follows `stale-while-revalidate` caching strategy
- Uses `usePromise` and `useCache` Hooks internally
- `useFetch`
- Helper to run `fetch()` with caching done automatically
- Follows `stale-while-revalidate` caching strategy
- Uses `useCachedPromise` Hook internally
## Getting Started
### Create your own plugin
### Install Gauntlet
- Go to [plugin-template](https://github.com/project-gauntlet/plugin-template) and create your own GitHub repo from it.
- Run `npm run dev` to start dev server (requires running application server)
- Dev server will automatically refresh the plugin on any file change
- Do the changes you need
- You can configure plugin using [Plugin manifest](#plugin-manifest)
- Documentation is, at the moment, basically non-existent but TypeScript declarations in `@project-gauntlet/api`
and `@project-gauntlet/deno` should help
- For examples see [Dev Plugin](dev_plugin). It is very busy because it is used for Gauntlet development, but it has examples of pretty much every available API
- Push changes to GitHub
- Run `publish` GitHub Actions workflow to publish plugin to `gauntlet/release` branch
- Profit!
See [Installation](https://gauntlet.sh/docs/installation)
### Global Shortcut
Main window can be opened using global shortcut or CLI command:
- Global Shortcut (can be changed in Settings)
- Windows: <kbd>ALT</kbd> + <kbd>Space</kbd>
- Linux X11: <kbd>Super</kbd> + <kbd>Space</kbd>
- Linux Wayland
- Global shortcut may not be supported, see [feature support](https://gauntlet.sh/docs/feature-support)
- Please use CLI command instead, and invoke it using window manager specific approach
- macOS: <kbd>CMD</kbd> + <kbd>Space</kbd>
- CLI command
- `gauntlet open`
### Install plugin
Plugins are installed in Settings UI. Use Git repository url of the plugin to install it.
Plugins are installed in Settings UI. Use Git repository url of the plugin to install it, e.g. `https://github.com/project-gauntlet/readme-demo-plugin.git`
![](docs/settings_ui.png)
### Install application
### Create your own plugin
#### macOS
Although it is possible to install Gauntlet by using `.dmg` directly, application doesn't have auto-update functionality so it is recommended to install using `brew` package manager.
Brew package: [link](https://formulae.brew.sh/cask/gauntlet)
To install run:
```
brew install --cask gauntlet
```
To start, manually open application.
#### Windows
Download `.msi` at [Releases page](https://github.com/project-gauntlet/gauntlet/releases/latest) and open to install Gauntlet
Note: application doesn't have auto-update functionality, and has to be updated manually
To start, manually open application.
#### Arch Linux
AUR package: [link](https://aur.archlinux.org/packages/gauntlet-bin)
To install run:
```
yay -S gauntlet-bin
```
To start `systemd` service run:
```
systemctl --user enable --now gauntlet.service
```
#### Nix
The nix flake in this repository is community maintained. If you face a problem, please create an issue and hopefully somebody will work on it.
To install, you either know what to do, or you can read more [here](nix/README.md).
#### Other Linux Distributions
At the moment application is only available for Arch Linux and Nix. If you want to create a package for other distributions see [Application packaging for Linux](#application-packaging-for-Linux)
### Global Shortcut
Main window can be opened using global shortcut or CLI command:
- Shortcut:
- Windows: <kbd>ALT</kbd> + <kbd>Space</kbd>
- Linux X11: <kbd>Super</kbd> + <kbd>Space</kbd>
- Linux Wayland: No global shortcut. Please use CLI command
- macOS: <kbd>CMD</kbd> + <kbd>Space</kbd>
- Can be changed in Settings
- CLI command:
- `gauntlet open`
## Configuration
### Plugin manifest
```toml
[gauntlet]
name = 'Plugin Name'
description = """
Plugin description
"""
[[preferences]] # plugin preference
name = 'testBool'
type = 'enum' # available values: 'number', 'string,' 'bool', 'enum', 'list_of_strings', 'list_of_numbers', 'list_of_enums'
default = 'item' # type of default depends on type field. Currently, list types have no default
description = "Some preference description"
enum_values = [{ label = 'Item', value = 'item'}] # defines list of available enum values, required for types "enum" and "list_of_enums"
[[entrypoint]]
id = 'ui-view' # id for entrypoint
name = 'UI view' # name of entrypoint
path = 'src/ui-view.tsx' # path to file, default export is expected to be function React Function Component
icon = 'icon.png' # optional, path to file inside assets dir
type = 'view'
description = 'Some entrypoint description'
[[entrypoint.preferences]] # entrypoint preference
name = 'boolPreference'
type = 'bool'
default = true
description = "bool preference description"
[[entrypoint.actions]]
id = 'someAction' # id of action, needs to align with value in <Action> "id" property
description = "demo action description"
shortcut = { key = ':', kind = 'main'} # key string only accepts lower and upper-case letters, numbers and symbols. kind can be "main" or "alternative"
[[entrypoint]]
id = 'command-a'
name = 'Command A'
path = 'src/command-a.ts' # path to file, the whole file is a js script
type = 'command'
description = 'Some entrypoint description'
[[entrypoint]]
id = 'entrypoint-generator'
name = 'Entrypoint generator'
path = 'src/entrypoint-generator.ts'
type = 'entrypoint-generator'
description = 'Some entrypoint description'
[[entrypoint]]
id = 'inline-view'
name = 'Inline view'
path = 'src/inline-view.tsx'
type = 'inline-view'
description = 'Some entrypoint description'
[permissions]
network = ["github.com", "example.com:8833"]
clipboard = ["read", "write", "clear"]
main_search_bar = ["read"]
# if specified requires supported_system to be specified as well
environment = ["ENV_VAR_NAME"]
# if specified requires supported_system to be specified as well
system = ["apiName"]
# if specified requires supported_system to be specified as well
[permissions.filesystem]
read = [
"C:\\ProgramFiles\\test",
"C:/ProgramFiles/test",
"{windows:user-home}\\test",
"{windows:user-home}/test",
"{linux:user-home}/test",
"/etc/test"
]
write = ["/home/exidex/.test"]
# if specified requires supported_system to be specified as well
[permissions.exec]
command = ["ls"]
executable = ["/usr/bin/ls"]
[[supported_system]]
os = 'linux' # 'linux', 'windows' or 'macos'
```
### Application config
Located at `$XDG_CONFIG_HOME/gauntlet/config.toml` for Linux. Not used at the moment.
## CLI
### Application
The Application has a simple command line interface
- `gauntlet` - starts server
- `gauntlet --minimized` - starts server without opening main window
- `gauntlet open` - opens application window, can be used instead of global shortcut
- `gauntlet settings` - settings, plugin installation and removal, preferences, etc
### Dev Tools
[`@project-gauntlet/tools`](https://www.npmjs.com/package/@project-gauntlet/tools) contains separate CLI tool for plugin
development purposes. It has following commands:
- `gauntlet dev`
- Starts development server which will automatically refreshed plugin on any file change.
- `gauntlet build`
- Builds plugin
- `gauntlet publish`
- Publishes plugin to separate git branch. Includes `build`
- `publish` assumes some things about git repository, so it is recommended to publish plugin from GitHub Actions
workflow
[Plugin template](https://github.com/project-gauntlet/plugin-template) has nice `npm run` wrappers for them.
See [Getting started with plugin development](https://gauntlet.sh/docs/plugin-development/getting-started)
## Theming
See [THEME.md](./docs/THEME.md)
## Architecture
The Application consists of 4 parts: server, frontend, plugin runtime and settings.
Each plugin runs in separate plugin runtime in separate OS process. Each plugin is its own sandboxed Deno Worker.
In plugin manifest it is possible to configure permissions which will allow plugin to have access to filesystem,
network, environment variables or subprocess execution.
Server saves plugins themselves and state of plugins into SQLite database.
Frontend is GUI module that uses [iced-rs](https://github.com/iced-rs/iced) as a GUI framework. It is run in the same process as a server.
Plugins can create UI using [React](https://github.com/facebook/react).
Plugin Runtime implements custom React Reconciler (similar to React Native) which renders GUI components to frontend.
Plugin Runtime listens on signals from frontend, so when user opens view defined by plugin, frontend sends an open-view request.
Plugin Runtime then receives it, runs React render and React Reconciler makes requests to the frontend containing information what actually should be rendered.
When a user interacts with the UI by clicking button or entering text into form,
frontend sends events to server to see whether any re-renders are needed.
Settings is a GUI application runs in separate process that communicates with server using a simple request-response approach.
Simplified communication:
![](docs/architecture.png)
Components:
![](docs/architecture-blocks.png)
Plugins (or rather its compiled state: manifest, js code and assets) are distributed via Git repository in `gauntlet/release` branch (similar to GitHub Pages).
Which means there is no one central place required for plugin distribution.
And to install plugin all you need is Git repository url.
## Application packaging for Linux
This section contains a list of things
that could be useful for someone who wants to package application for Linux distribution.
If something is missing, please [create an issue](https://github.com/project-gauntlet/gauntlet/issues).
Application is already packaged for [Arch Linux](#arch-linux) and [Nix](#nix) so you can use them as examples.
Relevant CLI commands:
- `$ gauntlet --minimized`
- Server needs to be started when user logs in, e.g. using `systemd` service
- `$ gauntlet open`
- Main windows is usually opened using [global shortcut](#global-shortcut), this CLI command can be used in cases where global shortcut functionality is not available
- `$ gauntlet settings`
- Settings are usually started on demand from Gauntlet itself
`.desktop` sample file can be found [here](assets/linux/gauntlet.desktop)
`systemd` service sample file can be found [here](assets/linux/gauntlet.service)
###### Directories used
- data dir - `$XDG_DATA_HOME/gauntlet` or `$HOME/.local/share/gauntlet`
- contains application state `data.db`
- cache dir - `$XDG_CACHE_HOME/gauntlet` or `$HOME/.cache/gauntlet`
- contains icon cache
- config dir - `$XDG_CONFIG_HOME/gauntlet` or `$HOME/.config/gauntlet`
- contains application config `config.toml`
- application will never do changes to config file
- state dir - `$XDG_STATE_HOME/gauntlet` or `$HOME/.local/state/gauntlet`
- contains log files created by plugin development
- `.desktop` files at locations defined by [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html)
Client and Setting applications have GUI and therefore use all the usual graphics-related stuff from X11.
Wayland support requires LayerShell protocol `zwlr_layer_shell_v1`.
See [Theming](https://gauntlet.sh/docs/theming)
## Building Gauntlet
You will need:
- NodeJS
- Rust
@ -412,6 +105,8 @@ You will need:
- CMake (not used by the project itself, but is required by a dependency)
- On Linux: `libxkbcommon-dev` (note: name may differ depending on used distribution)
### Dev
To build dev run:
```bash
npm ci
@ -419,14 +114,35 @@ npm run build
npm run build-dev-plugin
cargo build
```
In dev (without "release" feature) application will use only directories inside project directory to store state or cache.
In dev (without "release" feature) application will use directories ONLY inside project directory to store state or cache, to avoid messing up global installation
To build release run:
### Not-yet-packaged
To build not-yet-packaged release binary, run:
```bash
npm ci
npm run build
cargo build --release --features release
```
### Packaged
To build os-specific package, run one of the following:
macOS:
```bash
npm run build-macos-project --workspace @project-gauntlet/build
```
Windows:
```bash
npm run build-windows-project --workspace @project-gauntlet/build
```
Linux:
```bash
npm run build-linux-project --workspace @project-gauntlet/build
```
But the new version release needs to be done via GitHub Actions
## Contributing
@ -435,29 +151,5 @@ If you'd like to help build Gauntlet you can do it in more ways than just contri
- Reporting a bug or UI/UX problem
- Creating a plugin
If you are looking for things to do see pinned [issues](https://github.com/project-gauntlet/gauntlet/issues).
For simple problems feel free to open an issue or PR and tackle it yourself!
For simple problems feel free to open an issue or PR and tackle it yourself.
For more significant changes please contact creators on Discord (invite link on top of README) and discuss first.
All and any contributions are welcome.
## Versioning
### Application
Application uses simple incremental integers starting from `1`.
It doesn't follow the SemVer versioning.
Given application's reliance on plugins, once it is stable,
introducing breaking changes will be done carefully (if at all) and will be given a reasonable grace period to migrate.
SemVer is about a hard cutoff between major versions with breaking changes, which doesn't fit this kind of application.
Before application is declared stable, breaking changes could be done without a grace period.
### Tools
[`@project-gauntlet/tools`](https://www.npmjs.com/package/@project-gauntlet/tools) uses SemVer.
### Plugins
Plugins only have the latest published "version".

View file

@ -1 +1 @@
19
21

View file

@ -196,7 +196,7 @@ export default async function Applications(context: GeneratorContext<object, Ent
}),
add,
remove,
{ exts: ["app"], maxDepth: 2 }
{ exts: ["app"], maxDepth: 2, followSymlinks: true, }
);
}
case "windows": {

View file

@ -4,25 +4,30 @@ import {
GeneratedEntrypointAction,
} from "@project-gauntlet/api/helpers";
import { linux_open_application } from "gauntlet:bridge/internal-linux";
import React from "react";
import { useState } from "react";
import { Action, ActionPanel, List } from "@project-gauntlet/api/components";
export function ListOfWindows({ windows, focusWindow }: {
export function ListOfWindows({ windows, focusWindow, focusSecond }: {
windows: Record<string, OpenWindowData>,
focusWindow: (windowId: string) => void
focusWindow: (windowId: string) => void,
focusSecond: boolean
}) {
const knownWindows = readWindowOrder();
const sortedWindows = Object.keys(windows) // sort windows based on array stored on storage
.sort((a, b) => knownWindows.indexOf(a) - knownWindows.indexOf(b));
const [id, setId] = useState<string | null>(
focusSecond ? sortedWindows.at(1) || null : null
);
return (
<List
actions={
<ActionPanel>
<Action
label="Focus window"
onAction={(id: string | undefined) => {
onAction={id => {
if (id) {
focusAndSort(id, focusWindow)
return { close: true }
@ -31,6 +36,8 @@ export function ListOfWindows({ windows, focusWindow }: {
/>
</ActionPanel>
}
onItemFocusChange={setId}
focusedItemId={id}
>
{
sortedWindows.map(window => <List.Item key={window} id={window} title={windows[window]!!.title}/>)
@ -45,7 +52,13 @@ export type OpenWindowData = {
appId: string
}
export const openWindows: Record<string, OpenWindowData> = {};
export function openWindows(): Record<string, OpenWindowData> {
if ((globalThis as any).__openWindows == undefined) {
(globalThis as any).__openWindows = {}
}
return (globalThis as any).__openWindows
}
export function applicationActions(
id: string,
@ -65,7 +78,7 @@ export function applicationActions(
}
const appWindows = Object.fromEntries(
Object.entries(openWindows)
Object.entries(openWindows())
.filter(([_, windowData]) => windowData.appId == id)
)
@ -103,7 +116,13 @@ export function applicationActions(
{
label: "Show windows",
view: () => {
return <ListOfWindows windows={appWindows} focusWindow={windowId => focusWindow(windowId)}/>
return (
<ListOfWindows
windows={appWindows}
focusWindow={windowId => focusWindow(windowId)}
focusSecond={false}
/>
)
}
},
{
@ -123,7 +142,7 @@ export function applicationAccessories(id: string, experimentalWindowTracking: b
return []
}
const appWindows = Object.entries(openWindows)
const appWindows = Object.entries(openWindows())
.filter(([_, windowData]) => windowData.appId == id)
if (appWindows.length == 0) {
@ -147,7 +166,7 @@ export function addOpenWindow(
add: (id: string, data: GeneratedEntrypoint) => void,
) {
if (generatedEntrypoint) {
openWindows[windowId] = {
openWindows()[windowId] = {
id: windowId,
appId: appId,
title: windowTitle
@ -172,11 +191,11 @@ export function deleteOpenWindow(
get: (id: string) => GeneratedEntrypoint | undefined,
add: (id: string, data: GeneratedEntrypoint) => void,
) {
const openWindow = openWindows[windowId];
const openWindow = openWindows()[windowId];
if (openWindow) {
const generatedEntrypoint = get(openWindow.appId);
delete openWindows[windowId];
delete openWindows()[windowId];
const knownWindows = readWindowOrder();
const newKnownWindows = knownWindows.filter(id => id != windowId)

View file

@ -10,11 +10,19 @@ export default function Windows(): ReactElement {
case "linux": {
if (wayland()) {
return (
<ListOfWindows windows={openWindows} focusWindow={(windowId) => focusWaylandWindow(windowId)}/>
<ListOfWindows
windows={openWindows()}
focusWindow={(windowId) => focusWaylandWindow(windowId)}
focusSecond={true}
/>
)
} else {
return (
<ListOfWindows windows={openWindows} focusWindow={(windowId) => focusX11Window(windowId)}/>
<ListOfWindows
windows={openWindows()}
focusWindow={(windowId) => focusX11Window(windowId)}
focusSecond={true}
/>
)
}
}

1
dev_data/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
scenarios

View file

@ -1,3 +1,11 @@
#[main_window]
#close_on_unfocus = false
#close_on_unfocus = false
[wayland]
#main_window_surface = "xdg_shell"
global_shortcuts_api = "legacy_x11_api"
#global_shortcuts_api = "none"
[linux]
native_hud = true

View file

@ -64,12 +64,6 @@ export default function FormView(): ReactElement {
<Form.Select.Item value={"select_item_3"}>Select Item 3</Form.Select.Item>
<Form.Select.Item value={"select_item_4"}>Select Item 4</Form.Select.Item>
</Form.Select>
<Form.DatePicker
label={"What is your birthday?"}
onChange={value => {
console.log(`uncontrolled value: ${value}`)
}}
/>
<Form.Separator/>
{/* controlled */}
<Form.TextField
@ -105,12 +99,6 @@ export default function FormView(): ReactElement {
<Form.Select.Item value={"default_selected_item"}>Default Select Item</Form.Select.Item>
<Form.Select.Item value={"select_item_4"}>Select Item 4</Form.Select.Item>
</Form.Select>
<Form.DatePicker
value={"2024-03-22"}
onChange={value => {
console.log(`controlled value: ${value}`)
}}
/>
</Form>
);
};

View file

@ -30,7 +30,7 @@ export default function ListView(): ReactElement {
)
}
function pushPrimaryAction(id: string | undefined, pushView: (component: ReactNode) => void) {
function pushPrimaryAction(id: string | null, pushView: (component: ReactNode) => void) {
switch (id) {
case "UsePromiseTestBasic": {
pushView(<UsePromiseTestBasic/>)
@ -418,4 +418,4 @@ function printState(data: any, error: unknown, isLoading: boolean) {
console.dir(data)
console.dir(error)
console.dir(isLoading)
}
}

View file

@ -5,7 +5,7 @@ import { Environment } from "@project-gauntlet/api/helpers";
export default function ListView(): ReactElement {
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const onClick = (id: string | undefined) => {
const onClick = (id: string | null) => {
if (id == "print-env") {
console.log(Environment.gauntletVersion);
console.log(Environment.isDevelopment);
@ -63,4 +63,4 @@ export default function ListView(): ReactElement {
</List.Section>
</List>
)
}
}

View file

@ -1,27 +1,43 @@
import { ReactElement } from "react";
import { Grid } from "@project-gauntlet/api/components";
import { ReactElement, useState } from "react";
import { Action, ActionPanel, Grid } from "@project-gauntlet/api/components";
export default function Main(): ReactElement {
const content = (
const [id, setId] = useState<string | null>(null);
const content = (id: string) => (
<Grid.Item.Content>
<Grid.Item.Content.Paragraph>
Test
{id}
</Grid.Item.Content.Paragraph>
</Grid.Item.Content>
);
return (
<Grid onItemFocusChange={(id: string | undefined) => console.log("onItemFocusChange", id)}>
<Grid.Item id="adarian" title="Adarian">{content}</Grid.Item>
<Grid.Item id="aruzan" title="Aruzan">{content}</Grid.Item>
<Grid.Item id="blutopian" title="Blutopian">{content}</Grid.Item>
<Grid.Item id="caphex" title="Caphex">{content}</Grid.Item>
<Grid.Item id="condluran" title="Condluran">{content}</Grid.Item>
<Grid.Item id="frozian" title="Frozian">{content}</Grid.Item>
<Grid.Item id="evereni" title="Evereni">{content}</Grid.Item>
<Grid.Item id="ezaraa" title="Ezaraa">{content}</Grid.Item>
<Grid.Item id="houk" title="Houk">{content}</Grid.Item>
<Grid.Item id="inleshat" title="Inleshat">{content}</Grid.Item>
<Grid
onItemFocusChange={setId}
focusedItemId={id}
actions={
<ActionPanel>
<Action
label={`Focused: ${id}`}
onAction={(id) => {
console.log(id)
setId("condluran")
}}
/>
</ActionPanel>
}
>
<Grid.Item id="adarian" title="Adarian">{content("adarian")}</Grid.Item>
<Grid.Item id="aruzan" title="Aruzan">{content("aruzan")}</Grid.Item>
<Grid.Item id="blutopian" title="Blutopian">{content("blutopian")}</Grid.Item>
<Grid.Item id="caphex" title="Caphex">{content("caphex")}</Grid.Item>
<Grid.Item id="condluran" title="Condluran">{content("condluran")}</Grid.Item>
<Grid.Item id="frozian" title="Frozian">{content("frozian")}</Grid.Item>
<Grid.Item id="evereni" title="Evereni">{content("evereni")}</Grid.Item>
<Grid.Item id="ezaraa" title="Ezaraa">{content("ezaraa")}</Grid.Item>
<Grid.Item id="houk" title="Houk">{content("houk")}</Grid.Item>
<Grid.Item id="inleshat" title="Inleshat">{content("inleshat")}</Grid.Item>
</Grid>
)
}

View file

@ -2,10 +2,10 @@ import { ReactElement, useState } from "react";
import { List } from "@project-gauntlet/api/components";
export default function Main(): ReactElement {
const [id, setId] = useState<string | undefined>(undefined);
const [id, setId] = useState<string | null>(null);
return (
<List onItemFocusChange={setId}>
<List onItemFocusChange={setId} focusedItemId={id}>
<List.Item id="adarian" title="Adarian"/>
<List.Item id="aruzan" title="Aruzan"/>
<List.Item id="blutopian" title="Blutopian"/>

View file

@ -1,21 +0,0 @@
# Gauntlet Theming
Currently, in Gauntlet with themes it is possible to change (list is likely be extended with future updates):
- Colors of text and background
- Window border color, width and radius
- Border radius of components in content
Theming is only affects main window and doesn't affect settings
Theme config file is in TOML format
Theme config file locations:
- Windows: `C:\Users\Username\AppData\Roaming\Gauntlet\config\theme.toml`
- Linux: `$XDG_CONFIG_HOME/gauntlet/theme.toml`
- macOS: `$HOME/Library/Application Support/dev.project-gauntlet.gauntlet/theme.toml`
Currently, theme change is only applied after application restart
Any errors in theme parsing will be shown in application logs
See bundled themes for examples [here](./../bundled_themes)

View file

@ -1,17 +0,0 @@
@startuml
node "Frontend"
node "Server"
node "Deno worker 1" as Deno1
node "Deno worker 2" as Deno2
node "Deno worker 3" as Deno3
node "Deno worker 4" as Deno4
[Frontend] --> [Server]
[Server] --> [Deno1]
[Server] --> [Deno2]
[Server] --> [Deno3]
[Server] --> [Deno4]
@enduml

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View file

@ -1,31 +0,0 @@
@startuml
'https://www.planttext.com/
== Frontend: Start ==
Frontend -> Server: list of views and commands request
Server --> Frontend: list of views and commands response
== Frontend: Initial View Render ==
Frontend -> Server: open-view event
Server -> Frontend: render components request
Frontend --> Server: render components response
== Frontend: Command Execution ==
Frontend -> Server: execute command
== Frontend: View Update On Event ==
Frontend -> Server: button click, key press in input component, etc
Server -> Frontend: render components request
Frontend --> Server: render components response
== Settings ==
Settings -> Server: request
Server --> Settings: response
@enduml

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View file

@ -1 +0,0 @@
Date Picker is a type of form input that produces date value represented as a string in "YYYY-MM-DD" format

View file

@ -1 +0,0 @@
Text displayed in UI to the left of the date picker itself

View file

@ -1 +0,0 @@
Function that is called when the value of the data picker was changed

View file

@ -1 +0,0 @@
Value of the Date Picker. Can be used to implement controlled form

View file

@ -0,0 +1 @@
Sets item with specified id to be the one that is focused. `undefined` - uncontrolled, `null` - controlled and unset, other values - controlled and set

View file

@ -0,0 +1 @@
Sets item with specified id to be the one that is focused. `undefined` - uncontrolled, `null` - controlled and unset, other values - controlled and set

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 KiB

After

Width:  |  Height:  |  Size: 678 KiB

Before After
Before After

View file

@ -56,6 +56,15 @@ type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start content-svg
[[entrypoint]]
id = 'content-svg'
name = 'Content Svg'
path = 'src/content-svg.tsx'
type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start main
[[entrypoint]]
id = 'main'
@ -120,4 +129,4 @@ description = ''
# docs-code-segment:end
[permissions]
network = ["static.wikia.nocookie.net"]
network = ["static.wikia.nocookie.net", "upload.wikimedia.org"]

View file

@ -0,0 +1,14 @@
import { ReactNode } from "react";
import { Detail } from "@project-gauntlet/api/components";
const svgUrl = "https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg"
export default function ContentSvg(): ReactNode {
return (
<Detail>
<Detail.Content>
<Detail.Content.Svg source={{ url: svgUrl }}/>
</Detail.Content>
</Detail>
)
}

View file

@ -12,15 +12,6 @@ type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start date-picker
[[entrypoint]]
id = 'date-picker'
name = 'Date Picker'
path = 'src/date-picker.tsx'
type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start main
[[entrypoint]]
id = 'main'

View file

@ -1,17 +0,0 @@
import { ReactElement } from 'react';
import { Form } from "@project-gauntlet/api/components";
export default function DatePickerExample(): ReactElement {
return (
<Form>
<Form.DatePicker
label="Date"
value="2024-03-22"
onChange={value => {
console.log(`value: ${value}`)
}}
/>
</Form>
);
};

View file

@ -30,13 +30,6 @@ export default function MainExample(): ReactElement {
<Form.Separator/>
<Form.DatePicker
label="Date"
value={"2024-03-22"}
onChange={value => {
console.log(`value: ${value}`)
}}
/>
<Form.Checkbox
title="I acknowledge the Galactic Code and agree to abide by its regulations."
value={false}

View file

@ -102,6 +102,15 @@ type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start content-svg
[[entrypoint]]
id = 'content-svg'
name = 'Grid Content Svg'
path = 'src/content-svg.tsx'
type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start focus
[[entrypoint]]
id = 'focus'
@ -112,4 +121,4 @@ description = ''
# docs-code-segment:end
[permissions]
network = ["static.wikia.nocookie.net"]
network = ["static.wikia.nocookie.net", "upload.wikimedia.org"]

View file

@ -1,15 +1,16 @@
import { ReactElement } from "react";
import { Grid } from "@project-gauntlet/api/components";
const url = "https://static.wikia.nocookie.net/star-wars-canon/images/b/b0/Tatooine_TPM.png/revision/latest/scale-to-width-down/150?cb=20151124205032";
export default function ContentImageExample(): ReactElement {
return (
<Grid>
<Grid.Item id="tatooine" title="Tatooine">
<Grid.Item.Content>
<Grid.Item.Content.Image
source={{ url: "https://static.wikia.nocookie.net/star-wars-canon/images/b/b0/Tatooine_TPM.png/revision/latest/scale-to-width-down/150?cb=20151124205032" }}/>
<Grid.Item.Content.Image source={{ url: url }}/>
</Grid.Item.Content>
</Grid.Item>
</Grid>
)
}
}

View file

@ -0,0 +1,16 @@
import { ReactElement } from "react";
import { Grid } from "@project-gauntlet/api/components";
const svgUrl = "https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg"
export default function ContentSvgExample(): ReactElement {
return (
<Grid>
<Grid.Item id="svg">
<Grid.Item.Content>
<Grid.Item.Content.Svg source={{ url: svgUrl }}/>
</Grid.Item.Content>
</Grid.Item>
</Grid>
)
}

View file

@ -2,7 +2,7 @@ import { ReactElement, useState } from "react";
import { Grid } from "@project-gauntlet/api/components";
export default function FocusExample(): ReactElement {
const [id, setId] = useState<string | undefined>(undefined);
const [id, setId] = useState<string | null>(null);
const content = (text: string) => (
<Grid.Item.Content>

View file

@ -28,7 +28,7 @@ const items = [
},
{
title: "Dantooine",
image: "https://static.wikia.nocookie.net/starwars/images/a/a5/Dantooine_Resistance.jpg/revision/latest/scale-to-width-down/150?cb=20200120190043"
image: "https://static.wikia.nocookie.net/starwars/images/9/9b/Dantooine-RebuildingTheResistance.jpg/revision/latest/scale-to-width-down/150?cb=20200120190043"
},
]
@ -44,4 +44,4 @@ export default function MainExample(): ReactElement {
))}
</Grid>
)
}
}

View file

@ -2,18 +2,28 @@ import { ReactElement, useState } from "react";
import { Action, ActionPanel, Grid } from "@project-gauntlet/api/components";
export default function SearchBarSetSearchTextExample(): ReactElement {
const [searchText, setSearchText] = useState<string | undefined>("");
const [searchText, setSearchText] = useState<string>("");
return (
<Grid
actions={
<ActionPanel>
<Action label="Set value" onAction={(id) => setSearchText(id)}/>
<Action
label="Set value"
onAction={(id) => {
// This will be the value in search bar when
// enter is pressed while item is not focused
const unfocused = "item-not-unfocused";
setSearchText(id || unfocused)
}}
/>
</ActionPanel>
}
>
<Grid.SearchBar value={searchText} onChange={setSearchText}/>
<Grid.Item id="This will be the value in search bar">
{/* This id will be the value in search bar when clicked or press enter when item is focused */}
<Grid.Item id="item-focused">
<Grid.Item.Content>
<Grid.Item.Content.Paragraph>
Click me!

View file

@ -0,0 +1,2 @@
dist
node_modules

View file

@ -0,0 +1,16 @@
[gauntlet]
name = 'Docs Inline Svg'
description = ''
# docs-code-segment:start main
[[entrypoint]]
id = 'main'
name = 'Main'
path = 'src/main.tsx'
type = 'inline-view'
description = ''
# docs-code-segment:end
[permissions]
main_search_bar = ["read"]
network = ["upload.wikimedia.org"]

View file

@ -0,0 +1,17 @@
{
"name": "@project-gauntlet/docs-inline-svg",
"private": true,
"scripts": {
"build": "gauntlet build",
"dev": "gauntlet dev"
},
"dependencies": {
"@project-gauntlet/api": "file:../../js/api"
},
"devDependencies": {
"@types/react": "*",
"@types/deno": "*",
"@project-gauntlet/tools": "*",
"typescript": "*"
}
}

View file

@ -0,0 +1,19 @@
import { ReactElement } from "react";
import { Inline } from "@project-gauntlet/api/components";
const svgUrl = "https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg"
export default function Main({ text }: { text: string }): ReactElement | null {
if (text != "example") {
return null
}
return (
<Inline>
<Inline.Center>
<Inline.Center.Svg source={{ url: svgUrl }}/>
</Inline.Center>
</Inline>
)
}

View file

@ -0,0 +1,11 @@
{
"compilerOptions": {
"strict": true,
"module": "ES2022",
"esModuleInterop": true,
"target": "ES2022",
"moduleResolution": "bundler",
"jsx": "react-jsx"
},
"lib": ["ES2020"]
}

View file

@ -120,6 +120,15 @@ type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start content-svg
[[entrypoint]]
id = 'content-svg'
name = 'List Content Svg'
path = 'src/content-svg.tsx'
type = 'view'
description = ''
# docs-code-segment:end
# docs-code-segment:start metadata
[[entrypoint]]
id = 'metadata'
@ -193,5 +202,4 @@ description = ''
# docs-code-segment:end
[permissions]
network = ["static.wikia.nocookie.net"]
network = ["static.wikia.nocookie.net", "upload.wikimedia.org"]

View file

@ -1,7 +1,7 @@
import { ReactElement } from "react";
import { List } from "@project-gauntlet/api/components";
const imgUrl = "https://static.wikia.nocookie.net/starwars/images/e/e4/Ezaraa.png/revision/latest/scale-to-width-down/200?cb=20170511082800"
const imgUrl = "https://static.wikia.nocookie.net/starwars/images/9/9f/Ezaraa-TheScreamingCitadel1.png/revision/latest/scale-to-width-down/200?cb=20170511082800"
export default function ContentImageExample(): ReactElement {
return (

View file

@ -0,0 +1,17 @@
import { ReactElement } from "react";
import { List } from "@project-gauntlet/api/components";
const svgUrl = "https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg"
export default function ContentSvgExample(): ReactElement {
return (
<List>
<List.Item id="svg" title="Svg Example"/>
<List.Detail>
<List.Detail.Content>
<List.Detail.Content.Svg source={{ url: svgUrl }}/>
</List.Detail.Content>
</List.Detail>
</List>
)
}

View file

@ -2,7 +2,7 @@ import { ReactElement, useState } from "react";
import { List } from "@project-gauntlet/api/components";
export default function FocusExample(): ReactElement {
const [id, setId] = useState<string | undefined>(undefined);
const [id, setId] = useState<string | null>(null);
return (
<List onItemFocusChange={setId}>

View file

@ -2,18 +2,28 @@ import { ReactElement, useState } from "react";
import { Action, ActionPanel, List } from "@project-gauntlet/api/components";
export default function SearchBarSetSearchTextExample(): ReactElement {
const [searchText, setSearchText] = useState<string | undefined>("");
const [searchText, setSearchText] = useState<string>("");
return (
<List
actions={
<ActionPanel>
<Action label="Set value" onAction={(id) => setSearchText(id)}/>
<Action
label="Set value"
onAction={(id) => {
// This will be the value in search bar when
// enter is pressed while item is not focused
const unfocused = "item-not-unfocused";
setSearchText(id || unfocused)
}}
/>
</ActionPanel>
}
>
<List.SearchBar value={searchText} onChange={setSearchText}/>
<List.Item id="This will be the value in search bar" title="Click me!"/>
{/* This id will be the value in search bar when clicked or press enter when item is focused */}
<List.Item id="item-focused" title="Click me!"/>
</List>
)
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
"type": "ViewWithActionPanel"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
"type": "ViewWithActionPanel"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -0,0 +1,3 @@
{
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +0,0 @@
{
"type": "RequestViewRender"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -0,0 +1,3 @@
{
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -0,0 +1,3 @@
{
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,3 +1,3 @@
{
"type": "RequestViewRender"
}
"type": "View"
}

View file

@ -1,4 +1,4 @@
{
"type": "Search",
"type": "InlineView",
"text": "example"
}
}

View file

@ -1,4 +1,4 @@
{
"type": "Search",
"type": "InlineView",
"text": "example"
}
}

View file

@ -1,4 +1,4 @@
{
"type": "Search",
"type": "InlineView",
"text": "example"
}
}

View file

@ -1,4 +1,4 @@
{
"type": "Search",
"type": "InlineView",
"text": "example"
}
}

View file

@ -1,4 +1,4 @@
{
"type": "Search",
"type": "InlineView",
"text": "1 + 2"
}
}

View file

@ -1,4 +1,4 @@
{
"type": "Search",
"type": "InlineView",
"text": "example"
}
}

View file

@ -1,4 +1,4 @@
{
"type": "Search",
"type": "InlineView",
"text": "example"
}
}

Some files were not shown because too many files have changed in this diff Show more