diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 164afa07..908981c5 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -15,6 +15,7 @@ module.exports = {
"plugin:matrix-org/typescript",
"prettier",
"plugin:rxjs/recommended",
+ "plugin:storybook/recommended",
],
parserOptions: {
ecmaVersion: "latest",
diff --git a/.githooks/post-commit b/.githooks/post-commit
deleted file mode 100755
index 467799bd..00000000
--- a/.githooks/post-commit
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/sh
-
-FILE=.links.temp-disabled.yaml
-if test -f "$FILE"; then
- # Only do the post-commit hook if the file was temp-disabled by the pre-commit hook.
- # Otherwise linking was actively (`yarn links:disable`) disabled and this hook should noop.
- mv .links.temp-disabled.yaml .links.yaml
- yarnLog=$(yarn)
- echo "[yarn-linker] The post-commit hook has re-enabled .links.yaml."
- exit 1
-fi
diff --git a/.githooks/pre-commit b/.githooks/pre-commit
index 435d75f1..2656c9b9 100755
--- a/.githooks/pre-commit
+++ b/.githooks/pre-commit
@@ -1,11 +1,9 @@
-#!/usr/bin/sh
+#!/usr/bin/env bash
-FILE=".links.yaml"
-if test -f "$FILE"; then
- mv .links.yaml .links.temp-disabled.yaml
- # echo "running yarn"
- x=$(yarn)
- y=$(git add yarn.lock)
- echo "[yarn-linker] The pre-commit hook has disabled .links.yaml and MODIFIED the yarn.lock file. Review the staged changes (the hook added yarn.lock, was this desired?) and run \`git commit \` again if they look okay. The post-commit hook will re-enable your links."
+# Checks if there currently is linking configured. Informs the user to disable linking before committing.
+
+PNPMFILE=.pnpmfile.cjs
+if test -f "$PNPMFILE"; then
+ echo "[pnpm-linker] The pre-commit hook detected $PNPMFILE which implies you have linked packages in your pnpm-lock.yaml. Run pnpm links:off and commit again. See also linking.md."
exit 1
fi
diff --git a/.github/workflows/build-element-call.yaml b/.github/workflows/build-element-call.yaml
index 3ddabb0b..f4071975 100644
--- a/.github/workflows/build-element-call.yaml
+++ b/.github/workflows/build-element-call.yaml
@@ -37,15 +37,16 @@ jobs:
persist-credentials: false
- name: Enable Corepack
run: corepack enable
- - name: Yarn cache
+ - name: pnpm cache
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
- cache: "yarn"
+ cache: "pnpm"
node-version-file: ".node-version"
- name: Install dependencies
- run: "yarn install --immutable"
+ # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present)
+ run: "pnpm install --frozen-lockfile --ignore-pnpmfile"
- name: Build Element Call
- run: yarn run build:"$PACKAGE":"$BUILD_MODE"
+ run: pnpm run build:"$PACKAGE":"$BUILD_MODE"
env:
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 32ce25c9..ba7cde51 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -85,3 +85,31 @@ jobs:
SENTRY_URL: ${{ secrets.SENTRY_URL }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+
+ build_storybook:
+ name: Build Storybook
+ if: contains(github.event.pull_request.labels.*.name, 'storybook build')
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ persist-credentials: false
+ - name: Enable Corepack
+ run: corepack enable
+ - name: pnpm cache
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
+ with:
+ cache: "pnpm"
+ node-version-file: ".node-version"
+ - name: Install dependencies
+ run: "pnpm install --frozen-lockfile --ignore-pnpmfile"
+ - name: Build Storybook
+ run: pnpm run build-storybook
+ - name: Upload Artifact
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ with:
+ name: build-output-storybook
+ path: storybook-static
+ # We'll only use this in a triggered job, then we're done with it
+ retention-days: 1
diff --git a/.github/workflows/changelog-label.yml b/.github/workflows/changelog-label.yml
index f11d3130..84c53cdb 100644
--- a/.github/workflows/changelog-label.yml
+++ b/.github/workflows/changelog-label.yml
@@ -5,7 +5,7 @@ on:
# This is safe because we do not use actions/checkout or execute untrusted code.
# Using pull_request_target is necessary to allow status writes for PRs from forks.
pull_request_target:
- types: [labeled, unlabeled, opened]
+ types: [labeled, unlabeled, opened, synchronize]
permissions:
pull-requests: read
diff --git a/.github/workflows/deploy-to-netlify.yaml b/.github/workflows/deploy-to-netlify.yaml
index 76609328..554e384b 100644
--- a/.github/workflows/deploy-to-netlify.yaml
+++ b/.github/workflows/deploy-to-netlify.yaml
@@ -17,7 +17,7 @@ on:
package:
required: true
type: string
- description: Which package to deploy - 'full', 'embedded', or 'sdk'
+ description: Which package to deploy - 'full', 'embedded', 'sdk', or 'storybook'
artifact_run_id:
required: false
type: string
@@ -43,7 +43,7 @@ jobs:
with:
step: start
token: ${{ secrets.GITHUB_TOKEN }}
- env: Netlify
+ env: ${{ inputs.package}}
ref: ${{ inputs.deployment_ref }}
desc: |
Do you trust the author of this PR? Maybe this build will steal your keys or give you malware.
@@ -59,9 +59,13 @@ jobs:
- name: Add redirects file
# We fetch from github directly as we don't bother checking out the repo
+ # Not needed for storybook deployments
+ if: inputs.package != 'storybook'
run: curl -s https://raw.githubusercontent.com/element-hq/element-call/main/config/netlify_redirects > webapp/_redirects
- name: Add config file
+ # Not needed for storybook deployments
+ if: inputs.package != 'storybook'
run: |
if [ "${INPUTS_PACKAGE}" = "full" ]; then
curl -s "https://raw.githubusercontent.com/${INPUTS_PR_HEAD_FULL_NAME}/${INPUTS_PR_HEAD_REF}/config/config_netlify_preview.json" > webapp/config.json
@@ -78,7 +82,7 @@ jobs:
with:
publish-dir: webapp
deploy-message: "Deploy from GitHub Actions"
- alias: ${{ inputs.package == 'sdk' && format('pr{0}-sdk', inputs.pr_number) || format('pr{0}', inputs.pr_number) }}
+ alias: ${{ inputs.package == 'sdk' && format('pr{0}-sdk', inputs.pr_number) || inputs.package == 'storybook' && format('pr{0}-storybook', inputs.pr_number) || format('pr{0}', inputs.pr_number) }}
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 763d2eac..0638eca6 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -12,20 +12,21 @@ jobs:
persist-credentials: false
- name: Enable Corepack
run: corepack enable
- - name: Yarn cache
+ - name: pnpm cache
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
- cache: "yarn"
+ cache: "pnpm"
node-version-file: ".node-version"
- name: Install dependencies
- run: "yarn install --immutable"
+ # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present)
+ run: "pnpm install --frozen-lockfile --ignore-pnpmfile"
- name: Prettier
- run: "yarn run prettier:check"
+ run: "pnpm run prettier:check"
- name: i18n
- run: "yarn run i18n:check"
+ run: "pnpm run i18n:check"
- name: ESLint
- run: "yarn run lint:eslint"
+ run: "pnpm run lint:eslint"
- name: Type check
- run: "yarn run lint:types"
+ run: "pnpm run lint:types"
- name: Dead code analysis
- run: "yarn run lint:knip"
+ run: "pnpm run lint:knip"
diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml
index 0084b76b..3d88b083 100644
--- a/.github/workflows/pr-deploy.yaml
+++ b/.github/workflows/pr-deploy.yaml
@@ -14,7 +14,7 @@ jobs:
# 2. Event must be a pull_request
# 3. Head repository must be the SAME as the base repository (No Forks!)
if: >
- github.event.workflow_run.conclusion == 'success' &&
+ github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.head_repository.full_name == github.repository
runs-on: ubuntu-latest
@@ -63,6 +63,24 @@ jobs:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
+ netlify-storybook:
+ needs: prdetails
+ if: ${{ needs.prdetails.outputs.pr_data_json && contains(fromJSON(needs.prdetails.outputs.pr_data_json).labels.*.name, 'storybook build') }}
+ permissions:
+ deployments: write
+ uses: ./.github/workflows/deploy-to-netlify.yaml
+ with:
+ artifact_run_id: ${{ github.event.workflow_run.id || github.run_id }}
+ pr_number: ${{ needs.prdetails.outputs.pr_number }}
+ pr_head_full_name: ${{ github.event.workflow_run.head_repository.full_name }}
+ pr_head_ref: ${{ needs.prdetails.outputs.pr_data_json && fromJSON(needs.prdetails.outputs.pr_data_json).head.ref }}
+ deployment_ref: ${{ needs.prdetails.outputs.pr_data_json && fromJSON(needs.prdetails.outputs.pr_data_json).head.sha || github.ref || github.head_ref }}
+ package: storybook
+ secrets:
+ ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
+ NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
+ NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
+
docker:
if: ${{ needs.prdetails.outputs.pr_data_json && contains(fromJSON(needs.prdetails.outputs.pr_data_json).labels.*.name, 'docker build') }}
needs: prdetails
diff --git a/.github/workflows/publish-embedded-packages.yaml b/.github/workflows/publish-embedded-packages.yaml
index 3ab275a5..88d59947 100644
--- a/.github/workflows/publish-embedded-packages.yaml
+++ b/.github/workflows/publish-embedded-packages.yaml
@@ -97,7 +97,7 @@ jobs:
run: find ${FILENAME_PREFIX} -type f -print0 | sort -z | xargs -0 sha256sum | tee ${FILENAME_PREFIX}.sha256
- name: Upload
if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }}
- uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
+ uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2
with:
files: |
${{ env.FILENAME_PREFIX }}.tar.gz
@@ -297,7 +297,7 @@ jobs:
NEEDS_PUBLISH_IOS_OUTPUTS_ARTIFACT_VERSION: ${{ needs.publish_ios.outputs.ARTIFACT_VERSION }}
- name: Add release notes
if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }}
- uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
+ uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2
with:
append_body: true
body: |
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index 0675b1b1..40b94e26 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -42,7 +42,7 @@ jobs:
- name: Create Checksum
run: find ${FILENAME_PREFIX} -type f -print0 | sort -z | xargs -0 sha256sum | tee ${FILENAME_PREFIX}.sha256
- name: Upload
- uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
+ uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2
with:
files: |
${{ env.FILENAME_PREFIX }}.tar.gz
@@ -71,7 +71,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Add release note
- uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
+ uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2
with:
append_body: true
body: |
diff --git a/.github/workflows/test-netlify.yaml b/.github/workflows/test-netlify.yaml
new file mode 100644
index 00000000..bccde445
--- /dev/null
+++ b/.github/workflows/test-netlify.yaml
@@ -0,0 +1,48 @@
+# Triggers after the playwright tests have finished,
+# taking the artifact and uploading it to Netlify for easier viewing
+name: Upload End to End Test report to Netlify
+on:
+ # Privilege escalation necessary to publish to Netlify
+ # 🚨 We must not execute any checked out code here.
+ workflow_run: # zizmor: ignore[dangerous-triggers]
+ workflows: ["Test"]
+ types:
+ - completed
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }}
+ cancel-in-progress: ${{ github.event.workflow_run.event == 'pull_request' }}
+
+permissions: {}
+
+jobs:
+ report:
+ if: github.event.workflow_run.conclusion != 'cancelled'
+ name: Report results
+ runs-on: ubuntu-24.04
+ environment: Netlify
+ permissions:
+ statuses: write
+ deployments: write
+ actions: read
+ steps:
+ - name: Download HTML report
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ run-id: ${{ github.event.workflow_run.id }}
+ name: html-report
+ path: playwright-report
+
+ - name: 📤 Deploy to Netlify
+ uses: matrix-org/netlify-pr-preview@9805cd123fc9a7e421e35340a05e1ebc5dee46b5 # v3
+ with:
+ path: playwright-report
+ owner: ${{ github.event.workflow_run.head_repository.owner.login }}
+ branch: ${{ github.event.workflow_run.head_branch }}
+ revision: ${{ github.event.workflow_run.head_sha }}
+ token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
+ site_id: ${{ secrets.NETLIFY_SITE_ID }}
+ desc: Playwright Report
+ deployment_env: EndToEndTests
+ prefix: "e2e-"
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index cd1c94c5..d8af6f92 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -14,17 +14,18 @@ jobs:
persist-credentials: false
- name: Enable Corepack
run: corepack enable
- - name: Yarn cache
+ - name: pnpm cache
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
- cache: "yarn"
+ cache: "pnpm"
node-version-file: ".node-version"
- name: Install dependencies
- run: "yarn install --immutable"
+ # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present)
+ run: "pnpm install --frozen-lockfile --ignore-pnpmfile"
- name: Vitest
- run: "yarn run test:coverage"
+ run: "pnpm run test:coverage"
- name: Upload to codecov
- uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
+ uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
@@ -42,12 +43,13 @@ jobs:
run: corepack enable
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
- cache: "yarn"
+ cache: "pnpm"
node-version-file: ".node-version"
- name: Install dependencies
- run: yarn install --immutable
+ # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present)
+ run: pnpm install --frozen-lockfile --ignore-pnpmfile
- name: Install Playwright Browsers
- run: yarn playwright install --with-deps
+ run: pnpm exec playwright install --with-deps
- name: Run backend components
run: |
docker compose -f playwright-backend-docker-compose.yml -f playwright-backend-docker-compose.override.yml pull
@@ -56,10 +58,11 @@ jobs:
- name: Run Playwright tests
env:
USE_DOCKER: 1
- run: yarn playwright test
- - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ run: pnpm exec playwright test
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
- name: playwright-report
- path: playwright-report/
- retention-days: 3
+ name: html-report
+ path: playwright-report
+ if-no-files-found: error
+ retention-days: 4
diff --git a/.github/workflows/translations-download.yaml b/.github/workflows/translations-download.yaml
index ad9f4652..08260a5a 100644
--- a/.github/workflows/translations-download.yaml
+++ b/.github/workflows/translations-download.yaml
@@ -22,11 +22,12 @@ jobs:
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
- cache: "yarn"
+ cache: "pnpm"
node-version-file: ".node-version"
- name: Install Deps
- run: "yarn install --immutable"
+ # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present)
+ run: "pnpm install --frozen-lockfile --ignore-pnpmfile"
- name: Prune i18n
run: "rm -R locales"
@@ -40,7 +41,7 @@ jobs:
run: "sudo chown runner:docker -R locales"
- name: Prettier
- run: yarn prettier:format
+ run: pnpm prettier:format
- name: Create Pull Request
id: cpr
diff --git a/.gitignore b/.gitignore
index 5751844a..e9225072 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,12 +21,20 @@ yarn-error.log
!/.yarn/releases
!/.yarn/sdks
!/.yarn/versions
+# old yarn based linking
/.links.yaml
/.links.disabled.yaml
/.links.temp-disabled.yaml
+# pnpm based linking
+/.links.cjs
+/.links.disabled.cjs
+/.links.temp-disabled.cjs
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
+
+*storybook.log
+storybook-static
diff --git a/.prettierignore b/.prettierignore
index f06235c4..31e6cd83 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,2 +1,3 @@
+pnpm-lock.yaml
node_modules
dist
diff --git a/.storybook/main.ts b/.storybook/main.ts
new file mode 100644
index 00000000..977eca73
--- /dev/null
+++ b/.storybook/main.ts
@@ -0,0 +1,15 @@
+/*
+Copyright 2026 Element Creations Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE in the repository root for full details.
+*/
+
+import type { StorybookConfig } from "@storybook/react-vite";
+
+const config: StorybookConfig = {
+ stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
+ addons: ["@storybook/addon-docs"],
+ framework: "@storybook/react-vite",
+};
+export default config;
diff --git a/.storybook/manager.ts b/.storybook/manager.ts
new file mode 100644
index 00000000..1177be2f
--- /dev/null
+++ b/.storybook/manager.ts
@@ -0,0 +1,31 @@
+/*
+Copyright 2026 Element Creations Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE in the repository root for full details.
+*/
+
+import { create } from "storybook/theming";
+import { addons } from "storybook/manager-api";
+
+addons.setConfig({
+ theme: create({
+ base: "light",
+ colorPrimary: "#1b1d22",
+ colorSecondary: "#0467dd",
+
+ // Typography
+ fontBase: '"Inter", sans-serif',
+ fontCode: '"Inconsolata", monospace',
+
+ // Text colors
+ textColor: "#1b1d22",
+ appBg: "#ffffff",
+ barBg: "#ffffff",
+
+ brandTitle: "Element Call",
+ brandUrl: "https://element.io/",
+ brandImage: "/src/icons/Logo.svg",
+ brandTarget: "_self",
+ }),
+});
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
new file mode 100644
index 00000000..757c1f8a
--- /dev/null
+++ b/.storybook/preview.tsx
@@ -0,0 +1,56 @@
+/*
+Copyright 2026 Element Creations Ltd.
+
+SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
+Please see LICENSE in the repository root for full details.
+*/
+
+import type { Preview } from "@storybook/react-vite";
+import { TooltipProvider } from "@vector-im/compound-web";
+import i18n from "i18next";
+import { logger } from "matrix-js-sdk/lib/logger";
+
+import EN from "../locales/en/app.json";
+import { initReactI18next } from "react-i18next";
+import "../src/index.css";
+
+// Bare-minimum i18n config
+i18n
+ .use(initReactI18next)
+ .init({
+ lng: "en",
+ fallbackLng: "en",
+ supportedLngs: ["en"],
+ // We embed the translations, so that it never needs to fetch
+ resources: {
+ en: {
+ translation: EN,
+ },
+ },
+ interpolation: {
+ escapeValue: false, // React has built-in XSS protections
+ },
+ })
+ .catch((e) => logger.warn("Failed to init i18n for stories", e));
+
+const preview: Preview = {
+ parameters: {
+ layout: "centered",
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/i,
+ },
+ },
+ },
+ tags: ["autodocs"],
+ decorators: [
+ (Story) => (
+
@@ -186,7 +186,7 @@ To get started clone and set up this project: git clone https://github.com/element-hq/element-call.git cd element-call corepack enable -yarn +pnpm install ``` To use it, create a local config by, e.g., @@ -197,7 +197,7 @@ environment as outlined in the next section out of box. You're now ready to launch the development server: ```sh -yarn dev +pnpm dev ``` See also: @@ -230,7 +230,7 @@ only for local development and **_never be exposed to the public Internet._** Run backend components: ```sh -yarn backend +pnpm backend # or for podman-compose # podman-compose -f dev-backend-docker-compose.yml up ``` @@ -260,13 +260,13 @@ on https://localhost:3000 (this is configured in `playwright.config.ts`) - this is what will be tested. The local backend environment should be running for the test to work: -`yarn backend` +`pnpm backend` There are a few different ways to run the tests yourself. The simplest is to run: ```shell -yarn run test:playwright +pnpm run test:playwright ``` This will run the Playwright tests once, non-interactively. @@ -274,7 +274,7 @@ This will run the Playwright tests once, non-interactively. There is a more user-friendly way to run the tests in interactive mode: ```shell -yarn run test:playwright:open +pnpm run test:playwright:open ``` The easiest way to develop new test is to use the codegen feature of Playwright: @@ -316,7 +316,7 @@ To add a new translation key you can do these steps: 1. Add the new key entry to the code where the new key is used: `t("some_new_key")` -1. Run `yarn i18n` to extract the new key and update the translation files. This +1. Run `pnpm i18n` to extract the new key and update the translation files. This will add a skeleton entry to the `locales/en/app.json` file: ```jsonc diff --git a/WIDGET_TEST.md b/WIDGET_TEST.md index 53e26a29..fbad026a 100644 --- a/WIDGET_TEST.md +++ b/WIDGET_TEST.md @@ -1,6 +1,6 @@ # Testing Element-Call in widget mode -When running `yarn backend` the latest element-web develop will be deployed and served on `http://localhost:8081`. +When running `pnpm backend` the latest element-web develop will be deployed and served on `http://localhost:8081`. In a development environment, you might prefer to just use the `element-web` repo directly, but this setup is useful for CI/CD testing. ## Setup @@ -18,7 +18,7 @@ that uses It is part of the existing backend setup. To start the backend, run: ```sh -yarn backend +pnpm backend ``` Then open `http://localhost:8081` in your browser. diff --git a/backend/dev_homeserver-othersite.yaml b/backend/dev_homeserver-othersite.yaml index 81e775ca..7eb8f294 100644 --- a/backend/dev_homeserver-othersite.yaml +++ b/backend/dev_homeserver-othersite.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/backend/dev_homeserver.yaml b/backend/dev_homeserver.yaml index dc7b42c8..0aea2ece 100644 --- a/backend/dev_homeserver.yaml +++ b/backend/dev_homeserver.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/backend/dev_livekit-othersite.yaml b/backend/dev_livekit-othersite.yaml index 0ae98c24..53fc9ce9 100644 --- a/backend/dev_livekit-othersite.yaml +++ b/backend/dev_livekit-othersite.yaml @@ -18,3 +18,7 @@ keys: devkey: secret room: auto_create: false +webhook: + api_key: devkey + urls: + - https://matrix-rtc.othersite.m.localhost/livekit/jwt/sfu_webhook diff --git a/backend/dev_livekit.yaml b/backend/dev_livekit.yaml index 157e4d04..6cef4241 100644 --- a/backend/dev_livekit.yaml +++ b/backend/dev_livekit.yaml @@ -18,3 +18,7 @@ keys: devkey: secret room: auto_create: false +webhook: + api_key: devkey + urls: + - https://matrix-rtc.m.localhost/livekit/jwt/sfu_webhook diff --git a/backend/dev_nginx.conf b/backend/dev_nginx.conf index d3ddbc53..6ec0d701 100644 --- a/backend/dev_nginx.conf +++ b/backend/dev_nginx.conf @@ -28,14 +28,19 @@ server { # Reason: the lk-jwt-service uses the federation API for the openid token # verification, which requires TLS location ~ ^(/_matrix|/_synapse/client) { - proxy_pass "http://homeserver:8008"; + proxy_pass "http://homeserver:8008"; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; + proxy_set_header Host $host; + } + location ~ ^(/_matrix|/_synapse/admin) { + proxy_pass "http://homeserver:8008"; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; } - - error_page 500 502 503 504 /50x.html; } @@ -73,10 +78,16 @@ server { proxy_http_version 1.1; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; + proxy_set_header Host $host; } - error_page 500 502 503 504 /50x.html; + location ~ ^(/_matrix|/_synapse/admin) { + proxy_pass "http://homeserver-1:18008"; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + } } @@ -108,7 +119,7 @@ server { # JWT Service running at port 6080 proxy_pass http://jwt-auth-services/; - + } location ^~ /livekit/sfu/ { @@ -128,8 +139,6 @@ server { # LiveKit SFU websocket connection running at port 7880 proxy_pass http://livekit-sfu:7880/; } - - error_page 500 502 503 504 /50x.html; } @@ -156,7 +165,7 @@ server { # JWT Service running at port 16080 proxy_pass http://auth-service-1:16080/; - + } location ^~ /livekit/sfu/ { @@ -176,14 +185,12 @@ server { # LiveKit SFU websocket connection running at port 17880 proxy_pass http://livekit-sfu-1:17880/; } - - error_page 500 502 503 504 /50x.html; } # Convenience reverse proxy for the call.m.localhost domain to element call # running on the host either via -# - yarn dev --host or +# - pnpm dev --host or # - falling back to http (the element call docker container) server { listen 80; @@ -228,7 +235,6 @@ server { proxy_pass http://host.docker.internal:8080; } - error_page 500 502 503 504 /50x.html; } @@ -260,8 +266,6 @@ server { proxy_ssl_verify off; } - - error_page 500 502 503 504 /50x.html; } @@ -293,7 +297,5 @@ server { proxy_ssl_verify off; } - - error_page 500 502 503 504 /50x.html; } diff --git a/backend/playwright_homeserver-othersite.yaml b/backend/playwright_homeserver-othersite.yaml index 35640ae9..86c77b35 100644 --- a/backend/playwright_homeserver-othersite.yaml +++ b/backend/playwright_homeserver-othersite.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/backend/playwright_homeserver.yaml b/backend/playwright_homeserver.yaml index a83247cd..8f437524 100644 --- a/backend/playwright_homeserver.yaml +++ b/backend/playwright_homeserver.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/dev-backend-docker-compose.yml b/dev-backend-docker-compose.yml index 8d885399..702aef39 100644 --- a/dev-backend-docker-compose.yml +++ b/dev-backend-docker-compose.yml @@ -3,7 +3,7 @@ networks: services: auth-service: - image: ghcr.io/element-hq/lk-jwt-service:sha-f8ddd00 + image: ghcr.io/element-hq/lk-jwt-service:0.4.4 pull_policy: always hostname: auth-server environment: @@ -25,7 +25,7 @@ services: - ecbackend auth-service-1: - image: ghcr.io/element-hq/lk-jwt-service:sha-f8ddd00 + image: ghcr.io/element-hq/lk-jwt-service:0.4.4 pull_policy: always hostname: auth-server-1 environment: @@ -47,7 +47,7 @@ services: - ecbackend livekit: - image: livekit/livekit-server:v1.9.11 + image: livekit/livekit-server:v1.10.1 pull_policy: always hostname: livekit-sfu command: --dev --config /etc/livekit.yaml @@ -62,12 +62,15 @@ services: - 7882:7882/tcp - 50100-50200:50100-50200/udp volumes: + - ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z - ./backend/dev_livekit.yaml:/etc/livekit.yaml:Z + environment: + - SSL_CERT_FILE=/local_cert.pem networks: - ecbackend livekit-1: - image: livekit/livekit-server:v1.9.11 + image: livekit/livekit-server:v1.10.1 pull_policy: always hostname: livekit-sfu-1 command: --dev --config /etc/livekit.yaml @@ -82,7 +85,10 @@ services: - 17882:17882/tcp - 50300-50400:50300-50400/udp volumes: + - ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z - ./backend/dev_livekit-othersite.yaml:/etc/livekit.yaml:Z + environment: + - SSL_CERT_FILE=/local_cert.pem networks: - ecbackend @@ -164,6 +170,8 @@ services: - "8448:8448" extra_hosts: - "host.docker.internal:host-gateway" + - "auth-server:127.0.0.1" + - "auth-server-1:127.0.0.1" depends_on: - synapse networks: diff --git a/docs/README.md b/docs/README.md index d97e8d56..e5a5d08a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,8 +2,8 @@ This folder contains documentation for setup, usage, and development of Element Call. -- [Embedded vs standalone mode](./embedded-standalone.md) -- [Url format and parameters](./url-params.md) +- [Embedded vs standalone mode](./embedded_standalone.md) +- [Url format and parameters](./url_params.md) - [Global JS controls](./controls.md) -- [Self-Hosting](./self-hosting.md) +- [Self-Hosting](./self_hosting.md) - [Developing with linked packages](./linking.md) diff --git a/docs/embedded-standalone.md b/docs/embedded_standalone.md similarity index 97% rename from docs/embedded-standalone.md rename to docs/embedded_standalone.md index 440dfac0..24ad2a7d 100644 --- a/docs/embedded-standalone.md +++ b/docs/embedded_standalone.md @@ -14,7 +14,7 @@ The table below provides a comparison of the two packages: | **Release artifacts** | Docker Image, Tarball | Tarball, NPM for Web, Android AAR, SwiftPM for iOS | | **Recommended for** | Standalone/guest access usage | Embedding within messenger apps | | **Responsibility for regulatory compliance** | The administrator that is deploying the app is responsible for compliance with any applicable regulations (e.g. privacy) | The developer of the messenger app is responsible for compliance | -| **Analytics consent** | Element Call will show a consent UI. | Element Call will not show a consent UI. The messenger app should only provide the embedded Element Call with the [analytics URL parameters](./url-params.md#embedded-only-parameters) if consent has been granted. | +| **Analytics consent** | Element Call will show a consent UI. | Element Call will not show a consent UI. The messenger app should only provide the embedded Element Call with the [analytics URL parameters](./url_params.md#embedded-only-parameters) if consent has been granted. | | **Analytics data** | Element Call will send data to the Posthog, Sentry and Open Telemetry targets specified by the administrator in the `config.json` | Element Call will send data to the Posthog and Sentry targets specified in the URL parameters by the messenger app | ### Using the embedded package within a messenger app @@ -26,7 +26,7 @@ The basics are: 1. Add the appropriate platform dependency as given for a [release](https://github.com/element-hq/element-call/releases), or use the embedded tarball. e.g. `npm install @element-hq/element-call-embedded@0.9.0` 2. Include the assets from the platform dependency in the build process. e.g. copy the assets during a [Webpack](https://github.com/element-hq/element-web/blob/247cd8d56d832d006d7dfb919d1042529d712b59/webpack.config.js#L677-L682) build. 3. Use the `index.html` entrypointof the imported assets when you are constructing the WebView or iframe. e.g. using a [relative path in a webapp](https://github.com/element-hq/element-web/blob/247cd8d56d832d006d7dfb919d1042529d712b59/src/models/Call.ts#L680), or on the the Android [WebViewAssetLoader](https://github.com/element-hq/element-x-android/blob/fe5aab6588ecdcf9354a3bfbd9e97c1b31175a8f/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt#L20) -4. Set any of the [embedded-only URL parameters](./url-params.md#embedded-only-parameters) that you need. +4. Set any of the [embedded-only URL parameters](./url_params.md#embedded-only-parameters) that you need. ## Widget vs standalone mode @@ -36,4 +36,4 @@ As a widget, the app only uses the core calling (MatrixRTC) parts. The rest (aut Element Call and the hosting client are connected via the widget API. Element Call detects that it is run as a widget if a widgetId is defined in the url parameters. If `widgetId` is present then Element Call will try to connect to the client via the widget postMessage API using the parameters provided in [Url Format and parameters -](./url-params.md). +](./url_params.md). diff --git a/docs/linking.md b/docs/linking.md index 0abbc73e..1016fffb 100644 --- a/docs/linking.md +++ b/docs/linking.md @@ -1,39 +1,65 @@ -# Developing with linked packages +## Quickstart guide -If you want to make changes to a package that Element Call depends on and see those changes applied in real time, you can create a link to a local copy of the package. Yarn has a command for this (`yarn link`), but it's not recommended to use it as it ends up modifying package.json with details specific to your development environment. +run -Instead, you can use our little 'linker' plugin. Create a file named `.links.yaml` in the Element Call project directory, listing the names and paths of any dependencies you want to link. For example: - -```yaml -matrix-js-sdk: ../path/to/matrix-js-sdk -"@vector-im/compound-web": /home/alice/path/to/compound-web +```bash +./scripts/setup-linking.sh ``` -Then run `yarn install`. +Read the script output: + +``` +Setup complete. +Update: .links.cjs to your liking +Run: 'pnpm links:on' to test your .links.cjs +Run: 'git commit' with links enabled to test the git pre-commit hook. +Run: 'pnpm links:off' to be able to commit again +Run: 'git config --local core.hooksPath ""' to allow committing with linking (not recommended) +Run: 'rm links.cjs' & 'git config --local core.hooksPath ""' to fully revert what this script did +``` + +# Developing with linked packages + +If you want to make changes to a package that Element Call depends on and see those changes applied in real time, you can create a link to a local copy of the package. `pnpm` has a command for this (`pnpm link`), but it's not recommended to use it as it ends up modifying package.json with details specific to your development environment. + +Instead, create a file named `.links.cjs` in the Element Call project directory (or run `./scripts/setup-linking.sh` to create a template), listing the names and paths of any dependencies you want to link. For example: + +```cjs +// Packages to link to local checkouts +module.exports = { + "matrix-js-sdk": "../your/path/matrix-js-sdk", + "matrix-widget-api": "../your/path/matrix-widget-api", +}; +``` + +Then run `pnpm links:on`. (this will activate the pnpm file + run `pnpm install` to setup the linking) ## Hooks -Changes in `.links.yaml` will also update `yarn.lock` when `yarn` is executed. The lockfile will then contain the local +Changes in `.links.cjs` will also update `pnpm-lock.yaml` when `pnpm install` is executed. The lockfile will then contain the local version of the package which would not work on others dev setups or the github CI. -One always needs to run: + +One always needs to remove the pnpm `readPackage` script (the `.pnpmfile.cjs`) and run: ```bash -mv .links.yaml .links.disabled.yaml -yarn +pnpm install ``` before committing a change. -To make it more convenient to work with this linking system we added git hooks for your conviniece. -A `pre-commit` hook will run `mv .links.yaml .links.disabled.yaml`, `yarn` and `git add yarn.lock` if it detects -a `.links.yaml` file and abort the commit. -You will than need to check if the resulting changes are appropriate and commit again. +To make this less of a foot gun we added a git hook. +A `pre-commit` hook will check if linking is currently used. If it detects +a `.pnpmfile.cjs` file it will abort the commit with an explanatory message. +You will than need to run `pnpm links:off` and commit again. -A `post-commit` hook will setup the linking as it was -before if a `.links.disabled.yaml` is present. It runs `mv .links.disabled.yaml .links.yaml` and `yarn`. - -To activate the hooks automatically configure git with +To activate the hooks configure git with (when using the setup script (`./scripts/setup-linking.sh`) this is already done): ```bash -git config --local core.hooksPath .githooks/ +git config --local core.hooksPath .githooks ``` + +This will add the hook path for this repository only to .gihooks. which is a tracked (by git) folder containing the pre-commit hook. + +## Background + +Information, why this approach is used can be found in the [linking concept reasoning](./linking_concept_reasoning.md) document. diff --git a/docs/linking_concept_reasoning.md b/docs/linking_concept_reasoning.md new file mode 100644 index 00000000..7c135a96 --- /dev/null +++ b/docs/linking_concept_reasoning.md @@ -0,0 +1,30 @@ +### Why do we not enable .pnpmfile.cjs by default + +Background: The presence of the `.pnpmfile.cjs` adds a field to the `pnpm-lock.yaml` called: `pnpmfileChecksum`. This field is a checksum of the content of the `.pnpmfile.cjs` file. +`pnpm install --frozen-lockfile` **fails** if there is a `.pnpmfile.cjs` but no `pnpmfileChecksum` or vice versa (or on mismatch). + +_TLDR: running with `--ignore-pnpmfile` will fail if `pnpmfileChecksum` is present._ + +#### `pnpmfileChecksum` + renovate bot + +When the renovate bot creates a PR it runs `pnpm install --ignore-pnpmfile`. This means that the `pnpmfileChecksum` in the lockfile will be **empty**. +This breaks builds that **don't** ignore the `.pnpmfile.cjs`-file. (CI that runs on the renovate PR) +From here we have two possible paths: + +- ignore `.pnpmfile.cjs` in all CI builds CI will also fail if we accidently add it locally. +- fixup the `pnpm-lock.yaml` in the renovate PR to contain the correct `pnpmfileChecksum`. + +Ignoring in all CI builds means that CI will always fail if we enable the linking system. +This is annoying but can be worked around with the git hook we provide that at least lets us know that we are +commiting with enabled linking. +Only if we remember setting it back/disbale linking (or let ourselves remember by the git hook) the CI will work. + +#### Summary + +- We will always run into conflicts with the `pnpmfileChecksum` because in renovate prs it will be empty (`--ignore-pnpmfile`) +- To keep it simple we set `--ignore-pnpmfile` in all of ours CI to see issues immediately. +- The only solution is to never have a `.pnpmfile.cjs` in the repository when pushing. + - This way there will never be a commit with `pnpmfileChecksum` in the lockfile. + - renovate (which uses `--ignore-pnpmfile` which we cannot disable) and other CI will work +- We are able to use the linking system locally if we `cp` this file from the scripts folder into `./` on demand. +- `pnpm links:on` and `pnpm links:off` + `./scripts/setup-linking.sh` will help us with this. diff --git a/docs/self-hosting.md b/docs/self_hosting.md similarity index 99% rename from docs/self-hosting.md rename to docs/self_hosting.md index d6d46421..dc1dd687 100644 --- a/docs/self-hosting.md +++ b/docs/self_hosting.md @@ -237,8 +237,8 @@ source. First, clone and install the package: git clone https://github.com/element-hq/element-call.git cd element-call corepack enable -yarn -yarn build +pnpm install +pnpm build ``` If all went well, you can now find the build output under `dist` as a series of diff --git a/docs/url-params.md b/docs/url_params.md similarity index 62% rename from docs/url-params.md rename to docs/url_params.md index e24e9823..e88e7095 100644 --- a/docs/url-params.md +++ b/docs/url_params.md @@ -4,7 +4,7 @@ There are two formats for Element Call URLs. ## Link for sharing -Requires Element Call to be deployed in [standalone](./embedded-standalone.md) mode. +Requires Element Call to be deployed in [standalone](./embedded_standalone.md) mode. ```text https://element_call.domain/room/# @@ -36,46 +36,45 @@ possible to support encryption. | Package | Deployment | URL | | ------------------------------------ | ----------------------------- | ----------------------------------------------------------------------------- | -| [Full](./embedded-standalone.md) | All | `https://element_call.domain/room` | -| [Embedded](./embedded-standalone.md) | Remote URL | `https://element_call.domain/` n.b. no `/room` part | -| [Embedded](./embedded-standalone.md) | Embedded within messenger app | Platform dependent, but you load the `index.html` file without a `/room` part | +| [Full](./embedded_standalone.md) | All | `https://element_call.domain/room` | +| [Embedded](./embedded_standalone.md) | Remote URL | `https://element_call.domain/` n.b. no `/room` part | +| [Embedded](./embedded_standalone.md) | Embedded within messenger app | Platform dependent, but you load the `index.html` file without a `/room` part | ## Parameters ### Common Parameters -These parameters are relevant to both [widget](./embedded-standalone.md) and [standalone](./embedded-standalone.md) modes: +These parameters are relevant to both [widget](./embedded_standalone.md) and [standalone](./embedded_standalone.md) modes: -| Name | Values | Required for widget | Required for SPA | Description | -| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `intent` | `start_call`, `join_existing`, `start_call_dm`, `join_existing_dm. | No, defaults to `start_call` | No, defaults to `start_call` | The intent is a special url parameter that defines the defaults for all the other parameters. In most cases it should be enough to only set the intent to setup element-call. | -| `allowIceFallback` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Allows use of fallback STUN servers for ICE if the user's homeserver doesn’t provide any. | -| `posthogUserId` | Posthog analytics ID | No | No | Available only with user's consent for sharing telemetry in Element Web. | -| `appPrompt` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Prompts the user to launch the native mobile app upon entering a room, applicable only on Android and iOS, and must be enabled in config. | -| `confineToRoom` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Keeps the user confined to the current call/room. | -| `displayName` | | No | No | Display name used for auto-registration. | -| `enableE2EE` (deprecated) | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Legacy flag to enable end-to-end encryption, not used in the `livekit` branch. | -| `fontScale` | A decimal number such as `0.9` | No, defaults to `1.0` | No, defaults to `1.0` | Factor by which to scale the interface's font size. | -| `fonts` | | No | No | Defines the font(s) used by the interface. Multiple font parameters can be specified: `?font=font-one&font=font-two...`. | -| `header` | `none`, `standard` or `app_bar` | No, defaults to `standard` | No, defaults to `standard` | The style of headers to show. `standard` is the default arrangement, `none` hides the header entirely, and `app_bar` produces a header with a back button like you might see in mobile apps. The callback for the back button is `window.controls.onBackButtonPressed`. | -| `hideScreensharing` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the screen-sharing button. | -| `homeserver` | | Not applicable | No | Homeserver for registering a new (guest) user, configures non-default guest user server when creating a spa link. | -| `lang` | [BCP 47](https://www.rfc-editor.org/info/bcp47) code | No | No | The language the app should use. | -| `password` | | No | No | E2EE password when using a shared secret. (For individual sender keys in embedded mode this is not required.) | -| `perParticipantE2EE` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Enables per participant encryption with Keys exchanged over encrypted matrix room messages. | -| `controlledAudioDevices` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the [global JS controls for audio devices](./controls.md#audio-devices) should be enabled, allowing the list of audio devices to be controlled by the app hosting Element Call. | -| `roomId` | [Matrix Room ID](https://spec.matrix.org/v1.12/appendices/#room-ids) | Yes | No | Anything about what room we're pointed to should be from useRoomIdentifier which parses the path and resolves alias with respect to the default server name, however roomId is an exception as we need the room ID in embedded widget mode, and not the room alias (or even the via params because we are not trying to join it). This is also not validated, where it is in `useRoomIdentifier()`. | -| `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. | -| `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) | -| `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. | -| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. | -| `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. | -| `autoLeaveWhenOthersLeft` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. | -| `waitForCallPickup` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | When sending a notification, show UI that the app is awaiting an answer, play a dial tone, and (in widget mode) auto-close the widget once the notification expires. | +| Name | Values | Required for widget | Required for SPA | Description | +| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `intent` | `start_call`, `join_existing`, `start_call_voice`, `join_existing_voice`, `start_call_dm`, `join_existing_dm`, `start_call_dm_voice`, or `join_existing_dm_voice`. | No, defaults to `start_call` | No, defaults to `start_call` | The intent is a special url parameter that defines the defaults for all the other parameters. In most cases it should be enough to only set the intent to setup element-call. | +| `allowIceFallback` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Allows use of fallback STUN servers for ICE if the user's homeserver doesn’t provide any. | +| `posthogUserId` | Posthog analytics ID | No | No | Available only with user's consent for sharing telemetry in Element Web. | +| `confineToRoom` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Keeps the user confined to the current call/room. | +| `displayName` | | No | No | Display name used for auto-registration. | +| `enableE2EE` (deprecated) | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Legacy flag to enable end-to-end encryption, not used in the `livekit` branch. | +| `fontScale` | A decimal number such as `0.9` | No, defaults to `1.0` | No, defaults to `1.0` | Factor by which to scale the interface's font size. | +| `fonts` | | No | No | Defines the font(s) used by the interface. Multiple font parameters can be specified: `?font=font-one&font=font-two...`. | +| `header` | `none`, `standard` or `app_bar` | No, defaults to `standard` | No, defaults to `standard` | The style of headers to show. `standard` is the default arrangement, `none` hides the header entirely, and `app_bar` produces a header with a back button like you might see in mobile apps. The callback for the back button is `window.controls.onBackButtonPressed`. | +| `hideScreensharing` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the screen-sharing button. | +| `homeserver` | | Not applicable | No | Homeserver for registering a new (guest) user, configures non-default guest user server when creating a spa link. | +| `lang` | [BCP 47](https://www.rfc-editor.org/info/bcp47) code | No | No | The language the app should use. | +| `password` | | No | No | E2EE password when using a shared secret. (For individual sender keys in embedded mode this is not required.) | +| `perParticipantE2EE` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Enables per participant encryption with Keys exchanged over encrypted matrix room messages. | +| `controlledAudioDevices` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the [global JS controls for audio devices](./controls.md#audio-devices) should be enabled, allowing the list of audio devices to be controlled by the app hosting Element Call. | +| `roomId` | [Matrix Room ID](https://spec.matrix.org/v1.12/appendices/#room-ids) | Yes | No | Anything about what room we're pointed to should be from useRoomIdentifier which parses the path and resolves alias with respect to the default server name, however roomId is an exception as we need the room ID in embedded widget mode, and not the room alias (or even the via params because we are not trying to join it). This is also not validated, where it is in `useRoomIdentifier()`. | +| `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. | +| `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) | +| `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. | +| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. | +| `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. | +| `autoLeaveWhenOthersLeft` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. | +| `waitForCallPickup` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | When sending a notification, show UI that the app is awaiting an answer, play a dial tone, and (in widget mode) auto-close the widget once the notification expires. | ### Widget-only parameters -These parameters are only supported in [widget](./embedded-standalone.md) mode. +These parameters are only supported in [widget](./embedded_standalone.md) mode. | Name | Values | Required | Description | | --------------- | ----------------------------------------------------------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -90,7 +89,7 @@ These parameters are only supported in [widget](./embedded-standalone.md) mode. ### Embedded-only parameters -These parameters are only supported in the [embedded](./embedded-standalone.md) package of Element Call and will be ignored in the [full](./embedded-standalone.md) package. +These parameters are only supported in the [embedded](./embedded_standalone.md) package of Element Call and will be ignored in the [full](./embedded_standalone.md) package. | Name | Values | Required | Description | | -------------------- | -------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- | diff --git a/embedded/android/publish_android_package.sh b/embedded/android/publish_android_package.sh index 8c310c9b..31693317 100755 --- a/embedded/android/publish_android_package.sh +++ b/embedded/android/publish_android_package.sh @@ -11,7 +11,7 @@ pushd $CURRENT_DIR > /dev/null function build_assets() { echo "Generating Element Call assets..." pushd ../.. > /dev/null - yarn build + pnpm build popd > /dev/null } @@ -26,7 +26,7 @@ function copy_assets() { } getopts :sh opt -case $opt in +case $opt in s) SKIP=1 ;; @@ -41,7 +41,7 @@ if [ ! $SKIP ]; then echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then build_assets - else + else echo "Using existing assets from ../../dist" fi copy_assets @@ -56,4 +56,4 @@ echo "Publishing the Android project" ./gradlew publishAndReleaseToMavenCentral --no-daemon -popd > /dev/null \ No newline at end of file +popd > /dev/null diff --git a/index.html b/index.html index f17c73c0..f3177a48 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@