mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-11-04 10:32:44 +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