mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-10-31 08:15:07 +00:00
ci: add HealthChat desktop build pipeline
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
name: Build HealthChat Desktop
|
||||
|
||||
# Builds the HealthChat desktop (Electron) app: the fork's element-web webapp with
|
||||
# the HealthChat plugin (healthchat-module.js + healthchat-elements.js) injected,
|
||||
# packaged via the existing element-desktop build pipeline.
|
||||
#
|
||||
# This mirrors build-healthchat.yaml (web). It first builds the element-plugin from
|
||||
# healthchat-workspace, builds the fork webapp with the plugin injected, then feeds it
|
||||
# into build_desktop_prepare.yaml via its `webapp-artifact` input and packages it with
|
||||
# build_desktop_linux.yaml.
|
||||
#
|
||||
# IMPORTANT CAVEATS (see apps/desktop/element.io/healthchat/README):
|
||||
# - build_desktop_prepare.yaml / build_desktop_linux.yaml currently `actions/checkout`
|
||||
# `element-hq/element-web` (upstream). The HealthChat webapp + branding come from the
|
||||
# uploaded artifact + variant.json, but the Electron shell (electron-main, icons) is
|
||||
# upstream Element's. To ship a fully fork-branded shell, point those reusable
|
||||
# workflows at this fork (change their `repository:` / add a `ref` input).
|
||||
# - Plugin loading depends on element-main.ts rewriting `/modules/*` -> `/webapp/modules/*`.
|
||||
# Verify that rewrite exists in whichever desktop checkout is used.
|
||||
# - macOS/Windows builds need Element's signing/notarization secrets and are intentionally
|
||||
# omitted here; add build_desktop_macos.yaml / build_desktop_windows.yaml once those are
|
||||
# available.
|
||||
# - Confirm `ch.healthchat.api_base_url` in apps/desktop/element.io/healthchat/config.json
|
||||
# points at the real production API origin (assumed https://healthchat.ch).
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version (e.g. 1.4.0)."
|
||||
required: true
|
||||
type: string
|
||||
workspace_ref:
|
||||
description: "healthchat-workspace ref (defaults to .healthchat-workspace-version)."
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: build-healthchat-desktop-${{ github.event.inputs.version }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
webapp:
|
||||
name: Build webapp + plugin
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Resolve workspace ref
|
||||
id: workspace
|
||||
env:
|
||||
OVERRIDE: ${{ github.event.inputs.workspace_ref }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -n "$OVERRIDE" ]]; then
|
||||
REF="$OVERRIDE"
|
||||
elif [[ -f .healthchat-workspace-version ]]; then
|
||||
REF=$(head -n1 .healthchat-workspace-version | tr -d '[:space:]')
|
||||
[[ -n "$REF" ]] || { echo "::error::.healthchat-workspace-version is empty"; exit 1; }
|
||||
else
|
||||
echo "::error::.healthchat-workspace-version missing and no workspace_ref override provided"
|
||||
exit 1
|
||||
fi
|
||||
echo "ref=$REF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout healthchat-workspace
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: Novaloop-AG/healthchat-workspace
|
||||
path: healthchat-workspace
|
||||
token: ${{ secrets.HEALTHCHAT_WORKSPACE_TOKEN }}
|
||||
ref: ${{ steps.workspace.outputs.ref }}
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install monorepo deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build element-plugin
|
||||
run: |
|
||||
cd healthchat-workspace/element-plugin
|
||||
npm ci
|
||||
npm run build
|
||||
cd module
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Stage plugin artifacts
|
||||
run: |
|
||||
mkdir -p plugin-dist/elements
|
||||
cp healthchat-workspace/element-plugin/module/dist/healthchat-module.js plugin-dist/healthchat-module.js
|
||||
cp healthchat-workspace/element-plugin/dist/elements/browser/main.js plugin-dist/elements/healthchat-elements.js
|
||||
|
||||
- name: Build webapp with plugin injected
|
||||
env:
|
||||
VERSION: ${{ github.event.inputs.version }}
|
||||
run: ./apps/desktop/scripts/build-healthchat-webapp.sh
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: healthchat-webapp
|
||||
retention-days: 1
|
||||
path: apps/desktop/webapp
|
||||
|
||||
prepare:
|
||||
name: Prepare desktop asar
|
||||
needs: webapp
|
||||
permissions:
|
||||
contents: read
|
||||
uses: ./.github/workflows/build_desktop_prepare.yaml
|
||||
with:
|
||||
config: element.io/healthchat
|
||||
webapp-artifact: healthchat-webapp
|
||||
nightly: false
|
||||
deploy: false
|
||||
|
||||
linux:
|
||||
name: Linux ${{ matrix.arch }}
|
||||
needs: prepare
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
uses: ./.github/workflows/build_desktop_linux.yaml
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
sqlcipher: static
|
||||
version: ${{ github.event.inputs.version }}
|
||||
test: false
|
||||
@@ -0,0 +1,62 @@
|
||||
HealthChat desktop variant
|
||||
===========================
|
||||
|
||||
This directory is the `--cfgdir` / build config for HealthChat desktop builds:
|
||||
|
||||
config.json Element Web runtime config baked into webapp.asar. Mirrors
|
||||
apps/web/config.json (HealthChat homeserver, theme, branding) and
|
||||
loads the HealthChat plugin:
|
||||
- "modules": ["/modules/healthchat-module.js"]
|
||||
- "ch.healthchat.elements_base_url": "/webapp/modules/elements"
|
||||
build.json electron-builder variant (appId, productName "HealthChat", protocols).
|
||||
|
||||
Why the paths differ from web
|
||||
-----------------------------
|
||||
The desktop app serves the webapp from `vector://vector/webapp/`, so root-relative
|
||||
paths need a `/webapp` prefix:
|
||||
|
||||
- The `modules` array is rewritten automatically by apps/desktop/src/electron-main.ts
|
||||
(`/modules/x` -> `/webapp/modules/x`), so it stays as `/modules/healthchat-module.js`.
|
||||
- `ch.healthchat.elements_base_url` is NOT auto-rewritten (the elements bundle is loaded
|
||||
by a <script> tag the plugin injects, not by the module loader), so it is set explicitly
|
||||
to `/webapp/modules/elements` here. On web it is `/modules/elements`.
|
||||
|
||||
The plugin artifacts must live inside the asar at `modules/healthchat-module.js` and
|
||||
`modules/elements/healthchat-elements.js`.
|
||||
|
||||
Building locally
|
||||
----------------
|
||||
# 1. Build the element-plugin (from the healthchat-workspace checkout) and stage it:
|
||||
(cd ../healthchat-workspace/element-plugin && npm ci && npm run build)
|
||||
(cd ../healthchat-workspace/element-plugin/module && npm ci && npm run build)
|
||||
mkdir -p plugin-dist/elements
|
||||
cp ../healthchat-workspace/element-plugin/module/dist/healthchat-module.js plugin-dist/healthchat-module.js
|
||||
cp ../healthchat-workspace/element-plugin/dist/elements/browser/main.js plugin-dist/elements/healthchat-elements.js
|
||||
|
||||
# 2. Build the fork webapp with the plugin injected:
|
||||
./apps/desktop/scripts/build-healthchat-webapp.sh
|
||||
|
||||
# 3. Pack and run:
|
||||
cp apps/desktop/element.io/healthchat/config.json apps/desktop/webapp/config.json
|
||||
pnpm --dir apps/desktop run asar-webapp
|
||||
pnpm --dir apps/desktop start
|
||||
|
||||
CI
|
||||
--
|
||||
.github/workflows/build-healthchat-desktop.yaml builds the plugin + webapp artifact and
|
||||
feeds it into build_desktop_prepare.yaml (`config: element.io/healthchat`,
|
||||
`webapp-artifact: healthchat-webapp`) and build_desktop_linux.yaml.
|
||||
|
||||
Open items before a production release
|
||||
--------------------------------------
|
||||
- api_base_url: confirm the production API origin in config.json (currently assumed
|
||||
https://healthchat.ch). On desktop this MUST be absolute (vector:// origin can't reach
|
||||
a relative /api).
|
||||
- Fork vs upstream shell: build_desktop_prepare.yaml / build_desktop_linux.yaml check out
|
||||
element-hq/element-web (upstream). The webapp + variant are HealthChat's, but the Electron
|
||||
shell (electron-main, icons) is upstream. Point those workflows at this fork to fully brand
|
||||
the shell, and to guarantee the `/modules` -> `/webapp/modules` rewrite is present.
|
||||
- macOS/Windows: need signing/notarization secrets; add the macos/windows reusable workflows
|
||||
once configured.
|
||||
- Deploy target: the upstream deploy job pushes to packages.element.io / Cloudflare R2 — wire
|
||||
up a HealthChat distribution target instead.
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"appId": "ch.healthchat.desktop",
|
||||
"name": "healthchat-desktop",
|
||||
"productName": "HealthChat",
|
||||
"description": "HealthChat: secure communication for healthcare",
|
||||
"protocols": ["ch.healthchat.desktop", "healthchat"]
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"brand": "HealthChat",
|
||||
"branding": {
|
||||
"auth_footer_links": null,
|
||||
"auth_header_logo_url": "themes/element/img/logos/element-logo.png",
|
||||
"welcome_background_url": null
|
||||
},
|
||||
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
|
||||
"default_country_code": "GB",
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://matrix.healthchat.ch",
|
||||
"server_name": "healthchat.ch"
|
||||
},
|
||||
"m.identity_server": {
|
||||
"base_url": ""
|
||||
}
|
||||
},
|
||||
"default_theme": "custom-HealthChat Light",
|
||||
"disable_custom_urls": true,
|
||||
"disable_guests": true,
|
||||
"element_call": {},
|
||||
"embedded_pages": {
|
||||
"homeUrl": ""
|
||||
},
|
||||
"enable_presence_by_hs_url": "",
|
||||
"features": {},
|
||||
"integrations_jitsi_widget_url": "https://scalar.vector.im/api/widgets/jitsi.html",
|
||||
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||
"integrations_ui_url": "https://scalar.vector.im/",
|
||||
"integrations_widgets_urls": ["https://scalar.vector.im/api"],
|
||||
"jitsi": {
|
||||
"preferred_domain": "jitsi.healthchat.ch"
|
||||
},
|
||||
"logout_redirect_url": "",
|
||||
"permalink_prefix": "https://matrix.to",
|
||||
"room_directory": {
|
||||
"servers": ["matrix.org"]
|
||||
},
|
||||
"sso_redirect_options": {
|
||||
"immediate": true,
|
||||
"on_welcome_page": true,
|
||||
"on_login_page": true
|
||||
},
|
||||
"setting_defaults": {
|
||||
"UIFeature.deactivate": false,
|
||||
"UIFeature.advancedEncryption": false,
|
||||
"UIFeature.thirdPartyId": false,
|
||||
"UIFeature.identityServer": false,
|
||||
"UIFeature.shareSocial": false,
|
||||
"UIFeature.advancedSettings": false,
|
||||
"UIFeature.feedback": false,
|
||||
"custom_themes": [
|
||||
"HealthChat Light",
|
||||
{
|
||||
"name": "HealthChat Light",
|
||||
"is_dark": false,
|
||||
"colors": {
|
||||
"accent-color": "#1f4d85",
|
||||
"primary-color": "#1f4d85",
|
||||
"alert": "#df8e1d",
|
||||
"warning-color": "#d20f39",
|
||||
"sidebar-color": "#12325c",
|
||||
"roomlist-background-color": "#f5f5f5",
|
||||
"roomlist-highlights-color": "#d9d9d9",
|
||||
"roomlist-separator-color": "#9b9898",
|
||||
"roomlist-text-color": "#473e3e",
|
||||
"roomlist-text-secondary-color": "#9b9898",
|
||||
"timeline-background-color": "#ffffff",
|
||||
"timeline-highlights-color": "#d9d9d9",
|
||||
"timeline-text-color": "#473e3e",
|
||||
"timeline-text-secondary-color": "#9b9898",
|
||||
"secondary-content": "#9b9898",
|
||||
"tertiary-content": "#9b9898",
|
||||
"focus-bg-color": "#d9d9d9",
|
||||
"menu-selected-color": "#d9d9d9",
|
||||
"other-user-pill-bg-color": "#376A91",
|
||||
"room-highlight-color": "#376A91",
|
||||
"reaction-row-button-selected-bg-color": "#d9d9d9",
|
||||
"togglesw-off-color": "#9b9898",
|
||||
"avatar-background-colors": ["#12325c", "#1f4d85", "#376A91"],
|
||||
"username-colors": ["#12325c", "#2a4063", "#1f4d85", "#376A91", "#473e3e", "#1f4d85", "#2a4063", "#12325c"]
|
||||
},
|
||||
"fonts": {
|
||||
"general": "\"Century Gothic\", \"Futura\", \"Trebuchet MS\", \"Arial\", sans-serif"
|
||||
},
|
||||
"compound": {
|
||||
"--cpd-color-text-action-accent": "#1f4d85",
|
||||
"--cpd-color-bg-action-primary-rest": "#1f4d85",
|
||||
"--cpd-color-bg-action-primary-hovered": "#2a4063",
|
||||
"--cpd-color-bg-action-primary-pressed": "#12325c",
|
||||
"--cpd-color-text-link-external": "#1f4d85",
|
||||
"--cpd-color-icon-accent-tertiary": "#376A91"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"show_labs_settings": false,
|
||||
"modules": ["/modules/healthchat-module.js"],
|
||||
"ch.healthchat": {
|
||||
"api_base_url": "https://healthchat.ch",
|
||||
"elements_base_url": "/webapp/modules/elements"
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build the HealthChat desktop webapp directory: the fork's element-web build with
|
||||
# the HealthChat plugin artifacts injected at modules/. The result is written to
|
||||
# apps/desktop/webapp so it can either be:
|
||||
# - packed locally with `pnpm --dir apps/desktop run asar-webapp` (after copying
|
||||
# element.io/healthchat/config.json over webapp/config.json), or
|
||||
# - uploaded as the `webapp-artifact` consumed by build_desktop_prepare.yaml
|
||||
# (which overlays element.io/healthchat/config.json and packs the asar for you).
|
||||
#
|
||||
# Plugin artifacts are taken from $PLUGIN_DIST (default: ./plugin-dist at repo root),
|
||||
# expecting:
|
||||
# $PLUGIN_DIST/healthchat-module.js
|
||||
# $PLUGIN_DIST/elements/healthchat-elements.js
|
||||
# Build them first from the healthchat-workspace element-plugin:
|
||||
# (cd element-plugin && npm ci && npm run build)
|
||||
# (cd element-plugin/module && npm ci && npm run build)
|
||||
# then stage main.js -> healthchat-elements.js (see build-healthchat-desktop.yaml).
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
PLUGIN_DIST="${PLUGIN_DIST:-plugin-dist}"
|
||||
WEBAPP_SRC="apps/web/webapp"
|
||||
WEBAPP_DEST="apps/desktop/webapp"
|
||||
|
||||
if [ ! -f "$PLUGIN_DIST/healthchat-module.js" ] || [ ! -f "$PLUGIN_DIST/elements/healthchat-elements.js" ]; then
|
||||
echo "error: missing plugin artifacts under '$PLUGIN_DIST'." >&2
|
||||
echo " expected:" >&2
|
||||
echo " $PLUGIN_DIST/healthchat-module.js" >&2
|
||||
echo " $PLUGIN_DIST/elements/healthchat-elements.js" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building fork element-web webapp..."
|
||||
VERSION="${VERSION:-$(git describe --abbrev=0 --tags 2>/dev/null || echo 0.0.0)}"
|
||||
VERSION="$VERSION" pnpm --dir apps/web build
|
||||
|
||||
echo "Injecting HealthChat plugin into $WEBAPP_DEST/modules ..."
|
||||
rm -rf "$WEBAPP_DEST"
|
||||
cp -R "$WEBAPP_SRC" "$WEBAPP_DEST"
|
||||
mkdir -p "$WEBAPP_DEST/modules/elements"
|
||||
cp "$PLUGIN_DIST/healthchat-module.js" "$WEBAPP_DEST/modules/healthchat-module.js"
|
||||
cp "$PLUGIN_DIST/elements/healthchat-elements.js" "$WEBAPP_DEST/modules/elements/healthchat-elements.js"
|
||||
|
||||
echo "Done -> $WEBAPP_DEST"
|
||||
echo
|
||||
echo "To produce webapp.asar locally:"
|
||||
echo " cp apps/desktop/element.io/healthchat/config.json $WEBAPP_DEST/config.json"
|
||||
echo " pnpm --dir apps/desktop run asar-webapp"
|
||||
Reference in New Issue
Block a user