Skip to content

Commit

Permalink
Improve usability of PWAs in Dev Containers (#3576)
Browse files Browse the repository at this point in the history
* Add WIP icons

* Add WIP icons for gzweb

* Add WIP icons for glances

* Set cross origin to use credentials
ensuring auth cookie is included in request header
when requesting for web app manifest file
thus avoiding CORS policy violations in browser
when accessing forwarded codespaces ports from the web

> The request for the manifest is made without credentials (even if it's on the same domain), thus if the manifest requires credentials, you must include `crossorigin="use-credentials"` in the manifest tag.

- https://web.dev/add-manifest/
- https://stackoverflow.com/a/57184506/2577586

* Use ReqHost variable in templates
to account for X-Forwarded-Host value in header

* Delete duplicate manifest

* Set id property in app manifests
so we can address them independently from their start_url
- https://developer.chrome.com/blog/pwa-manifest-id/

* Ensure apps are uniquely identifies
by adding trailing slash to id
and thus different URI directories

* Refactor root landing page into nav2 app
by moving page file into nav2 sub folder
adding root redirect pointing to /nav2/
and updating html, markdown, manifest files respectively

* Fix https detection for Caddy reverse proxies
by also checking X-Forwarded-Proto in request header

* Remove unnecessary files

* Prune smaller images

* Prune duplicate icon

* Clean up html tags

* Update manifest icons

* Rename icons

* Revert "Prune duplicate icon"

This reverts commit 5710401.

* Add back favicon for shortcut

* Add self index for completeness and bookmarking

* Simplify icon linking

* Delete binary files

* Fix hyperlink path

* Include image files using gitattributes
to track these binary files via git LFS

* Add icons using git lfs

* Standardized all icon paths

* Use external links for icons
to avoid the need for using git LFS
although this is a bit of a hack

* Stage any and maskable icons

* Use any and masked icons

* Set colors to match maskable icon colors

* Update icon

* Use lossless compression
without removing background
- https://shortpixel.com/online-image-compression

* Use WebP instead of PNG
for smaller file sizes
- https://en.wikipedia.org/wiki/WebP

* Move icons into icons folder

* Use _SRV environment variables for service paths

* Download media files from github
during docker image build
to avoid adding always online dependencies
when creating or starting dev containers

* Delete media icons from git repo
now that we download media from anonymized URLs on github
- https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files

* Add comments

* Enable file browsing for non app paths
for remote debugging of media and asset files

* Consolidate assets into single folder

* Add links for file browser paths
to Server Diagnostics

* Delete unused symlink

* Update landing page to match manifest
by including same shortcuts and start url

* Patch gzweb to disable modelList
avoiding 404s for thumbnails
as they are hardcoded into js

* Update comments

* Simplify Caddyfile by reverting to symlinking
but add ROOT_SRV env for custom overriding

* Loop over nav2 srv folders when symlinking
to generalize over folder names

* Add matcher for file browsing root directory
while still redirecting to nav2 app by default

* Use placeholders for root variable
to consolidate env default fallback settings
e.g `:/srv`

* Promote file browser in Nav2 app shortcuts

* Fix and update SRV envs

* Postpone symlinking for Nav2 web app
to when post-create-command script then runs
given full repo is not copied into builder stage in Dockerfile.
While this could be postponed to update-content-command
leaving it here avoids blowing user changes
after the container has been created or modified.

* Add guard to check if srv folder exists

* Add refresh rate shortcuts to glances

* Add file browser shortcut to nav2

* Set scope for nav2 PWA to root
to allow for opening child apps inside nav2 app

* Display child apps in fullscreen mode by default
as users can still open them in standalone via nav2 app
given the nav2 app's scope is the parent root path

* Update shortcuts and landing page

* Document PWA scope and installation order
when using Nav2 PWA scoped as root

* Revert setting scope for nav2 PWA to root path
as adding file browser shortcut to nav2 PWA is not worth the trouble
of having to explain installation order caveats and URL launch behavior.
File browser shortcut is still accessible from inside nav2 pwa launcher
but merely displays in browser preview
given root / is out of scope for /nav2/

* Update server diagnostics for troubleshooting

* Verify checksum of archive before extraction
incase anonymized URL changes expected archive
  • Loading branch information
ruffsl authored and SteveMacenski committed Jun 9, 2023
1 parent 6ecbe81 commit 11615fd
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 146 deletions.
56 changes: 33 additions & 23 deletions .devcontainer/caddy/Caddyfile
Expand Up @@ -7,7 +7,7 @@

# Matcher for http request scheme. E.g. "http" or "https"
@http_scheme {
expression {http.request.scheme}=="https" || {header.X-Forwarded-Scheme}=="https"
expression {http.request.scheme}=="https" || {header.X-Forwarded-Scheme}=="https" || {header.X-Forwarded-Proto}=="https"
}
# If any http scheme is "https", then use "wss"
vars @http_scheme WsScheme "wss"
Expand All @@ -19,9 +19,9 @@
header X-Forwarded-Host *
}
# If http headers exists, then use them
vars @host_forwarded WsHost {header.X-Forwarded-Host}
vars @host_forwarded ReqHost {header.X-Forwarded-Host}
# Else default to host in request
vars WsHost {http.request.hostport}
vars ReqHost {http.request.hostport}

# Matcher for websocket connection upgrade requests
@websockets {
Expand All @@ -37,8 +37,8 @@
# E.g auto redirect websocket URL to match request scheme
(redirect) {
# Configure redirect to match request scheme
vars LayoutUrl "/assets/nav2_foxglove_layout.json"
vars DataSourceUrl "{vars.WsScheme}://{vars.WsHost}{args.0}/"
vars LayoutUrl "/assets/foxglove/nav2_layout.json"
vars DataSourceUrl "{vars.WsScheme}://{vars.ReqHost}{args.0}/"
redir /autoconnect "{args.0}/?ds=foxglove-websocket&ds.url={vars.DataSourceUrl}"
redir /autolayout "{args.0}/?ds=foxglove-websocket&ds.url={vars.DataSourceUrl}&layoutUrl={vars.LayoutUrl}"
}
Expand All @@ -55,30 +55,26 @@
route / {
# Inject link to manifest just after <head> tag
# https://developer.mozilla.org/docs/Web/Manifest
replace `<head>` `<head><link rel="manifest" href="manifest.json" />`
replace `<head>` `<head><link rel="manifest" href="manifest.json" crossorigin="use-credentials"/>`
}
# Redirect relative handle_path'ed manifest.json to /manifests directory
redir /manifest.json /manifests{http.request.orig_uri.path.dir}manifest.json
redir /manifest.json /assets{http.request.orig_uri.path.dir}manifest.json
}

# Snippet for hosted web app using websockets
# to serve static files and reverse proxying connections
# E.g. for serving GzWeb and Foxglove web apps
(app) {
# Redirect implicit directory requests twards index.html
redir {args.0} {args.0}/
# handle and strip path prefix from redirect
handle_path {args.0}/* {
# Set root directory for static files
root * {args.1}
# Serve static files
file_server
root * {http.vars.root}{args.0}
# Enable mobile web app features
import mobile
# Reverse proxy websockets to backend address
reverse_proxy @websockets {args.2}
reverse_proxy @websockets {args.1}
# Import custom snippets
import {args.3} {args.0}
import {args.2} {args.0}
}
}

Expand All @@ -88,24 +84,38 @@
:8080 {
# Include global matchers and variables
import globals
root * {$ROOT_SRV:/srv}
file_server browse

# Handle main landing page
# Handle root content
# I.e. assets internal to workspace
handle /* {
# Use relative path for root directory
root * srv
file_server
import mobile
# Render markdown files as html
templates
# Template manifest.json files
templates */manifest.json {
mime application/json
}
}

# Handle nav2 web app
# I.e. main landing page
handle_path /nav2/* {
root * {http.vars.root}/nav2
import mobile
# Render markdown files as html
templates
}

# Matcher for requests without browse query
@no_browse {
path /
not query browse=true
}
# Redirect to nav2 web app by default
redir @no_browse /nav2/

# Import app snippets for web apps
import app "/gzweb" "{$GZWEB_WS}/http/client" "localhost:9090" "dummy"
import app "/foxglove" "{$FOXGLOVE_WS}" "localhost:8765" "redirect"
import app "/gzweb" "localhost:9090" "dummy"
import app "/foxglove" "localhost:8765" "redirect"

# Handle glances web app
redir /glances /glances/
Expand Down
40 changes: 40 additions & 0 deletions .devcontainer/caddy/srv/assets/foxglove/manifest.json
@@ -0,0 +1,40 @@
{
"name": "Foxglove: {{placeholder "http.vars.ReqHost"}}",
"short_name": "Foxglove: {{placeholder "http.vars.ReqHost"}}",
"icons": [
{
"src": "/media/icons/foxglove/any_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "any"
},
{
"src": "/media/icons/foxglove/maskable_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "maskable"
}
],
"id": "/foxglove/",
"start_url": "/foxglove/autoconnect",
"theme_color": "#6F3BE8",
"background_color": "#6F3BE8",
"display": "fullscreen",
"shortcuts" : [
{
"name": "Auto Connect",
"url": "/foxglove/autoconnect",
"description": "Auto connect to default data source"
},
{
"name": "Auto Layout",
"url": "/foxglove/autolayout",
"description": "Auto connect using default layout"
},
{
"name": "Manual Connect",
"url": "/foxglove/",
"description": "Manually connect to data source"
}
]
}
40 changes: 40 additions & 0 deletions .devcontainer/caddy/srv/assets/glances/manifest.json
@@ -0,0 +1,40 @@
{
"name": "Glances: {{placeholder "http.vars.ReqHost"}}",
"short_name": "Glances: {{placeholder "http.vars.ReqHost"}}",
"icons": [
{
"src": "/media/icons/glances/any_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "any"
},
{
"src": "/media/icons/glances/maskable_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "maskable"
}
],
"id": "/glances/",
"start_url": "/glances/",
"theme_color": "#2C363F",
"background_color": "#2C363F",
"display": "fullscreen",
"shortcuts" : [
{
"name": "Refresh 1sec",
"url": "/glances/1",
"description": "Refresh page every 1 second"
},
{
"name": "Refresh 5sec",
"url": "/glances/5",
"description": "Refresh page every 5 seconds"
},
{
"name": "Refresh 10sec",
"url": "/glances/10",
"description": "Refresh page every 10 seconds"
}
]
}
23 changes: 23 additions & 0 deletions .devcontainer/caddy/srv/assets/gzweb/manifest.json
@@ -0,0 +1,23 @@
{
"name": "Gzweb: {{placeholder "http.vars.ReqHost"}}",
"short_name": "Gzweb: {{placeholder "http.vars.ReqHost"}}",
"icons": [
{
"src": "/media/icons/gzweb/any_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "any"
},
{
"src": "/media/icons/gzweb/maskable_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "maskable"
}
],
"id": "/gzweb/",
"start_url": "/gzweb/",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "fullscreen"
}
23 changes: 23 additions & 0 deletions .devcontainer/caddy/srv/assets/nav2/manifest.json
@@ -0,0 +1,23 @@
{
"name": "Nav2: {{placeholder "http.vars.ReqHost"}}",
"short_name": "Nav2: {{placeholder "http.vars.ReqHost"}}",
"icons": [
{
"src": "/media/icons/nav2/any_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "any"
},
{
"src": "/media/icons/nav2/maskable_icon_x512.webp",
"sizes": "512x512",
"type": "image/webp",
"purpose": "maskable"
}
],
"id": "/nav2/",
"start_url": "/nav2/",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
48 changes: 0 additions & 48 deletions .devcontainer/caddy/srv/index.md

This file was deleted.

32 changes: 0 additions & 32 deletions .devcontainer/caddy/srv/manifests/foxglove/manifest.json

This file was deleted.

15 changes: 0 additions & 15 deletions .devcontainer/caddy/srv/manifests/glances/manifest.json

This file was deleted.

15 changes: 0 additions & 15 deletions .devcontainer/caddy/srv/manifests/gzweb/manifest.json

This file was deleted.

8 changes: 0 additions & 8 deletions .devcontainer/caddy/srv/manifests/manifest.json

This file was deleted.

File renamed without changes.
Expand Up @@ -12,6 +12,8 @@
<title>{{$title}}</title>
<meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="github-markdown.css">
<link rel="icon" type="image/webp" href="/media/icons/nav2/any_icon_x512.webp">

<style>
body {
box-sizing: border-box;
Expand Down

0 comments on commit 11615fd

Please sign in to comment.