openvidu-dashboard: ./dashboard.sh dev runs the backend and frontend against openvidu-local-deployment

dashboard-ce/tools/dev.sh checks the configuration and MongoDB, then starts both development servers, stopped
together. The backend reads dashboard-ce/backend/dev.env (local deployment defaults), under a git-ignored .env and
the environment; DASHBOARD_DEV_PORT and DASHBOARD_DEV_BACKEND_PORT move the servers. The demo shares the process
helpers, now in dev-lib.sh, and runs every server by directory so Ctrl+C prints no pnpm errors.
chore/update-openvidu-actions-1.0.25
juancarmore 2026-10-26 19:00:12 +01:00
parent e4f1ef6e7f
commit 2390f8753b
18 changed files with 336 additions and 79 deletions

View File

@ -14,3 +14,7 @@ dashboard-ce/tools
# Their manifests keep the workspace consistent with the lockfile. # Their manifests keep the workspace consistent with the lockfile.
!dashboard-ce/tools/*/package.json !dashboard-ce/tools/*/package.json
PLAN.md PLAN.md
# Development settings, personal ones included, never reach the image.
**/.env
**/.env.*
**/dev.env

View File

@ -49,7 +49,8 @@ sources through the `source` export condition, so type checking, linting and tes
Everything runs through `./dashboard.sh` (what CI calls; `help` lists every command, any accepts `--skip-install`): Everything runs through `./dashboard.sh` (what CI calls; `help` lists every command, any accepts `--skip-install`):
`check` (lint, format check, typecheck, spec validation, unit tests), `test-integration` (Docker), `e2e`, `check` (lint, format check, typecheck, spec validation, unit tests), `test-integration` (Docker), `e2e`,
`contract-check <openvidu-livekit>`, `build-image ce`, `smoke-image ce`, and `demo ce`: a local demo on generated data `contract-check <openvidu-livekit>`, `build-image ce`, `smoke-image ce`, `dev` (backend and frontend development
servers against openvidu-local-deployment; README "Development") and `demo ce`: a local demo on generated data
(http://localhost:4200, `admin` / `admin`; MongoDB container `openvidu-dashboard-demo-mongo` on port 27018; (http://localhost:4200, `admin` / `admin`; MongoDB container `openvidu-dashboard-demo-mongo` on port 27018;
`DASHBOARD_DEMO_KEEP_DATA=true` reuses the data of a running container). `DASHBOARD_DEMO_KEEP_DATA=true` reuses the data of a running container).

View File

@ -36,7 +36,7 @@ All tasks run through `./dashboard.sh`:
```bash ```bash
./dashboard.sh install # install dependencies ./dashboard.sh install # install dependencies
./dashboard.sh check # lint + format check + type check + spec validation + unit tests ./dashboard.sh check # lint + format check + type check + spec validation + unit tests
./dashboard.sh dev # frontend dev server, proxying /api to a backend on port 5000 ./dashboard.sh dev # backend and frontend dev servers against openvidu-local-deployment
./dashboard.sh demo ce # local demo on generated data: http://localhost:4200, admin / admin ./dashboard.sh demo ce # local demo on generated data: http://localhost:4200, admin / admin
./dashboard.sh test-integration # integration tests against MongoDB (Docker required) ./dashboard.sh test-integration # integration tests against MongoDB (Docker required)
./dashboard.sh e2e # build the application and run the Playwright tests ./dashboard.sh e2e # build the application and run the Playwright tests
@ -46,6 +46,23 @@ All tasks run through `./dashboard.sh`:
./dashboard.sh help # list every command ./dashboard.sh help # list every command
``` ```
## Development
`./dashboard.sh dev` runs the backend and frontend development servers against the MongoDB of an
[openvidu-local-deployment](https://github.com/OpenVidu/openvidu-local-deployment) running on this machine, both
reloading on changes: http://localhost:4200, `admin` / `admin`. Ctrl+C stops both. Without a deployment,
`./dashboard.sh demo ce` runs the same servers on generated data instead.
- Before starting, it checks the configuration and that MongoDB answers, and says what to do when it does not.
- The backend reads `dashboard-ce/backend/dev.env`, the defaults for the local deployment. A git-ignored
`dashboard-ce/backend/.env` overrides them, and the environment overrides both, for example
`DATABASE_URL` for another MongoDB or `LOG_LEVEL=debug`. The deployment's replica set advertises its member
as `mongo:27017`, which only Docker resolves, so a URL from the host needs `directConnection=true`.
- `DASHBOARD_DEV_PORT` (default 4200) and `DASHBOARD_DEV_BACKEND_PORT` (default 5000) move the servers, for
example off port 5000 where macOS runs AirPlay.
- The deployment needs a 3.10 OpenVidu server: data appears once it writes the analytics database, and an
older writer schema stops the check.
## Container image ## Container image
`openvidu/openvidu-dashboard`, built from `dashboard-ce/docker/Dockerfile` on `node:24-trixie-slim` `openvidu/openvidu-dashboard`, built from `dashboard-ce/docker/Dockerfile` on `node:24-trixie-slim`

View File

@ -45,6 +45,10 @@ Behaviour is specified in `openspec/specs/*-api`, `api-conventions`, `auth`, `st
`entityIdKind()` from typings. `entityIdKind()` from typings.
- Configuration variables are new `DASHBOARD_*`, or `DATABASE_*` for database connection settings; legacy names keep - Configuration variables are new `DASHBOARD_*`, or `DATABASE_*` for database connection settings; legacy names keep
their 3.9 meaning (`src/config/variables.ts`, unit-tested). The README lists them all. their 3.9 meaning (`src/config/variables.ts`, unit-tested). The README lists them all.
- `scripts/dev.ts` (exported as `@openvidu-dashboard/backend/dev`) serves `./dashboard.sh dev`: `loadDevEnv()` (the
environment, then `.env`, then `dev.env`; `scripts/dev-preload.ts` for `tsx watch --import`) and
`checkDevConfig()` (`scripts/dev-check.ts`). `dev.env` holds the openvidu-local-deployment defaults; never give
`src/` defaults for required variables, since a deployment must fail when they are missing.
## Rules ## Rules

View File

@ -0,0 +1,7 @@
# Defaults of ./dashboard.sh dev, for openvidu-local-deployment running on this machine. Override any of them in
# .env next to this file (git-ignored) or in the environment.
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin
# The deployment's replica set advertises its member as mongo:27017, a name only Docker resolves.
DATABASE_URL=mongodb://mongoadmin:mongoadmin@localhost:27017/?directConnection=true
DASHBOARD_BASE_PATH=/

View File

@ -13,14 +13,15 @@
"default": "./dist/index.js" "default": "./dist/index.js"
}, },
"./testing": "./test/support/index.ts", "./testing": "./test/support/index.ts",
"./testing/global-mongo": "./test/support/global-mongo.ts" "./testing/global-mongo": "./test/support/global-mongo.ts",
"./dev": "./scripts/dev.ts"
}, },
"files": [ "files": [
"dist" "dist"
], ],
"scripts": { "scripts": {
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"dev": "tsx watch --conditions=source src/server.ts", "dev": "tsx watch --conditions=source --import ./scripts/dev-preload.ts src/server.ts",
"typecheck": "tsc --noEmit -p tsconfig.json", "typecheck": "tsc --noEmit -p tsconfig.json",
"test": "vitest run --project unit", "test": "vitest run --project unit",
"test:integration": "vitest run --project integration --project integration-plans", "test:integration": "vitest run --project integration --project integration-plans",

View File

@ -0,0 +1,6 @@
/** Run by `./dashboard.sh dev` before it starts the development servers. */
import { checkDevConfig } from './dev.js';
if (!(await checkDevConfig())) {
process.exitCode = 1;
}

View File

@ -0,0 +1,4 @@
/** Preloaded by the backend development scripts: the environment, then `.env` (git-ignored), then `dev.env`. */
import { DEV_ENV_FILE, loadDevEnv } from './dev.js';
loadDevEnv(['.env', DEV_ENV_FILE]);

View File

@ -0,0 +1,110 @@
/**
* Configuration of `./dashboard.sh dev`, exported as `@openvidu-dashboard/backend/dev` for the development scripts of
* extending workspaces: the variable files of the backend development server and the check that runs before it.
*/
import { fileURLToPath } from 'node:url';
import { MongoClient } from 'mongodb';
import { WriterSchemaStatus } from '@openvidu-dashboard/typings';
import { applyEnvFile, loadConfigFile } from '../src/config/config-file.js';
import { type DashboardConfig, parseConfig } from '../src/config/variables.js';
import { mongoClientOptions, resolveMongoUrl } from '../src/mongo/mongo-client.js';
import { olderSchemaMessage, readSchemaStatus } from '../src/schema/schema-status.js';
/** The defaults for openvidu-local-deployment running on this machine. */
export const DEV_ENV_FILE = fileURLToPath(new URL('../dev.env', import.meta.url));
const MONGO_HINT =
'Start openvidu-local-deployment, set DATABASE_URL in the .env of the backend, or run ./dashboard.sh demo for ' +
'generated data.';
/**
* Loads the files that exist, in order, into `env`: a variable keeps the first value it gets, so the environment wins
* over every file and each file over the ones after it.
*
* @throws Error when a file cannot be read.
*/
export function loadDevEnv(files: readonly string[], env: NodeJS.ProcessEnv = process.env): void {
for (const file of files) {
const result = applyEnvFile(file, env);
if (result.kind === 'unreadable') {
throw new Error(`Cannot read ${file}: ${result.reason}`);
}
}
}
/**
* Checks the configuration in `env` and that its MongoDB answers with a schema this dashboard supports, printing the
* problem or what the backend will use.
*
* @returns Whether the backend can start.
*/
export async function checkDevConfig(env: NodeJS.ProcessEnv = process.env): Promise<boolean> {
const problem = await findProblem(env);
if (problem !== undefined) {
process.stderr.write(`${problem}\n`);
}
return problem === undefined;
}
async function findProblem(env: NodeJS.ProcessEnv): Promise<string | undefined> {
const file = loadConfigFile(env);
if (file.kind === 'unreadable') {
return `Cannot read ${file.path} (DASHBOARD_CONFIG_PATH): ${file.reason}`;
}
const parsed = parseConfig(env);
if (parsed.kind === 'mongo-disabled') {
return 'MONGO_ENABLED is false: the dashboard stops at startup';
}
if (parsed.kind === 'invalid') {
return parsed.errors.map((error) => `Invalid configuration: ${error}`).join('\n');
}
return findMongoProblem(parsed.config);
}
async function findMongoProblem(config: DashboardConfig): Promise<string | undefined> {
const url = resolveMongoUrl(config.database);
if (url.kind === 'missing') {
return `Define DATABASE_URL, or ${url.variables.join(', ')}`;
}
const redacted = url.url.replace(/\/\/([^:@/]+):[^@/]*@/, '//$1:***@');
let client: MongoClient;
try {
client = new MongoClient(url.url, { ...mongoClientOptions(config.database), serverSelectionTimeoutMS: 3_000 });
} catch (error) {
return `Cannot use the MongoDB settings: ${errorMessage(error)}`;
}
try {
const schema = await readSchemaStatus(client.db(config.database.name));
if (schema.status === WriterSchemaStatus.OLDER && schema.writer !== undefined) {
return `${olderSchemaMessage(schema.writer)} (pull the latest images of the deployment)`;
}
} catch (error) {
return `MongoDB does not answer at ${redacted}: ${errorMessage(error)}\n${MONGO_HINT}`;
} finally {
await client.close();
}
process.stdout.write(`User ${config.admin.username}; MongoDB ${redacted}, database ${config.database.name}\n`);
return undefined;
}
function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}

View File

@ -14,10 +14,11 @@ export type ConfigFileResult =
export function loadConfigFile(env: NodeJS.ProcessEnv): ConfigFileResult { export function loadConfigFile(env: NodeJS.ProcessEnv): ConfigFileResult {
const path = env.DASHBOARD_CONFIG_PATH?.trim(); const path = env.DASHBOARD_CONFIG_PATH?.trim();
if (!path) { return path ? applyEnvFile(path, env) : { kind: 'none' };
return { kind: 'none' }; }
}
/** Loads the `KEY=value` lines of `path` into `env`; variables already set in `env` keep their value. */
export function applyEnvFile(path: string, env: NodeJS.ProcessEnv): Exclude<ConfigFileResult, { kind: 'none' }> {
if (!existsSync(path)) { if (!existsSync(path)) {
return { kind: 'missing', path }; return { kind: 'missing', path };
} }

View File

@ -0,0 +1,46 @@
import { mkdtempSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { describe, expect, it } from 'vitest';
import { parseConfig } from '../../src/config/variables.js';
import { DEV_ENV_FILE, loadDevEnv } from '../../scripts/dev.js';
describe('development variables', () => {
function file(content: string): string {
const path = join(mkdtempSync(join(tmpdir(), 'dashboard-dev-')), '.env');
writeFileSync(path, content);
return path;
}
it('keeps the environment over the first file and that file over the next one', () => {
const env: NodeJS.ProcessEnv = { ADMIN_PASSWORD: 'from-env' };
loadDevEnv(
[file('ADMIN_PASSWORD=from-local\nLOG_LEVEL=debug\n'), file('LOG_LEVEL=warn\nSERVER_PORT=6000\n')],
env
);
expect(env).toEqual({ ADMIN_PASSWORD: 'from-env', LOG_LEVEL: 'debug', SERVER_PORT: '6000' });
});
it('skips a file that does not exist', () => {
const env: NodeJS.ProcessEnv = {};
loadDevEnv(['/nonexistent/.env'], env);
expect(env).toEqual({});
});
it('defaults to a valid configuration for the local deployment', () => {
const env: NodeJS.ProcessEnv = {};
loadDevEnv([DEV_ENV_FILE], env);
const parsed = parseConfig(env);
expect(parsed.kind).toBe('config');
expect(parsed.kind === 'config' && parsed.config.admin.username).toBe('admin');
expect(env.DATABASE_URL).toBe('mongodb://mongoadmin:mongoadmin@localhost:27017/?directConnection=true');
});
});

View File

@ -5,5 +5,5 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"types": ["node"] "types": ["node"]
}, },
"include": ["src", "test", "vitest.config.ts"] "include": ["src", "test", "scripts", "vitest.config.ts"]
} }

View File

@ -1,60 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Shared parts of the local demos, sourced by dashboard-ce/tools/demo.sh and by the demos of workspaces that extend # Shared parts of the local demos, sourced by dashboard-ce/tools/demo.sh and by the demos of workspaces that extend
# these packages: a MongoDB replica set (a container, or DASHBOARD_DEMO_MONGO_URI), 30 days of generated data kept live, # these packages: a MongoDB replica set (a container, or DASHBOARD_DEMO_MONGO_URI), 30 days of generated data kept live,
# and the backend and frontend development servers. The caller sets DATABASE and STATS_MODE and runs from the root of # and the backend and frontend development servers of dev-lib.sh. The caller sets DATABASE and STATS_MODE and runs
# its workspace. # from the root of its workspace.
# DASHBOARD_DEMO_MONGO_URI MongoDB to use instead of the container # DASHBOARD_DEMO_MONGO_URI MongoDB to use instead of the container
# DASHBOARD_DEMO_MONGO_PORT host port of the container (default 27018) # DASHBOARD_DEMO_MONGO_PORT host port of the container (default 27018)
# DASHBOARD_DEMO_KEEP_DATA true reuses the demo database instead of generating it again # DASHBOARD_DEMO_KEEP_DATA true reuses the demo database instead of generating it again
TOOLS_DIR="$(dirname "${BASH_SOURCE[0]}")"
# shellcheck source=dashboard-ce/tools/dev-lib.sh
source "$TOOLS_DIR/dev-lib.sh"
MONGO_IMAGE="${DASHBOARD_TEST_MONGO_IMAGE:-openvidu/mongodb:8.0.29-r1}" MONGO_IMAGE="${DASHBOARD_TEST_MONGO_IMAGE:-openvidu/mongodb:8.0.29-r1}"
MONGO_CONTAINER=openvidu-dashboard-demo-mongo MONGO_CONTAINER=openvidu-dashboard-demo-mongo
MONGO_PORT="${DASHBOARD_DEMO_MONGO_PORT:-27018}" MONGO_PORT="${DASHBOARD_DEMO_MONGO_PORT:-27018}"
# The frontend development servers proxy /api to port 5000 (proxy.conf.json); another backend gets its own proxy file.
DEFAULT_BACKEND_PORT=5000
WORK_DIR="$(mktemp -d)"
PIDS=()
kill_tree() {
local child
for child in $(pgrep -P "$1" || true); do
kill_tree "$child"
done
kill "$1" 2>/dev/null || true
}
cleanup() {
for pid in "${PIDS[@]}"; do
kill_tree "$pid"
done
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
# require_free_ports <port>...: exits when one is in use.
require_free_ports() {
local port
for port in "$@"; do
if (exec 3<>"/dev/tcp/127.0.0.1/$port") 2>/dev/null; then
echo "Port $port is in use" >&2
exit 1
fi
done
}
wait_for() {
for _ in $(seq 1 120); do
curl -sf -o /dev/null "$1" && return 0
sleep 1
done
echo "$1 did not answer" >&2
exit 1
}
start_mongo() { start_mongo() {
if [ "$(docker inspect -f '{{.State.Running}}' "$MONGO_CONTAINER" 2>/dev/null)" != true ]; then if [ "$(docker inspect -f '{{.State.Running}}' "$MONGO_CONTAINER" 2>/dev/null)" != true ]; then
@ -92,34 +52,22 @@ prepare_data() {
if [ "${DASHBOARD_DEMO_KEEP_DATA:-false}" != true ]; then if [ "${DASHBOARD_DEMO_KEEP_DATA:-false}" != true ]; then
echo "Generating $DATABASE (scenario S, 30 days, $STATS_MODE stats)" echo "Generating $DATABASE (scenario S, 30 days, $STATS_MODE stats)"
pnpm --silent --filter @openvidu-dashboard/data-generator run generate --uri "$MONGO_URI" --db "$DATABASE" \ pnpm --silent --dir "$TOOLS_DIR/data-generator" run generate --uri "$MONGO_URI" --db "$DATABASE" \
--scenario S --days 30 --stats-mode "$STATS_MODE" --drop --five-minute-rollups --node-rollups --room-sums \ --scenario S --days 30 --stats-mode "$STATS_MODE" --drop --five-minute-rollups --node-rollups --room-sums \
--active-window 60 --min-active-rooms 10 | tail -2 --active-window 60 --min-active-rooms 10 | tail -2
fi fi
pnpm --silent --filter @openvidu-dashboard/data-generator run keep-alive --uri "$MONGO_URI" --db "$DATABASE" & pnpm --silent --dir "$TOOLS_DIR/data-generator" run keep-alive --uri "$MONGO_URI" --db "$DATABASE" &
PIDS+=("$!") PIDS+=("$!")
} }
# start_backend <package> <port> [VAR=value...]: the backend development server on the demo database, in the background. # start_backend <package directory> <port> [VAR=value...]: the backend development server on the demo database, in
# the background.
start_backend() { start_backend() {
local package="$1" local directory="$1"
local port="$2" local port="$2"
shift 2 shift 2
env SERVER_PORT="$port" DASHBOARD_BASE_PATH=/ ADMIN_USERNAME=admin ADMIN_PASSWORD=admin DATABASE_URL="$MONGO_URI" \ start_dev_backend "$directory" "$port" DASHBOARD_BASE_PATH=/ ADMIN_USERNAME=admin ADMIN_PASSWORD=admin \
DATABASE_NAME="$DATABASE" "$@" pnpm --silent --filter "$package" run dev & DATABASE_URL="$MONGO_URI" DATABASE_NAME="$DATABASE" "$@"
PIDS+=("$!")
}
# start_frontend <package> <port> <backend port>: the frontend development server proxying /api to that backend.
start_frontend() {
local proxy=()
if [ "$3" != "$DEFAULT_BACKEND_PORT" ]; then
printf '{ "/api": { "target": "http://localhost:%s", "secure": false } }\n' "$3" >"$WORK_DIR/proxy-$2.json"
proxy=(--proxy-config "$WORK_DIR/proxy-$2.json")
fi
pnpm --silent --filter "$1" run dev --port "$2" "${proxy[@]}"
} }

View File

@ -22,7 +22,7 @@ source dashboard-ce/tools/demo-lib.sh
require_free_ports "$DEFAULT_BACKEND_PORT" "$FRONTEND_PORT" require_free_ports "$DEFAULT_BACKEND_PORT" "$FRONTEND_PORT"
prepare_data prepare_data
start_backend @openvidu-dashboard/backend "$DEFAULT_BACKEND_PORT" start_backend dashboard-ce/backend "$DEFAULT_BACKEND_PORT"
wait_for "http://127.0.0.1:$DEFAULT_BACKEND_PORT/api/healthcheck" wait_for "http://127.0.0.1:$DEFAULT_BACKEND_PORT/api/healthcheck"
echo "OpenVidu Dashboard ce demo: http://localhost:$FRONTEND_PORT (admin / admin)" echo "OpenVidu Dashboard ce demo: http://localhost:$FRONTEND_PORT (admin / admin)"
start_frontend @openvidu-dashboard/frontend "$FRONTEND_PORT" "$DEFAULT_BACKEND_PORT" start_frontend dashboard-ce/frontend "$FRONTEND_PORT" "$DEFAULT_BACKEND_PORT"

View File

@ -0,0 +1,80 @@
#!/usr/bin/env bash
# Development servers of the local runs, sourced by dev.sh and demo-lib.sh here and by the scripts of workspaces that
# extend these packages: the backend and frontend development servers in one session, stopped together. The caller
# runs from the root of its workspace.
# The frontend development servers proxy /api to port 5000 (proxy.conf.json); another backend gets its own proxy file.
DEFAULT_BACKEND_PORT=5000
WORK_DIR="$(mktemp -d)"
PIDS=()
kill_tree() {
local child
for child in $(pgrep -P "$1" || true); do
kill_tree "$child"
done
kill "$1" 2>/dev/null || true
}
cleanup() {
for pid in "${PIDS[@]}"; do
kill_tree "$pid"
done
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
# require_free_ports <port>...: exits when one is in use.
require_free_ports() {
local port
for port in "$@"; do
if (exec 3<>"/dev/tcp/127.0.0.1/$port") 2>/dev/null; then
echo "Port $port is in use" >&2
exit 1
fi
done
}
wait_for() {
for _ in $(seq 1 120); do
curl -sf -o /dev/null "$1" && return 0
sleep 1
done
echo "$1 did not answer" >&2
exit 1
}
# check_dev_backend <package directory>: exits when the backend there cannot start, with its scripts/dev-check.ts
# and the variables of its scripts/dev-preload.ts.
check_dev_backend() {
pnpm --silent --dir "$1" exec tsx --conditions=source --import ./scripts/dev-preload.ts scripts/dev-check.ts
}
# start_dev_backend <package directory> <port> [VAR=value...]: the backend development server in the background. The
# variables win over the files of its scripts/dev-preload.ts.
start_dev_backend() {
local directory="$1"
local port="$2"
shift 2
env SERVER_PORT="$port" "$@" pnpm --silent --dir "$directory" run dev &
PIDS+=("$!")
}
# start_frontend <package directory> <port> <backend port>: the frontend development server proxying /api to that
# backend.
start_frontend() {
local proxy=()
if [ "$3" != "$DEFAULT_BACKEND_PORT" ]; then
printf '{ "/api": { "target": "http://localhost:%s", "secure": false } }\n' "$3" >"$WORK_DIR/proxy-$2.json"
proxy=(--proxy-config "$WORK_DIR/proxy-$2.json")
fi
pnpm --silent --dir "$1" run dev --port "$2" "${proxy[@]}"
}

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Local development against openvidu-local-deployment (see dev-lib.sh): the backend and frontend development servers,
# both reloading on changes. The backend reads dashboard-ce/backend/dev.env, overridden by dashboard-ce/backend/.env
# (git-ignored) and by the environment.
# Usage: dashboard-ce/tools/dev.sh
# DASHBOARD_DEV_PORT port of the frontend development server (default 4200)
# DASHBOARD_DEV_BACKEND_PORT port of the backend development server (default 5000)
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
FRONTEND_PORT="${DASHBOARD_DEV_PORT:-4200}"
BACKEND_PORT="${DASHBOARD_DEV_BACKEND_PORT:-5000}"
# shellcheck source=dashboard-ce/tools/dev-lib.sh
source dashboard-ce/tools/dev-lib.sh
require_free_ports "$BACKEND_PORT" "$FRONTEND_PORT"
check_dev_backend dashboard-ce/backend
start_dev_backend dashboard-ce/backend "$BACKEND_PORT"
wait_for "http://127.0.0.1:$BACKEND_PORT/api/healthcheck"
echo "OpenVidu Dashboard: http://localhost:$FRONTEND_PORT"
start_frontend dashboard-ce/frontend "$FRONTEND_PORT" "$BACKEND_PORT"

View File

@ -35,7 +35,9 @@ Commands:
format-check Prettier --check format-check Prettier --check
typecheck tsc --noEmit in every package that defines it typecheck tsc --noEmit in every package that defines it
build Build every package in dependency order build Build every package in dependency order
dev Frontend dev server on http://localhost:4200, proxying /api to the backend on port 5000 dev Backend and frontend dev servers against openvidu-local-deployment: http://localhost:4200, backend
on port 5000 (DASHBOARD_DEV_PORT, DASHBOARD_DEV_BACKEND_PORT); defaults in
dashboard-ce/backend/dev.env, overridden by dashboard-ce/backend/.env and the environment
demo [ce] Local demo on generated data: MongoDB (a container, or DASHBOARD_DEMO_MONGO_URI), 30 days of data demo [ce] Local demo on generated data: MongoDB (a container, or DASHBOARD_DEMO_MONGO_URI), 30 days of data
kept live, backend and frontend dev servers on http://localhost:4200 (admin / admin) kept live, backend and frontend dev servers on http://localhost:4200 (admin / admin)
test Unit tests (Vitest) of every package that defines them (same as test-unit) test Unit tests (Vitest) of every package that defines them (same as test-unit)
@ -141,7 +143,11 @@ case "$COMMAND" in
format-check) run format:check ;; format-check) run format:check ;;
typecheck) run typecheck ;; typecheck) run typecheck ;;
build) run build ;; build) run build ;;
dev) run dev ;; dev)
require_pnpm
ensure_installed
dashboard-ce/tools/dev.sh
;;
demo) demo)
require_ce require_ce
require_pnpm require_pnpm

View File

@ -14,7 +14,6 @@
"format:check": "prettier --check .", "format:check": "prettier --check .",
"typecheck": "pnpm -r run typecheck", "typecheck": "pnpm -r run typecheck",
"build": "pnpm -r run build", "build": "pnpm -r run build",
"dev": "pnpm --filter @openvidu-dashboard/frontend run dev",
"test:unit": "pnpm -r --if-present run test", "test:unit": "pnpm -r --if-present run test",
"test:integration": "pnpm -r --if-present run test:integration", "test:integration": "pnpm -r --if-present run test:integration",
"e2e": "pnpm --filter \"@openvidu-dashboard/e2e^...\" run build && pnpm --filter @openvidu-dashboard/e2e run e2e", "e2e": "pnpm --filter \"@openvidu-dashboard/e2e^...\" run build && pnpm --filter @openvidu-dashboard/e2e run e2e",