Merge branch 'develop'

This commit is contained in:
Etherpad Release Bot 2025-10-10 10:36:43 +00:00
commit 868a03bb8e
58 changed files with 2625 additions and 2059 deletions

View file

@ -12,8 +12,11 @@ on:
permissions:
contents: read
jobs:
withoutpluginsLinux:
env:
PNPM_HOME: ~/.pnpm-store
# run on pushes to any branch
# run on PRs from external forks
if: |
@ -24,33 +27,27 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [20, 22, 24]
node: [">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"]
steps:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
~/.local/share/gnpm
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.3
@ -59,21 +56,23 @@ jobs:
version: 1.0
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm i --frozen-lockfile --runtimeVersion="${{ matrix.node }}"
- name: Install admin ui
working-directory: admin
run: pnpm install
run: gnpm install --runtimeVersion="${{ matrix.node }}"
- name: Build admin ui
working-directory: admin
run: pnpm build
run: gnpm build --runtimeVersion="${{ matrix.node }}"
-
name: Run the backend tests
run: pnpm test
run: gnpm test --runtimeVersion="${{ matrix.node }}"
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest
run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}"
withpluginsLinux:
env:
PNPM_HOME: ~/.pnpm-store
# run on pushes to any branch
# run on PRs from external forks
if: |
@ -84,33 +83,27 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [20, 22, 24]
node: [">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"]
steps:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
~/.local/share/gnpm
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.3
@ -119,17 +112,14 @@ jobs:
version: 1.0
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
- name: Install admin ui
working-directory: admin
run: pnpm install
run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}"
- name: Build admin ui
working-directory: admin
run: pnpm build
run: gnpm build --runtimeVersion="${{ matrix.node }}"
-
name: Install Etherpad plugins
run: >
pnpm install --workspace-root
gnpm install --workspace-root
ep_align
ep_author_hover
ep_cursortrace
@ -141,57 +131,53 @@ jobs:
ep_set_title_on_pad
ep_spellcheck
ep_subscript_and_superscript
ep_table_of_contents
ep_table_of_contents --runtimeVersion="${{ matrix.node }}"
-
name: Run the backend tests
run: pnpm test
run: gnpm test --runtimeVersion="${{ matrix.node }}"
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest
run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}"
withoutpluginsWindows:
env:
PNPM_HOME: ~\\.pnpm-store
# run on pushes to any branch
# run on PRs from external forks
if: |
(github.event_name != 'pull_request')
|| (github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id)
strategy:
fail-fast: false
matrix:
node: [">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"]
name: Windows without plugins
runs-on: windows-latest
steps:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
C:\gnpm\
C:\Users\runneradmin\AppData\Roaming\gnpm\
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installOnWindows.bat
- name: Install admin ui
working-directory: admin
run: pnpm install
run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}"
- name: Build admin ui
working-directory: admin
run: pnpm build
run: gnpm build --runtimeVersion="${{ matrix.node }}"
-
name: Fix up the settings.json
run: |
@ -200,17 +186,23 @@ jobs:
-
name: Run the backend tests
working-directory: src
run: pnpm test
run: gnpm test --runtimeVersion="${{ matrix.node }}"
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest
run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}"
withpluginsWindows:
env:
PNPM_HOME: ~\\.pnpm-store
# run on pushes to any branch
# run on PRs from external forks
if: |
(github.event_name != 'pull_request')
|| (github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id)
strategy:
fail-fast: false
matrix:
node: [">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"]
name: Windows with Plugins
runs-on: windows-latest
@ -218,40 +210,32 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 22
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
C:\gnpm\
C:\Users\runneradmin\AppData\Roaming\gnpm\
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
- name: Install admin ui
working-directory: admin
run: pnpm install
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
- name: Install dependencies
run: gnpm install --runtimeVersion="${{ matrix.node }}"
- name: Build admin ui
working-directory: admin
run: pnpm build
run: gnpm build --runtimeVersion="${{ matrix.node }}"
-
name: Install Etherpad plugins
# The --legacy-peer-deps flag is required to work around a bug in npm
# v7: https://github.com/npm/cli/issues/2199
run: >
pnpm install --workspace-root
gnpm install --workspace-root
ep_align
ep_author_hover
ep_cursortrace
@ -263,7 +247,7 @@ jobs:
ep_set_title_on_pad
ep_spellcheck
ep_subscript_and_superscript
ep_table_of_contents
ep_table_of_contents --runtimeVersion="${{ matrix.node }}"
# Etherpad core dependencies must be installed after installing the
# plugin's dependencies, otherwise npm will try to hoist common
# dependencies by removing them from src/node_modules and installing them
@ -275,7 +259,7 @@ jobs:
# rules.
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installOnWindows.bat
run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}"
-
name: Fix up the settings.json
run: |
@ -284,7 +268,7 @@ jobs:
-
name: Run the backend tests
working-directory: src
run: pnpm test
run: gnpm test --runtimeVersion="${{ matrix.node }}"
- name: Run the new vitest tests
working-directory: src
run: pnpm run test:vitest
run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}"

View file

@ -33,31 +33,29 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
- uses: actions/cache@v4
name: Setup gnpm cache
if: always()
with:
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
- name: Setup Pages
uses: actions/configure-pages@v5
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
- name: Install dependencies
run: pnpm install
run: gnpm install
- name: Build app
working-directory: doc
run: pnpm run docs:build
run: gnpm run docs:build
env:
COMMIT_REF: ${{ github.sha }}
- name: Upload artifact

View file

@ -37,10 +37,10 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
-
name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
-
name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v4
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4

View file

@ -1,4 +1,4 @@
name: Docker
name: "Docker"
on:
pull_request:
paths-ignore:
@ -18,6 +18,8 @@ permissions:
jobs:
docker:
runs-on: ubuntu-latest
env:
PNPM_HOME: ~/.pnpm-store
steps:
-
name: Check out
@ -42,27 +44,22 @@ jobs:
tags: ${{ env.TEST_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max
-
name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
~/.local/share/gnpm
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Test
working-directory: etherpad
@ -79,7 +76,7 @@ jobs:
*) printf %s\\n "unexpected status: ${status}" >&2; exit 1;;
esac
done
(cd src && pnpm run test-container)
(cd src && gnpm run test-container)
git clean -dxf .
-
name: Docker meta
@ -113,7 +110,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Update repo description
uses: peter-evans/dockerhub-description@v4
uses: peter-evans/dockerhub-description@v5
if: github.ref == 'refs/heads/master'
with:
readme-filepath: ./etherpad/README.md

View file

@ -1,5 +1,5 @@
# Leave the powered by Sauce Labs bit in as this means we get additional concurrency
name: "Frontend admin tests powered by Sauce Labs"
name: "Frontend admin tests"
on:
push:
@ -11,6 +11,8 @@ permissions:
jobs:
withplugins:
env:
PNPM_HOME: ~/.pnpm-store
name: with plugins
runs-on: ubuntu-latest
@ -29,26 +31,22 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
~/.local/share/gnpm
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
@ -56,8 +54,6 @@ jobs:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
#-
# name: Install etherpad plugins
# # We intentionally install an old ep_align version to test upgrades to
@ -75,7 +71,7 @@ jobs:
# rules.
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: pnpm i
run: gnpm i --runtimeVersion="${{ matrix.node }}"
#-
# name: Install etherpad plugins
# run: rm -Rf node_modules/ep_align/static/tests/*
@ -99,7 +95,7 @@ jobs:
- name: Build admin frontend
working-directory: admin
run: |
pnpm run build
gnpm run build --runtimeVersion="${{ matrix.node }}"
# name: Run the frontend admin tests
# shell: bash
# env:
@ -130,7 +126,7 @@ jobs:
- name: Run the frontend admin tests
shell: bash
run: |
pnpm run prod &
gnpm run prod --runtimeVersion="${{ matrix.node }}" &
connected=false
can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1
@ -142,9 +138,9 @@ jobs:
sleep 1
done
cd src
pnpm exec playwright install
pnpm exec playwright install-deps
pnpm run test-admin
gnpm exec playwright install --runtimeVersion="${{ matrix.node }}"
gnpm exec playwright install-deps --runtimeVersion="${{ matrix.node }}"
gnpm run test-admin --runtimeVersion="${{ matrix.node }}"
- uses: actions/upload-artifact@v4
if: always()
with:

View file

@ -11,6 +11,8 @@ permissions:
jobs:
playwright-chrome:
env:
PNPM_HOME: ~/.pnpm-store
name: Playwright Chrome
runs-on: ubuntu-latest
steps:
@ -23,32 +25,26 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 22
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
~/.cache/ms-playwright
~/.local/share/gnpm
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm install --frozen-lockfile
-
name: export GIT_HASH to env
id: environment
@ -56,17 +52,10 @@ jobs:
-
name: Create settings.json
run: cp ./src/tests/settings.json settings.json
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Run the frontend tests
shell: bash
run: |
pnpm run prod &
gnpm run prod &
connected=false
can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1
@ -78,8 +67,8 @@ jobs:
sleep 1
done
cd src
pnpm exec playwright install chromium --with-deps
pnpm run test-ui --project=chromium
gnpm exec playwright install chromium --with-deps
gnpm run test-ui --project=chromium
- uses: actions/upload-artifact@v4
if: always()
with:
@ -87,6 +76,8 @@ jobs:
path: src/playwright-report/
retention-days: 30
playwright-firefox:
env:
PNPM_HOME: ~/.pnpm-store
name: Playwright Firefox
runs-on: ubuntu-latest
steps:
@ -97,46 +88,34 @@ jobs:
printf %s\\n '::set-output name=tunnel_id::${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}'
- name: Checkout repository
uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.PNPM_HOME }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
- name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm install --frozen-lockfile
- name: export GIT_HASH to env
id: environment
run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})"
- name: Create settings.json
run: cp ./src/tests/settings.json settings.json
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Run the frontend tests
shell: bash
run: |
pnpm run prod &
gnpm run prod &
connected=false
can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1
@ -148,8 +127,8 @@ jobs:
sleep 1
done
cd src
pnpm exec playwright install firefox --with-deps
pnpm run test-ui --project=firefox
gnpm exec playwright install firefox --with-deps
gnpm run test-ui --project=firefox
- uses: actions/upload-artifact@v4
if: always()
with:
@ -159,7 +138,8 @@ jobs:
playwright-webkit:
name: Playwright Webkit
runs-on: ubuntu-latest
env:
PNPM_HOME: ~/.pnpm-store
steps:
-
name: Generate Sauce Labs strings
@ -170,39 +150,25 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 22
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
path: |
${{ env.PNPM_HOME }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm install --frozen-lockfile
-
name: export GIT_HASH to env
id: environment
@ -213,7 +179,7 @@ jobs:
- name: Run the frontend tests
shell: bash
run: |
pnpm run prod &
gnpm run prod &
connected=false
can_connect() {
curl -sSfo /dev/null http://localhost:9001/ || return 1
@ -225,8 +191,8 @@ jobs:
sleep 1
done
cd src
pnpm exec playwright install webkit --with-deps
pnpm run test-ui --project=webkit || true
gnpm exec playwright install webkit --with-deps
gnpm run test-ui --project=webkit || true
- uses: actions/upload-artifact@v4
if: always()
with:

60
.github/workflows/handleRelease.yml vendored Normal file
View file

@ -0,0 +1,60 @@
name: "Handle release"
# any branch is useful for testing before a PR is submitted
on:
workflow_run:
workflows:
- "Docker"
permissions:
contents: read
env:
PNPM_HOME: ~/.pnpm-store
jobs:
create-release:
permissions: write-all
# run on pushes to any branch
# run on PRs from external forks
if: |
(github.event_name != 'pull_request')
|| (github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id)
name: Handle the release
runs-on: ubuntu-latest
steps:
-
name: Checkout repository
uses: actions/checkout@v5
- uses: actions/cache@v4
name: Setup gnpm cache
if: always()
with:
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
- name: Install all dependencies and symlink for ep_etherpad-lite
run: gnpm install --frozen-lockfile
- name: Build etherpad
run: gnpm run build:etherpad
# On release, create release
- name: Generate Changelog
if: ${{startsWith(github.ref, 'refs/tags/v') }}
working-directory: bin
run: gnpm run generateChangelog ${{ github.ref }} > ${{ github.workspace }}-CHANGELOG.txt
- name: Release
uses: softprops/action-gh-release@v2
if: ${{startsWith(github.ref, 'refs/tags/v') }}
with:
body_path: ${{ github.workspace }}-CHANGELOG.txt
make_latest: true

View file

@ -12,6 +12,10 @@ on:
permissions:
contents: read
env:
PNPM_HOME: ~/.pnpm-store
LOG_LEVEL: DEBUG
jobs:
withoutplugins:
# run on pushes to any branch
@ -25,37 +29,36 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm install --frozen-lockfile
-
name: Install etherpad-load-test
run: sudo npm install -g etherpad-load-test-socket-io
-
name: Run load test
run: src/tests/frontend/travis/runnerLoadTest.sh 25 50
run: |
gnpm --gnpmEnv
eval "$(gnpm --gnpmEnv)"
echo $PATH
src/tests/frontend/travis/runnerLoadTest.sh 25 50
withplugins:
# run on pushes to any branch
@ -69,37 +72,32 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install etherpad-load-test
run: pnpm install -g etherpad-load-test-socket-io
run: sudo npm install -g etherpad-load-test-socket-io
-
name: Install etherpad plugins
# The --legacy-peer-deps flag is required to work around a bug in npm v7:
# https://github.com/npm/cli/issues/2199
run: >
pnpm install --workspace-root
gnpm install --workspace-root
ep_align
ep_author_hover
ep_cursortrace
@ -123,10 +121,12 @@ jobs:
# rules.
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm install --frozen-lockfile
-
name: Run load test
run: src/tests/frontend/travis/runnerLoadTest.sh 25 50
run: |
eval "$(gnpm --gnpmEnv)"
src/tests/frontend/travis/runnerLoadTest.sh 25 50
long:
# run on pushes to any branch
@ -140,34 +140,33 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm install --frozen-lockfile
-
name: Install etherpad-load-test
run: sudo npm install -g etherpad-load-test-socket-io
-
name: Run load test
run: src/tests/frontend/travis/runnerLoadTest.sh 5000 5
run: |
gnpm --gnpmEnv
eval "$(gnpm --gnpmEnv)"
echo $PATH
src/tests/frontend/travis/runnerLoadTest.sh 5000 5

View file

@ -12,6 +12,8 @@ on:
permissions:
contents: read
env:
PNPM_HOME: ~/.pnpm-store
jobs:
performTypeCheck:
@ -23,30 +25,26 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: ./bin/installDeps.sh
run: gnpm install --frozen-lockfile
- name: Perform type check
working-directory: ./src
run: npm run ts-check
run: gnpm run ts-check

View file

@ -12,6 +12,9 @@ on:
permissions:
contents: read
env:
PNPM_HOME: ~/.pnpm-store
jobs:
ratelimit:
# run on pushes to any branch
@ -25,26 +28,23 @@ jobs:
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
name: Setup gnpm cache
if: always()
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
-
name: docker network
@ -63,7 +63,7 @@ jobs:
docker run --rm --network ep_net --ip 172.23.42.3 --name anotherip -dt anotherip
-
name: install dependencies and create symlink for ep_etherpad-lite
run: bin/installDeps.sh
run: gnpm install --frozen-lockfile
-
name: run rate limit test
run: |

View file

@ -1,3 +1,5 @@
permissions:
contents: read
name: Release etherpad
on:
workflow_dispatch:
@ -12,6 +14,9 @@ on:
- minor
- major
env:
PNPM_HOME: ~/.pnpm-store
jobs:
releases:
runs-on: ubuntu-latest
@ -42,24 +47,25 @@ jobs:
repository: ether/ether.github.com
path: ether.github.com
token: '${{ secrets.ETHER_RELEASE_TOKEN }}'
- name: Setup Node.js
uses: actions/setup-node@v4
- uses: actions/cache@v4
name: Setup gnpm cache
if: always()
with:
node-version: '20'
- uses: pnpm/action-setup@v4
name: Install pnpm
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Install dependencies etherpad
run: pnpm install --frozen-lockfile
working-directory: etherpad
version: 0.0.12
- name: Install dependencies ether.github.com
run: pnpm install --frozen-lockfile
run: gnpm install --frozen-lockfile
working-directory: ether.github.com
- name: Set git user
run: |
@ -76,7 +82,8 @@ jobs:
working-directory: etherpad
run: |
cd bin
pnpm run release ${{ inputs.release_type }}
gnpm install
gnpm run release ${{ inputs.release_type }}
- name: Push after release
working-directory: etherpad
run: |

45
.github/workflows/releaseEtherpad.yml vendored Normal file
View file

@ -0,0 +1,45 @@
name: releaseEtherpad.yaml
permissions:
contents: read
on:
workflow_dispatch:
env:
PNPM_HOME: ~/.pnpm-store
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
if: always()
with:
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 0.0.12
- name: Install dependencies
run: gnpm install --frozen-lockfile
- name: Rename etherpad
working-directory: ./src
run: sed -i 's/ep_etherpad-lite/ep_etherpad/g' package.json
- name: Release to npm
run: gnpm publish --no-git-checks
working-directory: ./src
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PRIVATE_TOKEN }}

View file

@ -9,7 +9,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
close-issue-label: wontfix
close-pr-label: wontfix

View file

@ -12,6 +12,9 @@ on:
permissions:
contents: read
env:
PNPM_HOME: ~/.pnpm-store
jobs:
withpluginsLinux:
# run on pushes to any branch
@ -31,35 +34,28 @@ jobs:
uses: actions/checkout@v5
with:
ref: develop #FIXME change to master when doing release
-
uses: actions/setup-node@v4
- uses: actions/cache@v4
name: Setup gnpm cache
if: always()
with:
node-version: ${{ matrix.node }}
- uses: pnpm/action-setup@v4
name: Install pnpm
path: |
${{ env.STORE_PATH }}
~/.local/share/gnpm
~/.cache/ms-playwright
/usr/local/bin/gnpm
/usr/local/bin/gnpm-0.0.12
key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-gnpm-store-
- name: Setup gnpm
uses: SamTV12345/gnpm-setup@main
with:
version: 10
run_install: false
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
version: 0.0.12
- name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.3
with:
packages: libreoffice libreoffice-pdfimport
version: 1.0
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
-
name: Install libreoffice
uses: awalsh128/cache-apt-pkgs-action@v1.5.3
@ -68,17 +64,14 @@ jobs:
version: 1.0
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: bin/installDeps.sh
- name: Install admin ui
working-directory: admin
run: pnpm install
run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}"
- name: Build admin ui
working-directory: admin
run: pnpm build
run: gnpm build --runtimeVersion="${{ matrix.node }}"
-
name: Install Etherpad plugins
run: >
pnpm run install-plugins
gnpm run install-plugins
ep_align
ep_author_hover
ep_cursortrace
@ -90,13 +83,13 @@ jobs:
ep_set_title_on_pad
ep_spellcheck
ep_subscript_and_superscript
ep_table_of_contents
ep_table_of_contents --runtimeVersion="${{ matrix.node }}"
-
name: Run the backend tests
run: pnpm run test
run: gnpm run test --runtimeVersion="${{ matrix.node }}"
-
name: Install all dependencies and symlink for ep_etherpad-lite
run: ./bin/installDeps.sh
run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}"
# Because actions/checkout@v5 is called with "ref: master" and without
# "fetch-depth: 0", the local clone does not have the ${GITHUB_SHA}
# commit. Fetch ${GITHUB_REF} to get the ${GITHUB_SHA} commit. Note that a
@ -113,4 +106,4 @@ jobs:
# commit that merges the PR's source branch to its destination branch.
run: git checkout "${GITHUB_SHA}"
- name: Run the backend tests
run: pnpm run test
run: gnpm run test --runtimeVersion="${{ matrix.node }}"

View file

@ -1,86 +0,0 @@
name: "Windows Build"
# any branch is useful for testing before a PR is submitted
on:
push:
paths-ignore:
- "doc/**"
pull_request:
paths-ignore:
- "doc/**"
permissions:
contents: read
jobs:
build-zip:
permissions: write-all
# run on pushes to any branch
# run on PRs from external forks
if: |
(github.event_name != 'pull_request')
|| (github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id)
name: Build .zip
runs-on: windows-latest
steps:
-
uses: msys2/setup-msys2@v2
with:
path-type: inherit
install: >-
zip
-
name: Checkout repository
uses: actions/checkout@v5
-
uses: actions/setup-node@v4
with:
node-version: 22
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Only install direct dependencies
run: pnpm config set auto-install-peers false
-
name: Install all dependencies and symlink for ep_etherpad-lite
shell: msys2 {0}
run: bin/installDeps.sh
-
name: Run the backend tests
shell: msys2 {0}
working-directory: src
run: pnpm test
-
name: Run Etherpad
working-directory: src
run: |
pnpm i
pnpm exec playwright install --with-deps
pnpm run prod &
curl --connect-timeout 10 --max-time 20 --retry 5 --retry-delay 10 --retry-max-time 60 --retry-connrefused http://127.0.0.1:9001/p/test
pnpm exec playwright install chromium --with-deps
pnpm run test-ui --project=chromium
# On release, create release
- name: Generate Changelog
if: ${{startsWith(github.ref, 'refs/tags/v') }}
working-directory: bin
run: pnpm run generateChangelog ${{ github.ref }} > ${{ github.workspace }}-CHANGELOG.txt
- name: Release
uses: softprops/action-gh-release@v2
if: ${{startsWith(github.ref, 'refs/tags/v') }}
with:
body_path: ${{ github.workspace }}-CHANGELOG.txt
make_latest: true

View file

@ -1,3 +1,12 @@
# 2.5.1
### Notable enhancements and fixes
- Added endpoint for prometheus scraping. You can now scrape the metrics endpoint with prometheus. It is available at /stats/prometheus if you have enableMetrics set to true in your settings.json
- fixed exposeVersion causing the pad panel to not load correctly
- fixed admin manage pad url to also take the base path into account
# 2.5.0
### Notable enhancements and fixes

View file

@ -1,7 +1,7 @@
{
"name": "admin",
"private": true,
"version": "2.5.0",
"version": "2.5.1",
"type": "module",
"scripts": {
"dev": "vite",
@ -16,27 +16,31 @@
"devDependencies": {
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-toast": "^1.2.15",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@typescript-eslint/eslint-plugin": "^8.40.0",
"@typescript-eslint/parser": "^8.40.0",
"@vitejs/plugin-react-swc": "^4.0.1",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"i18next": "^25.4.0",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.1",
"@typescript-eslint/eslint-plugin": "^8.46.0",
"@typescript-eslint/parser": "^8.46.0",
"@vitejs/plugin-react": "^5.0.4",
"babel-plugin-react-compiler": "19.1.0-rc.3",
"eslint": "^9.37.0",
"eslint-plugin-react-hooks": "^6.1.1",
"eslint-plugin-react-refresh": "^0.4.23",
"i18next": "^25.5.3",
"i18next-browser-languagedetector": "^8.2.0",
"lucide-react": "^0.541.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-hook-form": "^7.62.0",
"react-i18next": "^15.7.1",
"react-router-dom": "^7.8.1",
"lucide-react": "^0.545.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-hook-form": "^7.64.0",
"react-i18next": "^16.0.0",
"react-router-dom": "^7.9.0",
"socket.io-client": "^4.8.1",
"typescript": "^5.9.2",
"vite": "^7.1.3",
"vite-plugin-static-copy": "^3.1.2",
"vite-plugin-svgr": "^4.3.0",
"typescript": "^5.9.3",
"vite": "npm:rolldown-vite@latest",
"vite-plugin-babel": "^1.3.2",
"vite-plugin-static-copy": "^3.1.3",
"zustand": "^5.0.8"
},
"overrides": {
"vite": "npm:rolldown-vite@latest"
}
}

50
admin/public/brand.svg Normal file
View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg fill="#0f775b" width="355px" height="355px" viewBox="0 0 355 355" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Group 10</title>
<defs>
<!-- top line -->
<rect id="path-4" x="41" y="110" width="142" height="25" rx="12.5" fill="#0f775b">
<animate attributeName="width" from="0" to="142" dur="3s" fill="freeze"/>
</rect>
<!-- middle line -->
<rect id="path-2" x="42" y="167" width="168" height="27" rx="13.5" fill="#0f775b">
<animate attributeName="width" from="0" to="168" dur="5s" fill="freeze"/>
</rect>
<!-- bottom line -->
<rect id="path-6" x="41" y="226" width="105" height="25" rx="12.5" fill="#0f775b">
<animate attributeName="width" from="0" to="105" dur="2s" fill="freeze"/>
</rect>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" >
<g id="Group-5-Copy-2" transform="translate(-415.000000, -351.000000)">
<g id="Group-10" transform="translate(415.000000, 351.000000)">
<g id="Group-9" transform="translate(0.000000, 15.000000)">
<!-- small radio wave -->
<path stroke="0f775b" d="M237.612214,138.157654 C234.725783,135.28192 230.051254,135.279644 227.164823,138.157654 C224.278392,141.035663 224.278392,145.698831 227.164823,148.57684 C234.93988,156.329214 239.222735,166.601382 239.222735,177.499403 C239.222735,188.397423 234.93988,198.669591 227.164823,206.424696 C224.278392,209.30043 224.278392,213.965873 227.164823,216.841607 C228.608267,218.280384 230.497251,219 232.388518,219 C234.277503,219 236.16877,218.280384 237.612214,216.841607 C248.18012,206.304532 254,192.334147 254,177.499403 C254,162.665114 248.18012,148.694728 237.612214,138.157654 Z" id="Path-Copy-26" fill-opacity="0.200482" fill="#000000" fill-rule="nonzero" opacity="0.754065225">
<animate attributeName="opacity" from="0" to="1" dur="3s" repeatCount="indefinite"/>
</path>
<!-- large radio wave -->
<path stroke="0f775b" d="M267.333026,113.158661 C264.51049,110.280446 259.939438,110.280446 257.116902,113.158661 C254.294366,116.039154 254.294366,120.709078 257.116902,123.586837 C285.703837,152.763042 285.703837,200.237641 257.116902,229.413847 C254.294366,232.292061 254.294366,236.96153 257.116902,239.839744 C258.528393,241.280219 260.375562,242 262.224964,242 C264.074365,242 265.921535,241.279763 267.333026,239.837011 C301.555658,204.912576 301.555658,148.084007 267.333026,113.158661 Z" id="Path-Copy-27" fill-opacity="0.250565" fill="#131514" fill-rule="nonzero" opacity="0.754065225">
<animate attributeName="opacity" from="0" to="1" dur="3s" repeatCount="indefinite"/>
</path>
<!-- top line -->
<g stroke="0f775b" id="Rectangle-Copy-56">
<use fill="#000000" fill-opacity="0.200482" fill-rule="evenodd" xlink:href="#path-4"></use>
</g>
<!-- middle line -->
<g stroke="0f775b" id="Rectangle-Copy-55">
<use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
<use fill="#000000" fill-opacity="0.200482" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<!-- bottom line -->
<g stroke="0f775b" id="Rectangle-Copy-57">
<use fill="black" fill-opacity="1" filter="url(#filter-7)" xlink:href="#path-6"></use>
<use fill="#000000" fill-opacity="0.200482" xlink:href="#path-6"></use>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -1,6 +1,7 @@
import {FC, JSX, ReactElement} from "react";
export type IconButtonProps = {
style?: React.CSSProperties,
icon: JSX.Element,
title: string|ReactElement,
onClick: ()=>void,
@ -8,8 +9,8 @@ export type IconButtonProps = {
disabled?: boolean
}
export const IconButton:FC<IconButtonProps> = ({icon,className,onClick,title, disabled})=>{
return <button onClick={onClick} className={"icon-button "+ className} disabled={disabled}>
export const IconButton:FC<IconButtonProps> = ({icon,className,onClick,title, disabled, style})=>{
return <button style={style} onClick={onClick} className={"icon-button "+ className} disabled={disabled}>
{icon}
<span>{title}</span>
</button>

View file

@ -42,6 +42,9 @@ div.menu {
position: fixed;
}
[role="dialog"] h2 {
color: var(--etherpad-color);
}
.icon-button {
display: flex;
@ -54,6 +57,26 @@ div.menu {
cursor: pointer;
}
.icon-button:hover {
background-color: #13a37c;
}
.dialog-close-button {
position: absolute;
top: 10px;
right: 10px;
background: none;
border: none;
cursor: pointer;
color: var(--etherpad-color);
}
.icon-button:active {
background-color: #13a37c;
transform: scale(0.98);
}
.icon-button svg {
align-self: center;
}
@ -868,3 +891,7 @@ input, button, select, optgroup, textarea {
display: flex;
justify-content: center;
}
.manage-pads-header {
display: flex;
}

View file

@ -6,8 +6,13 @@ import {useDebounce} from "../utils/useDebounce.ts";
import {determineSorting} from "../utils/sorting.ts";
import * as Dialog from "@radix-ui/react-dialog";
import {IconButton} from "../components/IconButton.tsx";
import {ChevronLeft, ChevronRight, Eye, Trash2, FileStack} from "lucide-react";
import {ChevronLeft, ChevronRight, Eye, Trash2, FileStack, PlusIcon} from "lucide-react";
import {SearchField} from "../components/SearchField.tsx";
import {useForm} from "react-hook-form";
type PadCreateProps = {
padName: string
}
export const PadPage = ()=>{
const settingsSocket = useStore(state=>state.settingsSocket)
@ -25,6 +30,8 @@ export const PadPage = ()=>{
const [deleteDialog, setDeleteDialog] = useState<boolean>(false)
const [errorText, setErrorText] = useState<string|null>(null)
const [padToDelete, setPadToDelete] = useState<string>('')
const [createPadDialogOpen, setCreatePadDialogOpen] = useState<boolean>(false)
const {register, handleSubmit} = useForm<PadCreateProps>()
const pages = useMemo(()=>{
if(!pads){
return 0;
@ -70,8 +77,33 @@ export const PadPage = ()=>{
})
})
type SettingsSocketCreateReponse = {
error: string
} | {
success: string
}
settingsSocket.on('results:createPad', (rep: SettingsSocketCreateReponse)=>{
if ('error' in rep) {
useStore.getState().setToastState({
open: true,
title: rep.error,
success: false
})
} else {
useStore.getState().setToastState({
open: true,
title: rep.success,
success: true
})
setCreatePadDialogOpen(false)
// reload pads
settingsSocket.emit('padLoad', searchParams)
}
})
settingsSocket.on('results:cleanupPadRevisions', (data)=>{
let newPads = useStore.getState().pads?.results ?? []
const newPads = useStore.getState().pads?.results ?? []
if (data.error) {
setErrorText(data.error)
@ -99,6 +131,12 @@ export const PadPage = ()=>{
settingsSocket?.emit('cleanupPadRevisions', padID)
}
const onPadCreate = (data: PadCreateProps)=>{
settingsSocket?.emit('createPad', {
padName: data.padName
})
}
return <div>
<Dialog.Root open={deleteDialog}><Dialog.Portal>
@ -139,7 +177,32 @@ export const PadPage = ()=>{
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<h1><Trans i18nKey="ep_admin_pads:ep_adminpads2_manage-pads"/></h1>
<Dialog.Root open={createPadDialogOpen}>
<Dialog.Portal>
<Dialog.Overlay className="dialog-confirm-overlay" />
<Dialog.Content className="dialog-confirm-content">
<Dialog.Title className="dialog-confirm-title"><Trans i18nKey="index.newPad"/></Dialog.Title>
<form onSubmit={handleSubmit(onPadCreate)}>
<button className="dialog-close-button" onClick={()=>{
setCreatePadDialogOpen(false);
}}>x</button>
<div style={{display: 'grid', gap: '10px', gridTemplateColumns: 'auto auto', marginBottom: '1rem'}}>
<label><Trans i18nKey="ep_admin_pads:ep_adminpads2_padname"/></label>
<input {...register('padName', {
required: true
})}/>
</div>
<input type="submit" value={t('admin_settings.createPad')} className="login-button" />
</form>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<span className="manage-pads-header">
<h1><Trans i18nKey="ep_admin_pads:ep_adminpads2_manage-pads"/></h1>
<span style={{width: '29px', marginBottom: 'auto', marginTop: 'auto', flexGrow: 1}}><IconButton style={{float: 'right'}} icon={<PlusIcon/>} title={<Trans i18nKey="index.newPad"/>} onClick={()=>{
setCreatePadDialogOpen(true)
}}/></span>
</span>
<SearchField value={searchTerm} onChange={v=>setSearchTerm(v.target.value)} placeholder={t('ep_admin_pads:ep_adminpads2_search-heading')}/>
<table>
<thead>
@ -192,7 +255,7 @@ export const PadPage = ()=>{
<IconButton icon={<FileStack/>} title={<Trans i18nKey="ep_admin_pads:ep_adminpads2_cleanup"/>} onClick={()=>{
cleanupPad(pad.padName)
}}/>
<IconButton icon={<Eye/>} title="view" onClick={()=>window.open(`/p/${pad.padName}`, '_blank')}/>
<IconButton icon={<Eye/>} title={<Trans i18nKey="index.createOpenPad"/>} onClick={()=>window.open(`../../p/${pad.padName}`, '_blank')}/>
</div>
</td>
</tr>

View file

@ -20,7 +20,6 @@ export const ShoutPage = ()=>{
setShouts([...shouts, shout])
})
pluginSocket.on('results:stats', (statData) => {
console.log('Shoutdata', statData);
setTotalUsers(statData.totalUsers);
})
}

View file

@ -1,6 +1,7 @@
import {useStore} from "../store/store.ts";
import * as Dialog from '@radix-ui/react-dialog';
import ReactComponent from './brand.svg?react';
import brand from './brand.svg'
export const LoadingScreen = ()=>{
const showLoading = useStore(state => state.showLoading)
@ -10,7 +11,7 @@ export const LoadingScreen = ()=>{
<div className="flex flex-col items-center">
<div className="animate-spin w-16 h-16 border-t-2 border-b-2 border-[--fg-color] rounded-full"></div>
<div className="mt-4 text-[--fg-color]">
<ReactComponent/>
<img src={brand}/>
</div>
</div>
</Dialog.Content>

View file

@ -1,18 +1,20 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import svgr from 'vite-plugin-svgr'
import {viteStaticCopy} from "vite-plugin-static-copy";
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), svgr(), viteStaticCopy({
plugins: [viteStaticCopy({
targets: [
{
src: '../src/locales',
dest: ''
}
]
})],
}), react({
babel: {
plugins: ['babel-plugin-react-compiler'],
}})],
base: '/admin',
build:{
outDir: '../src/templates/admin',

View file

@ -1,23 +1,23 @@
{
"name": "bin",
"version": "2.5.0",
"version": "2.5.1",
"description": "",
"main": "checkAllPads.js",
"directories": {
"doc": "doc"
},
"dependencies": {
"axios": "^1.10.0",
"axios": "^1.12.1",
"ep_etherpad-lite": "workspace:../src",
"log4js": "^6.9.1",
"semver": "^7.7.2",
"tsx": "^4.20.5",
"ueberdb2": "^5.0.15"
"semver": "^7.7.3",
"tsx": "^4.20.6",
"ueberdb2": "^5.0.22"
},
"devDependencies": {
"@types/node": "^24.3.0",
"@types/semver": "^7.7.0",
"typescript": "^5.9.2"
"@types/node": "^24.7.0",
"@types/semver": "^7.7.1",
"typescript": "^5.9.3"
},
"scripts": {
"makeDocs": "node --import tsx make_docs.ts",

View file

@ -24,7 +24,7 @@ const possibleActions = [
const install = ()=> {
const argsAsString: string = args.join(" ");
const regexRegistryPlugins = /(?<=i\s)(.*?)(?=--github|--path|$)/;
const regexRegistryPlugins = /(?<=(?:i|install)\s)(.*?)(?=--github|--path|$)/;
const regexLocalPlugins = /(?<=--path\s)(.*?)(?=--github|$)/;
const regexGithubPlugins = /(?<=--github\s)(.*?)(?=--path|$)/;
const registryPlugins = argsAsString.match(regexRegistryPlugins)?.[0]?.split(" ")?.filter(s => s) || [];
@ -109,6 +109,9 @@ switch (action) {
case "rm":
remove(args.slice(1));
break;
case "remove":
remove(args.slice(1));
break;
default:
console.error('Expected at least one argument!');
process.exit(1);

View file

@ -1,6 +1,6 @@
== Changeset Library
The https://github.com/ether/etherpad-lite/blob/develop/src/static/js/Changeset.js[changeset
The https://github.com/ether/etherpad-lite/blob/develop/src/static/js/Changeset.ts[changeset
library]
provides tools to create, read, and apply changesets.
@ -31,7 +31,7 @@ const AttributePool = require('ep_etherpad-lite/static/js/AttributePool');
----
Changesets do not include any attribute keyvalue pairs. Instead, they use
numeric identifiers that reference attributes kept in an https://github.com/ether/etherpad-lite/blob/develop/src/static/js/AttributePool.js[attribute pool].
numeric identifiers that reference attributes kept in an https://github.com/ether/etherpad-lite/blob/develop/src/static/js/AttributePool.ts[attribute pool].
This attribute interning reduces the transmission overhead of attributes that
are used many times.

View file

@ -29,7 +29,7 @@ const AttributePool = require('ep_etherpad-lite/static/js/AttributePool');
Changesets do not include any attribute keyvalue pairs. Instead, they use
numeric identifiers that reference attributes kept in an [attribute
pool](https://github.com/ether/etherpad-lite/blob/develop/src/static/js/AttributePool.js).
pool](https://github.com/ether/etherpad-lite/blob/develop/src/static/js/AttributePool.ts).
This attribute interning reduces the transmission overhead of attributes that
are used many times.

View file

@ -9,5 +9,8 @@
},
"peerDependencies": {
"search-insights": "^2.17.3"
},
"overrides": {
"vite": "npm:rolldown-vite@latest"
}
}

View file

@ -7,8 +7,9 @@ execute its own functionality based on these events.
Publicly available plugins can be found in the npm registry (see
<https://npmjs.org>). Etherpad's naming convention for plugins is to prefix your
plugins with `ep_`. So, e.g. it's `ep_flubberworms`. Thus you can install
plugins from npm, using `npm install --no-save --legacy-peer-deps
ep_flubberworm` in Etherpad's root directory.
plugins from npm, using `pnpm run plugins install ep_flubberworms` in Etherpad's root directory.
Also see [wiki article](https://github.com/ether/etherpad-lite/wiki/Available-Plugins) for more info.
You can also browse to `http://yourEtherpadInstan.ce/admin/plugins`, which will
list all installed plugins and those available on npm. It even provides

View file

@ -17,3 +17,15 @@ We currently measure:
Under the hood, we are happy to rely on https://github.com/felixge/node-measured[measured] for all our metrics needs.
To modify or simply access our stats in your plugin, simply `require('ep_etherpad-lite/stats')` which is a https://yaorg.github.io/node-measured/packages/measured-core/Collection.html[`measured.Collection`].
=== Prometheus scraper
Besides the non standard `/stats` endpoint, Etherpad also exposes a `/stats/prometheus` endpoint which is compatible with Prometheus scraping. It includes a lot more metrics than the standard `/stats` endpoint. It contains the following metrics:
- ueberdb stats
- gc
- memory
- event loop lag
- v8
- and more

View file

@ -42,14 +42,14 @@
"ui": "workspace:./ui"
},
"engines": {
"node": ">=18.18.2",
"npm": ">=6.14.0",
"pnpm": ">=8.3.0"
"node": ">=20.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/ether/etherpad-lite.git"
},
"version": "2.5.0",
"packageManager": "pnpm@10.18.0",
"engineStrict": true,
"version": "2.5.1",
"license": "Apache-2.0"
}

3070
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -48,6 +48,7 @@
"index.generateNewPad": "Стварыць выпадковую назву дакумэнта",
"index.labelPad": "Назва дакумэнта (неабавязкова)",
"index.placeholderPadEnter": "Калі ласка, увядзіце назву дакумэнта…",
"index.createAndShareDocuments": "Стварайце і дзяліцеся дакумэнтамі ў рэальным часе",
"pad.toolbar.bold.title": "Тоўсты (Ctrl-B)",
"pad.toolbar.italic.title": "Курсіў (Ctrl-I)",
"pad.toolbar.underline.title": "Падкрэсьліваньне (Ctrl-U)",
@ -64,6 +65,7 @@
"pad.toolbar.savedRevision.title": "Захаваць вэрсію",
"pad.toolbar.settings.title": "Налады",
"pad.toolbar.embed.title": "Падзяліцца і ўбудаваць гэты дакумэнт",
"pad.toolbar.home.title": "Вярнуцца ў пачатак",
"pad.toolbar.showusers.title": "Паказаць карыстальнікаў у гэтым дакумэнце",
"pad.colorpicker.save": "Захаваць",
"pad.colorpicker.cancel": "Скасаваць",
@ -80,6 +82,8 @@
"pad.settings.fontType": "Тып шрыфту:",
"pad.settings.fontType.normal": "Звычайны",
"pad.settings.language": "Мова:",
"pad.settings.deletePad": "Выдаліць нататнік",
"pad.delete.confirm": "Вы ўпэўненыя, што хочаце выдаліць гэты нататнік?",
"pad.settings.about": "Пра",
"pad.settings.poweredBy": "Працуе на",
"pad.importExport.import_export": "Імпарт/Экспарт",

View file

@ -3,6 +3,7 @@
"authors": [
"Alexgabi",
"An13sa",
"Atzerritik",
"HairyFotr",
"Izendegi",
"Mikel Ibaiba",
@ -45,7 +46,7 @@
"admin_settings.current_save.value": "Gorde Ezarpenak",
"admin_settings.page-title": "Ezarpenak - Etherpad",
"index.newPad": "Pad berria",
"index.createOpenPad": "edo sortu/ireki Pad bat honako izenarekin:",
"index.createOpenPad": "Ireki Pad bat honako izenarekin:",
"index.openPad": "ireki existitzen den eta hurrengo izena duen Pad-a:",
"index.recentPadsEmpty": "Ez da aurkitu duela gutxiko pad-ik",
"index.generateNewPad": "Sortu pad izen aleatorioa",

67
src/locales/got.json Normal file
View file

@ -0,0 +1,67 @@
{
"@metadata": {
"authors": [
"Gothicspeaker"
]
},
"admin_plugins.name": "𐌽𐌰𐌼𐍉",
"admin_plugins.version": "𐌿𐍃𐌼𐌴𐍂𐌹",
"admin_plugins_info.version_latest": "𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄 𐍅𐌹𐍃𐌰𐌽𐌳𐍉 𐌿𐍃𐌼𐌴𐍂𐌹",
"admin_plugins_info.version_number": "𐍂𐌰𐌸𐌾𐍉 𐌿𐍃𐌼𐌴𐍂𐌾𐌹𐍃",
"index.newPad": "𐍀𐌰𐌳 𐌽𐌹𐍅𐌹",
"index.createOpenPad": "𐍀𐌰𐌳 𐌱𐌹 𐌽𐌰𐌼𐌹𐌽 𐌿𐍃𐌻𐌿𐌺𐌰𐌽",
"index.openPad": "𐍅𐌹𐍃𐌰𐌽𐌳𐍉 𐍀𐌰𐌳 𐌿𐍃𐌻𐌿𐌺𐌰𐌽 𐌼𐌹𐌸 𐌽𐌰𐌼𐌹𐌽:",
"index.recentPads": "𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰 𐍀𐌰𐌳𐌰",
"index.recentPadsEmpty": "𐌽𐌹 𐌱𐌹𐌲𐌰𐍄 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰 𐍀𐌰𐌳𐌰.",
"index.labelPad": "𐌽𐌰𐌼𐍉 𐍀𐌰𐌳𐌹𐍃 (𐌼𐌰𐌷𐍄𐌴𐌹𐌲)",
"index.placeholderPadEnter": "𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺 𐌼𐌴𐌻𐌴𐌹 𐌽𐌰𐌼𐍉 𐍀𐌰𐌳𐌹𐍃...",
"pad.toolbar.bold.title": "𐌱𐌰𐌻𐌸 (𐌺𐍄𐍂𐌻+𐌱)",
"pad.toolbar.italic.title": "𐌹𐍄𐌰𐌻𐌹𐍃𐌺 (𐌺𐍄𐍂𐌻+𐌹)",
"pad.toolbar.underline.title": "𐌿𐍆𐍃𐍄𐍂𐌹𐌺𐍃 (𐌺𐍄𐍂𐌻+𐌿)",
"pad.toolbar.strikethrough.title": "𐍃𐍄𐍂𐌹𐌺𐌰𐌸𐌰𐌹𐍂𐌷 (𐌺𐍄𐍂𐌻+5)",
"pad.toolbar.undo.title": "𐌱𐌻𐌰𐌿𐌸𐌾𐌰𐌽 (𐌺𐍄𐍂𐌻+𐌶)",
"pad.toolbar.redo.title": "𐌰𐍆𐍄𐍂𐌰𐌲𐌰𐍄𐌰𐌿𐌾𐌰𐌽 (𐌺𐍄𐍂𐌻+𐍅)",
"pad.toolbar.timeslider.title": "𐌸𐌴𐌹𐌷𐍃𐌰𐍃𐌻𐌴𐌹𐌳𐌰𐌽𐌳𐍃",
"pad.toolbar.savedRevision.title": "𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌽",
"pad.toolbar.home.title": "𐌲𐌰𐍅𐌰𐌽𐌳𐌾𐌰𐌽 𐌸𐌿𐌺 𐌳𐌿 𐌲𐌰𐍂𐌳𐌰",
"pad.colorpicker.save": "𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌽",
"pad.colorpicker.cancel": "𐌱𐌹𐍅𐌰𐌽𐌳𐌾𐌰𐌽",
"pad.settings.myView": "𐍃𐌹𐌿𐌽𐍃 𐌼𐌴𐌹𐌽𐌰",
"pad.settings.stickychat": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹 𐌰𐌽𐌰 𐍃𐌺𐌰𐌹𐍂𐌼𐌰 𐍃𐌹𐌽𐍄𐌴𐌹𐌽𐍉",
"pad.settings.chatandusers": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹 𐌾𐌰𐌷 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐍃 𐌱𐌰𐌽𐌳𐍅𐌾𐌰𐌽",
"pad.settings.language": "𐍂𐌰𐌶𐌳𐌰:",
"pad.settings.deletePad": "𐍀𐌰𐌳𐌰 𐌿𐍃𐌵𐌹𐍃𐍄𐌾𐌰𐌽",
"pad.delete.confirm": "𐌱𐌹 𐍃𐌿𐌽𐌾𐌰𐌹 𐍅𐌹𐌻𐌴𐌹𐌶𐌿 𐌸𐌰𐌼𐌼𐌰 𐍀𐌰𐌳𐌰 𐌿𐍃𐌵𐌹𐍃𐍄𐌾𐌰𐌽?",
"pad.settings.about": "𐌱𐌹",
"pad.importExport.exporthtml": "𐌷𐍄𐌼𐌻",
"pad.importExport.exportpdf": "𐍀𐌳𐍆",
"pad.importExport.exportopen": "𐍉𐌳𐍆 (𐍉𐍀𐌰𐌹𐌽 𐌳𐍉𐌺𐌿𐌼𐌰𐌹𐌽𐍄 𐍆𐌰𐌿𐍂𐌼𐌰𐍄)",
"pad.modals.cancel": "𐌱𐌹𐍅𐌰𐌽𐌳𐌾𐌰𐌽",
"pad.modals.userdup": "𐌿𐍃𐌻𐌿𐌺𐌰𐌽 𐌹𐌽 𐌰𐌿𐌲𐌰𐌳𐌰𐌿𐍂𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌼𐌼𐌰",
"pad.modals.deleted": "𐌿𐍃𐌵𐌹𐍃𐍄𐌹𐌸.",
"pad.modals.deleted.explanation": "𐌸𐌰𐍄𐌰 𐍀𐌰𐌳 𐌿𐍃𐌽𐌿𐌼𐌰𐌽 𐌹𐍃𐍄.",
"pad.share": "𐌸𐌰𐍄𐌰 𐍀𐌰𐌳 𐌳𐌰𐌹𐌻𐌾𐌰𐌽",
"pad.share.readonly": "𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐌰𐌽𐌰𐌺𐌿𐌽𐌽𐌰𐌽",
"pad.share.link": "𐌲𐌰𐍅𐌹𐍃𐍃",
"pad.chat": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹",
"pad.chat.title": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹 𐌸𐌰𐌼𐌼𐌰 𐍀𐌰𐌳𐌰 𐌿𐍃𐌻𐌿𐌺𐌰𐌽.",
"pad.chat.stick.title": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹 𐍃𐍄𐌹𐌺𐌰𐌽 𐌳𐌿 𐍃𐌺𐌰𐌹𐍂𐌼𐌰",
"timeslider.toolbar.returnbutton": "𐌲𐌰𐍅𐌰𐌽𐌳𐌾𐌰𐌽 𐌸𐌿𐌺 𐌳𐌿 𐍀𐌰𐌳𐌰",
"timeslider.toolbar.authors": "𐌱𐍉𐌺𐌰𐍂𐌾𐍉𐍃:",
"timeslider.toolbar.authorsList": "𐌽𐌹 𐌱𐍉𐌺𐌰𐍂𐌾𐍉𐍃",
"timeslider.version": "𐌿𐍃𐌼𐌴𐍂𐌹 {{version}}",
"timeslider.month.january": "𐌾𐌰𐌽𐌿𐌰𐍂𐌴𐌹𐍃",
"timeslider.month.february": "𐍆𐌰𐌹𐌱𐍂𐌿𐌰𐍂𐌴𐌹𐍃",
"timeslider.month.march": "𐌼𐌰𐍂𐍄𐌹𐌿𐍃",
"timeslider.month.april": "𐌰𐍀𐍂𐌴𐌹𐌻𐌹𐍃",
"timeslider.month.may": "𐌼𐌰𐌾𐌿𐍃",
"timeslider.month.june": "𐌾𐌿𐌽𐌹𐌿𐍃",
"timeslider.month.july": "𐌾𐌿𐌻𐌹𐌿𐍃",
"timeslider.month.august": "𐌰𐌲𐌿𐍃𐍄𐌿𐍃",
"timeslider.month.september": "𐍃𐌰𐌹𐍀𐍄𐌰𐌹𐌼𐌱𐌰𐌹𐍂",
"timeslider.month.october": "𐌰𐌿𐌺𐍄𐍉𐌱𐌰𐌹𐍂",
"timeslider.month.november": "𐌽𐌰𐌿𐌱𐌰𐌹𐌼𐌱𐌰𐌹𐍂",
"timeslider.month.december": "𐌾𐌹𐌿𐌻𐌴𐌹𐍃",
"pad.userlist.entername": "𐌼𐌴𐌻𐌴𐌹 𐌽𐌰𐌼𐍉 𐌸𐌴𐌹𐌽",
"pad.userlist.unnamed": "𐌿𐌽𐌽𐌰𐌼𐌽𐌹𐌸"
}

View file

@ -38,8 +38,15 @@
"admin_settings.current_save.value": "Nastajenja składować",
"admin_settings.page-title": "Nastajenja Etherpad",
"index.newPad": "Nowy zapisnik",
"index.createOpenPad": "abo wutwor/wočiń zapisnik z mjenom:",
"index.createOpenPad": "Zapisnik po mjenje wočinić",
"index.openPad": "wočińće eksistowacy Pad z mjenom:",
"index.recentPads": "Najnowše zapisniki",
"index.recentPadsEmpty": "Žane najnowše zapisniki namakane.",
"index.generateNewPad": "Připadne mjeno zapisnika generować",
"index.labelPad": "Mjeno zapisnika (po přeću)",
"index.placeholderPadEnter": "Prošu zapodaj mjeno zapisnika…",
"index.createAndShareDocuments": "Wutwor a dźěl dokumenty we woprawdźitym času",
"index.createAndShareDocumentsDescription": "Etherpad wam zmóžnja, dokumenty zhromadnje we woprawdźitym času wobdźěłać, kaž editor live multi-player, kotryž we wašim wobhladowaku běži.",
"pad.toolbar.bold.title": "Tučny (Strg-B)",
"pad.toolbar.italic.title": "Kursiwny (Strg-I)",
"pad.toolbar.underline.title": "Podšmórnyć (Strg-U)",
@ -56,6 +63,7 @@
"pad.toolbar.savedRevision.title": "Wersiju składować",
"pad.toolbar.settings.title": "Nastajenja",
"pad.toolbar.embed.title": "Tutón zapisnik dźělić a zasadźić",
"pad.toolbar.home.title": "Wróćo k startowej stronje",
"pad.toolbar.showusers.title": "Wužiwarjow na tutym zapisniku pokazać",
"pad.colorpicker.save": "Składować",
"pad.colorpicker.cancel": "Přetorhnyć",

View file

@ -30,6 +30,7 @@
"admin_plugins.page-title": "Gestore dei plugin - Etherpad",
"admin_plugins.version": "Versione",
"admin_plugins_info": "Informazioni sulla risoluzione dei problemi",
"admin_plugins_info.hooks": "Hook installati",
"admin_plugins_info.hooks_client": "Hook lato client",
"admin_plugins_info.hooks_server": "Hook lato server",
"admin_plugins_info.parts": "Parti installate",

View file

@ -1,9 +1,16 @@
{
"@metadata": {
"authors": [
"Belkacem77"
"Belkacem77",
"ButterflyOfFire"
]
},
"admin_plugins.name": "Isem",
"admin_plugins.version": "Lqem",
"admin_settings": "Iɣewwaren",
"admin_settings.current": "Tawila tamirant",
"admin_settings.current_save.value": "Sekles iɣewwaren",
"admin_settings.page-title": "Iɣewwaren - Etherpad",
"index.newPad": "Apad amaynut",
"index.createOpenPad": "neɣ rnu/ldi apad s yisem:",
"pad.toolbar.bold.title": "Zur (Ctrl+B)",
@ -24,7 +31,7 @@
"pad.toolbar.embed.title": "Bḍu sakin seddu apad-agi",
"pad.toolbar.showusers.title": "Sken iseqdacen ɣef upad-agi",
"pad.colorpicker.save": "Sekles",
"pad.colorpicker.cancel": "Sefsex",
"pad.colorpicker.cancel": "Semmet",
"pad.loading": "Asali...",
"pad.noCookie": "Anagi n tuqqna ulac-it. Sireg inagan n tuqqna deg iminig-ik!",
"pad.permissionDenied": "Ur ɣur-k ara tasiregt akken ad tkecmeḍ ar upad-agi",
@ -37,6 +44,7 @@
"pad.settings.rtlcheck": "Ɣeṛ agbur seg uyeffus s azelmaḍ?",
"pad.settings.fontType": "Anaw n tsefsit:",
"pad.settings.language": "Tutlayt:",
"pad.settings.about": "Ɣef",
"pad.importExport.import_export": "Kter/Sifeḍ",
"pad.importExport.import": "Sali aḍris neɣ isemli",
"pad.importExport.importSuccessful": "Yedda!",
@ -52,7 +60,7 @@
"pad.modals.reconnecting": "Tulsa n tuqqna ar upad-ik.",
"pad.modals.forcereconnect": "Ḥettem tulsa n tuqqna",
"pad.modals.reconnecttimer": "Ɛreḍ tikelt-nniḍen tuqqna",
"pad.modals.cancel": "Sefsex",
"pad.modals.cancel": "Semmet",
"pad.modals.userdup": "Yeldi deg usfaylu-nniḍen",
"pad.modals.userdup.explanation": "Apad-agi yettban yeldi deg isfuyla-nniḍen deg uselkim-agi.",
"pad.modals.userdup.advice": "Ales tuqqna akken ad tesqedceḍ asfaylu-agi.",

View file

@ -32,7 +32,7 @@
"pad.toolbar.redo.title": "Widderhuelen (Ctrl-Y)",
"pad.toolbar.savedRevision.title": "Versioun späicheren",
"pad.toolbar.settings.title": "Astellungen",
"pad.toolbar.home.title": "Zréck op d'Haaptsäit",
"pad.toolbar.home.title": "Zeréck op d'Haaptsäit",
"pad.toolbar.showusers.title": "Aktuell Benotzer vun dësem Pad uweisen",
"pad.colorpicker.save": "Späicheren",
"pad.colorpicker.cancel": "Ofbriechen",

View file

@ -40,6 +40,7 @@
"pad.settings.fontType": "Fonta tips:",
"pad.settings.fontType.normal": "Normāls",
"pad.settings.language": "Valoda:",
"pad.settings.about": "Par",
"pad.importExport.import_export": "Importet/Eksportet",
"pad.importExport.import": "Augšupielādēt jebkuru teksta failu vai dokumentu",
"pad.importExport.importSuccessful": "Veiksmīgi!",

View file

@ -5,8 +5,26 @@
"شاه زمان پټان"
]
},
"admin_plugins.last-update": "وروستۍ هم‌مهالېدنه",
"admin_plugins.name": "نوم",
"admin_plugins.version": "بل‌بڼه",
"admin_plugins_info": "ستونزو اواري مالومات",
"admin_plugins_info.hooks": "ځای‌پرځای‌شوي چنگکونه",
"admin_plugins_info.version_latest": "وروستۍ د لاسرسي وړ بل‌بڼه",
"admin_plugins_info.version_number": "بل‌بڼې شمېره",
"admin_settings": "اوڼنې",
"admin_settings.current": "اوسنی ترتيب",
"admin_settings.current_example-devel": "د پراختيااوڼنې کينډۍ بېلگه",
"admin_settings.current_example-prod": "د توليد اوڼنې کينډۍ بېلگه",
"admin_settings.current_save.value": "اوڼنې خوندي‌کول",
"index.newPad": "نوې ليکچه",
"index.createOpenPad": "ليکچه د نوم له مخې پرانېستل",
"index.recentPads": "وروستۍ ليکچې",
"index.recentPadsEmpty": "هېڅ وروستۍ ليکچې ونه موندل شوې.",
"index.generateNewPad": "ناڅاپي ليکچې نوم پنځول",
"index.labelPad": "ليکچې نوم (اختياري)",
"index.placeholderPadEnter": "مهرباني وکړئ ليکچې نوم وليکئ...",
"index.createAndShareDocuments": "په رښتينې وخت کې لاسوندونه جوړ او شريک کړئ",
"pad.toolbar.bold.title": "زغرد (Ctrl-B)",
"pad.toolbar.italic.title": "رېوند (Ctrl-I)",
"pad.toolbar.underline.title": "لرکرښن (Ctrl+U)",
@ -31,6 +49,9 @@
"pad.settings.fontType": "ليکبڼې ډول:",
"pad.settings.fontType.normal": "نورمال",
"pad.settings.language": "ژبه:",
"pad.settings.about": "په‌اړه",
"pad.settings.poweredBy": "چلوونکی",
"pad.importExport.import_export": "رالېږدول/بهرلېږل",
"pad.importExport.importSuccessful": "بريالی شو!",
"pad.importExport.exportetherpad": "اېترپډ",
"pad.importExport.exporthtml": "اچ ټي ام اېل",
@ -39,6 +60,9 @@
"pad.importExport.exportpdf": "پي ډي اېف",
"pad.importExport.exportopen": "ODF (اوپن ډاکومنټ فارمټ)",
"pad.modals.connected": "اړيکمن شو.",
"pad.modals.forcereconnect": "په زوره بيانښلونه",
"pad.modals.reconnecttimer": "د بيانښلولو هڅه‌کول",
"pad.modals.cancel": "ناگارل",
"pad.modals.slowcommit.explanation": "پالنگر ځواب نه وايي.",
"pad.modals.slowcommit.cause": "دا کېدای شي د جال د اړيکتيايي ستونزو په سبب وي.",
"pad.modals.deleted": "ړنگ شو.",
@ -71,5 +95,6 @@
"pad.userlist.unnamed": "بې نومه",
"pad.impexp.importbutton": "اوس واردول",
"pad.impexp.importing": "په واردولو کې دی...",
"pad.impexp.uploadFailed": "راپورته‌کول نابرياله شول، مهرباني وکړئ بيا هڅه وکړئ.",
"pad.impexp.copypaste": "لطفاً لمېسل لېښل ترسره کړئ"
}

View file

@ -26,7 +26,7 @@
"pad.toolbar.embed.title": "ၽႄပၼ်ၽႅတ်ႉဢၼ်ၼႆႉသေ ၽိူမ်ႉပၼ်",
"pad.toolbar.showusers.title": "ၼႄပၼ်ၵေႃႉၸႂ်ႉ တီႈၼိူဝ်ၽႅတ်ႉၼႆႉ",
"pad.colorpicker.save": "ၵဵပ်းသိမ်း",
"pad.colorpicker.cancel": "ဢမ်ႇႁဵတ်း",
"pad.colorpicker.cancel": "ယႃႉၶိုၼ်း",
"pad.loading": "တိုၵ်ႉလူတ်ႇ",
"pad.noCookie": "ၶုၵ်းၶီး ဢမ်ႇႁၼ်လႆႈ။ ၶႅၼ်းတေႃႈ ၶႂၢင်းပၼ် ၶုၵ်းၶီး တီႈၼႂ်း ပရၢဝ်ႇသႃႇၸဝ်ႈၵဝ်ႇ",
"pad.permissionDenied": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇမီးၶေႃႈၶႂၢင်ႉ တႃႇၶဝ်ႈၼႂ်းၽႅတ်ႉၼႆႉ",
@ -54,7 +54,7 @@
"pad.modals.reconnecting": "ၶိုၼ်းၵွင်ႉသၢၼ်ၸူး ၽႅတ်ႉၸဝ်ႈၵဝ်ႇယူႇ",
"pad.modals.forcereconnect": "တဵၵ်းၸႂ်ႉ ၶိုၼ်းၵွင်ႉသၢၼ်",
"pad.modals.reconnecttimer": "ၶတ်းၸႂ်တူၺ်း တႃႇၶိုၼ်းၵွင်ႉသိုပ်ႇၸူး",
"pad.modals.cancel": "ဢမ်ႇႁဵတ်း",
"pad.modals.cancel": "ယႃႉၶိုၼ်း",
"pad.modals.userdup": "ပိုတ်ႇတမ်ႈတီႈ ၼႃႈတူမႂ်ႇ",
"pad.modals.userdup.explanation": "တမ်ႈတီႈၼႂ်းၶွမ်းတၢင်ႇဢၼ်ၼၼ်ႉ ၽႅတ်ႉဢၼ်ၼႆႉ လႅပ်ႉပိုတ်ႇဝႆႉ တမ်ႈတီႈ ပရၢဝ်ႇသႃႇတၢင်ႇတီႈယူႇ",
"pad.modals.userdup.advice": "ၶိုၼ်းၵွင်ႉသၢၼ်တၢင် တမ်ႈတီႈ ဝိၼ်းတူဝ်းၼႆႉ",
@ -71,14 +71,14 @@
"pad.modals.badChangeset.cause": "ၼႆႉမၼ်းၸၢင်ႈပဵၼ်ယွၼ်ႉပိူဝ်ႈ လွင်ႈၵုမ်းၵၢၼ်သႃႇပိူဝ်ႇ ၽိတ်းပိူင်ႈဝႆႉ ဢမ်ႇၼၼ် ပဵၼ်ယွၼ်ႉလွင်ႈဢၼ်ဢမ်ႇမုင်ႈမွင်းဝႆႉ။ သင်ၸိူဝ်ႉဝႃႈ ၸဝ်ႈၵဝ်ႇယိၼ်းဝႃႈပဵၼ်လွင်ႈၽိတ်းပိူင်ႈၼႆ ၶႅၼ်းတေႃႈၵပ်းသိုပ်ႇၸူးတင်း ၽူႈၵုမ်းၵၢၼ် ၵၢၼ်ၸွႆႈသၢင်ႈလႄႈ။ ၶိုၼ်းၶတ်းၸႂ်ၵွင်ႉသိုပ်ႇသေ တွၼ်ႈတႃႇ သိုပ်ႇႁဵတ်းလွင်ႈမႄးထတ်း။",
"pad.modals.corruptPad.explanation": "ၽႅတ်ႉဢၼ်ၸဝ်ႈၵဝ်ႇပေႃႉၼၼ်ႉ ၶဝ်ႈၽိတ်းဝႆႉ",
"pad.modals.corruptPad.cause": "ဢၼ်ၼႆႉ သႃႇဝႃႇဢၼ်ၸၼ်ထိင်းမၼ်း ၽိတ်းဝႆႉ ဢမ်ႇၼၼ် ဢမ်ႇမုင်ႈမွင်းသေ ၽိတ်းပိူင်ႈဝႆႉယဝ်ႉ။ ၶႅၼ်းတေႃႈ ၵပ်းသိုပ်ႇတမ်ႈတီႈ ၽူႈၵုမ်းၵၢၼ်.",
"pad.modals.deleted": "ယႃႉ",
"pad.modals.deleted": "မွတ်ႇပႅတ်ႈယဝ်ႉ။",
"pad.modals.deleted.explanation": "ၽႅတ်ႉဢၼ်ၼႆႉ ၶၢႆႉပႅတ်ႈယဝ်ႉ",
"pad.modals.disconnected": "ၸဝ်ႈၵဝ်ႇ ဢမ်ႇၵွင်ႉသၢၼ်ဝႆႉ",
"pad.modals.disconnected.explanation": "လွင်ႈၵွင်ႉသၢၼ် ၵႂႃႇၸူးသႃႇဝႃႇၼၼ်ႉ ႁၢႆဝႆႉ",
"pad.modals.disconnected.cause": "သႃႇဝႃႇတေဢမ်ႇၸၢင်ႈယိပ်းတိုဝ်း။ တႃႇႁႂ်ႈသိုပ်ႇပဵၼ်ၵၢၼ်ၵႂႃႇၼၼ်ႉ ၶႅၼ်းတေႃႈ ပွင်ႇၶၢဝ်ႇ တမ်ႈတီႈ ၽူႈၵုမ်းၵၢၼ်",
"pad.share": "ၽႄၽႅတ်ႉၼႆႉ",
"pad.share.readonly": "လူလၢႆလၢႆ",
"pad.share.link": "ၵွင်ႉ",
"pad.share.link": "လိင်ႉၶ်",
"pad.share.emebdcode": "သႂ်ႇ URL",
"pad.chat": "ၶျၢတ်ႉ",
"pad.chat.title": "ပိုတ်ႇၶျၢတ်ႉ တႃႇၽႅတ်ႉၼႆႉ",

View file

@ -49,7 +49,7 @@
"admin_settings.current_save.value": "Ayarları Kaydet",
"admin_settings.page-title": "Ayarlar - Etherpad",
"index.newPad": "Yeni Bloknot",
"index.createOpenPad": "veya şu adla bir Bloknot oluşturun/açın:",
"index.createOpenPad": "İsme göre açık bloknot",
"index.openPad": "şu adla varolan bir Bloknot'u açın:",
"pad.toolbar.bold.title": "Kalın (Ctrl+B)",
"pad.toolbar.italic.title": "Eğik (Ctrl+I)",

View file

@ -57,7 +57,7 @@ exports.expressCreateServer = (hookName: string, args: ArgsExpressType, cb: Func
}
// if is a directory search for index file matching the extension
if (fs.statSync(pathname).isDirectory()) {
if (exist && fs.statSync(pathname).isDirectory()) {
pathname = pathname + '/index.html';
ext = path.parse(pathname).ext;
}

View file

@ -251,6 +251,25 @@ exports.socketio = (hookName: string, {io}: any) => {
}
})
type PadCreationOptions = {
padName: string,
}
socket.on('createPad', async ({padName}: PadCreationOptions)=>{
const padExists = await padManager.doesPadExists(padName);
if (padExists) {
socket.emit('results:createPad', {
error: 'Pad already exists',
});
return;
}
padManager.getPad(padName);
socket.emit('results:createPad', {
success: `Pad created ${padName}`,
});
return;
})
socket.on('cleanupPadRevisions', async (padId: string) => {
if (!settings.cleanup.enabled) {
socket.emit('results:cleanupPadRevisions', {

View file

@ -13,8 +13,11 @@ const plugins = require('../../../static/js/pluginfw/plugin_defs');
import {build, buildSync} from 'esbuild'
import {ArgsExpressType} from "../../types/ArgsExpressType";
import prometheus from "../../prometheus";
let ioI: { sockets: { sockets: any[]; }; } | null = null
exports.socketio = (hookName: string, {io}: any) => {
ioI = io
}
@ -35,6 +38,12 @@ exports.expressPreSession = async (hookName:string, {app}:ArgsExpressType) => {
app.get('/stats', (req:any, res:any) => {
res.json(require('../../stats').toJSON());
});
app.get('/stats/prometheus', async (req, res) => {
const metrics = await prometheus()
res.setHeader('Content-Type', metrics.contentType)
res.send(await metrics.metrics())
})
}

11
src/node/metrics.ts Normal file
View file

@ -0,0 +1,11 @@
import Prometheus from 'prom-client';
export const metrics = {
'cpu': new Prometheus.Gauge({ name: 'nodejs_cpu_gauge', help: 'gauge for nodejs cpu' ,labelNames: ['type'] }),
'memory_process': new Prometheus.Gauge({ name: 'nodejs_memory_process_gauge', help: 'gauge for nodejs memory_process' ,labelNames: ['type'] }),
'memory_physical': new Prometheus.Gauge({ name: 'nodejs_memory_physical_gauge', help: 'gauge for nodejs_memory_physical' ,labelNames: ['type'] }),
'eventloop_latency': new Prometheus.Gauge({ name: 'nodejs_eventloop_latency_gauge' , help: 'gauge for nodejs_eventloop_latency' ,labelNames: ['type'] }),
'gc': new Prometheus.Gauge({ name: 'nodejs_gc_gauge' , help: 'gause for nodejs_gc' ,labelNames: ['type']}),
'gc_duration': new Prometheus.Summary({ name: 'nodejs_gc_duration' , help: 'gause for nodejs_gc_duration', percentiles: [ 0.5, 0.75, 0.95 ] }),
'http_duration': new Prometheus.Summary({ name: 'http_duration', help: 'summary for http_duration', percentiles: [ 0.5, 0.75, 0.95 ] ,labelNames: ['url'] })
};

25
src/node/prometheus.ts Normal file
View file

@ -0,0 +1,25 @@
import client from 'prom-client'
const db = require('./db/DB').db
const monitor = function () {
const collectDefaultMetrics = client.collectDefaultMetrics;
const Registry = client.Registry;
const register = new Registry();
collectDefaultMetrics({register});
const gaugeDB = new client.Gauge({
name: "ueberdb_stats",
help: "ueberdb stats",
labelNames: ['type'],
})
for (const [metric, value] of Object.entries(db.metrics)) {
if (typeof value !== 'number') continue;
gaugeDB.set({type: metric}, value);
}
register.registerMetric(gaugeDB);
return register
};
export default monitor;

View file

@ -25,7 +25,7 @@
export const argv: Record<string, string> = {};
const argvInternal = process.argv.slice(2);
let arg, prevArg;
let arg, prevArg = "";
// Loop through args
for (let i = 0; i < argvInternal.length; i++) {
@ -33,22 +33,26 @@ for (let i = 0; i < argvInternal.length; i++) {
// Override location of settings.json file
if (prevArg && prevArg === '--settings' || prevArg === '-s') {
console.log("Using specified settings from command line");
argv.settings = arg;
}
// Override location of credentials.json file
if (prevArg && prevArg === '--credentials') {
exports.argv.credentials = arg;
console.log("Using specified credentials from command line");
argv.credentials = arg;
}
// Override location of settings.json file
if (prevArg && prevArg === '--sessionkey') {
exports.argv.sessionkey = arg;
console.log("Using specified session key from command line");
argv.sessionkey = arg;
}
// Override location of APIKEY.txt file
if (prevArg && prevArg === '--apikey') {
exports.argv.apikey = arg;
console.log("Using specified API key from command line");
argv.apikey = arg;
}
prevArg = arg;

View file

@ -31,21 +31,21 @@
],
"dependencies": {
"async": "^3.2.6",
"axios": "^1.11.0",
"axios": "^1.12.1",
"cookie-parser": "^1.4.7",
"cross-env": "^10.0.0",
"cross-env": "^10.1.0",
"cross-spawn": "^7.0.6",
"ejs": "^3.1.10",
"esbuild": "^0.25.9",
"esbuild": "^0.25.10",
"express": "^5.1.0",
"express-rate-limit": "^8.0.1",
"express-rate-limit": "^8.1.0",
"express-session": "^1.18.2",
"find-root": "1.1.0",
"formidable": "^3.5.4",
"http-errors": "^2.0.0",
"jose": "^6.0.13",
"jose": "^6.1.0",
"js-cookie": "^3.0.5",
"jsdom": "^26.1.0",
"jsdom": "^27.0.0",
"jsonminify": "0.4.2",
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^4.0.0",
@ -53,36 +53,37 @@
"live-plugin-manager": "^1.1.0",
"lodash.clonedeep": "4.5.0",
"log4js": "^6.9.1",
"lru-cache": "^11.1.0",
"lru-cache": "^11.2.2",
"measured-core": "^2.0.0",
"mime-types": "^3.0.1",
"oidc-provider": "^9.4.2",
"oidc-provider": "^9.5.1",
"openapi-backend": "^5.15.0",
"prom-client": "^15.1.3",
"proxy-addr": "^2.0.7",
"rate-limiter-flexible": "^7.2.0",
"rate-limiter-flexible": "^8.0.1",
"rehype": "^13.0.2",
"rehype-minify-whitespace": "^6.0.2",
"resolve": "1.22.10",
"rusty-store-kv": "^1.3.1",
"security": "1.0.0",
"semver": "^7.7.2",
"semver": "^7.7.3",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"superagent": "10.2.3",
"swagger-ui-express": "^5.0.1",
"tinycon": "0.6.8",
"tsx": "4.20.5",
"ueberdb2": "^5.0.15",
"tsx": "4.20.6",
"ueberdb2": "^5.0.22",
"underscore": "1.13.7",
"unorm": "1.6.0",
"wtfnode": "^0.10.0"
"wtfnode": "^0.10.1"
},
"bin": {
"etherpad-healthcheck": "../bin/etherpad-healthcheck",
"etherpad-lite": "node/server.ts"
},
"devDependencies": {
"@playwright/test": "^1.55.0",
"@playwright/test": "^1.56.0",
"@types/async": "^3.2.25",
"@types/cookie-parser": "^1.4.9",
"@types/cross-spawn": "^6.0.6",
@ -93,24 +94,24 @@
"@types/http-errors": "^2.0.5",
"@types/jquery": "^3.5.33",
"@types/js-cookie": "^3.0.6",
"@types/jsdom": "^21.1.7",
"@types/jsdom": "^27.0.0",
"@types/jsonminify": "^0.4.3",
"@types/jsonwebtoken": "^9.0.10",
"@types/mime-types": "^3.0.1",
"@types/mocha": "^10.0.9",
"@types/node": "^24.3.0",
"@types/oidc-provider": "^9.1.2",
"@types/semver": "^7.7.0",
"@types/node": "^24.7.0",
"@types/oidc-provider": "^9.5.0",
"@types/semver": "^7.7.1",
"@types/sinon": "^17.0.3",
"@types/supertest": "^6.0.2",
"@types/swagger-ui-express": "^4.1.8",
"@types/underscore": "^1.13.0",
"@types/whatwg-mimetype": "^3.0.2",
"chokidar": "^4.0.3",
"eslint": "^9.33.0",
"eslint": "^9.37.0",
"eslint-config-etherpad": "^4.0.4",
"etherpad-cli-client": "^3.0.4",
"mocha": "^11.7.1",
"etherpad-cli-client": "^3.0.5",
"mocha": "^11.7.4",
"mocha-froth": "^0.2.10",
"nodeify": "^1.0.1",
"openapi-schema-validation": "^0.4.2",
@ -118,7 +119,7 @@
"sinon": "^21.0.0",
"split-grid": "^1.0.11",
"supertest": "^7.1.3",
"typescript": "^5.9.2",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
},
"engines": {
@ -146,6 +147,6 @@
"debug:socketio": "cross-env DEBUG=socket.io* node --require tsx/cjs node/server.ts",
"test:vitest": "vitest"
},
"version": "2.5.0",
"version": "2.5.1",
"license": "Apache-2.0"
}

View file

@ -480,7 +480,12 @@ const pad = {
setTimeout(() => { checkChatAndUsersVisibility(mobileMatch); }, 0); // check now after load
$('#editorcontainer').addClass('initialized');
if (window.location.hash.toLowerCase() !== '#skinvariantsbuilder' && window.clientVars.enableDarkMode && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
if (window.clientVars.enableDarkMode) {
$('#theme-switcher').attr('style', 'display: flex;');
}
if (window.location.hash.toLowerCase() !== '#skinvariantsbuilder' && window.clientVars.enableDarkMode && (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) && !skinVariants.isWhiteModeEnabledInLocalStorage()) {
skinVariants.updateSkinVariantsClasses(['super-dark-editor', 'dark-background', 'super-dark-toolbar']);
}

View file

@ -26,6 +26,7 @@ import padutils,{Cookies} from "./pad_utils";
const padcookie = require('./pad_cookie').padcookie;
const Ace2Editor = require('./ace').Ace2Editor;
import html10n from '../js/vendors/html10n'
const skinVariants = require('./skin_variants');
const padeditor = (() => {
let pad = undefined;
@ -86,11 +87,22 @@ const padeditor = (() => {
$('#delete-pad').on('click', () => {
if (window.confirm(html10n.get('pad.delete.confirm'))) {
pad.collabClient.sendMessage({type: 'PAD_DELETE', data:{padId: pad.getPadId()}});
// redirect to home page after deletion
// redirect to home page after deletion
window.location.href = '/';
}
})
// theme switch
$('#theme-switcher').on('click',()=>{
if (skinVariants.isDarkMode()) {
skinVariants.setDarkModeInLocalStorage(false);
skinVariants.updateSkinVariantsClasses(['super-light-toolbar super-light-editor light-background']);
} else {
skinVariants.setDarkModeInLocalStorage(true);
skinVariants.updateSkinVariantsClasses(['super-dark-editor', 'dark-background', 'super-dark-toolbar']);
}
})
// Language
html10n.bind('localized', () => {
$('#languagemenu').val(html10n.getLanguage());

View file

@ -23,6 +23,24 @@ const updateSkinVariantsClasses = (newClasses) => {
domsToUpdate.forEach((el) => { el.addClass(newClasses.join(' ')); });
};
const isDarkMode = ()=>{
return $('html').hasClass('super-dark-editor')
}
const setDarkModeInLocalStorage = (isDark)=>{
localStorage.setItem('ep_darkMode', isDark?'true':'false');
}
const isDarkModeEnabledInLocalStorage = ()=>{
return localStorage.getItem('ep_darkMode')==='true';
}
const isWhiteModeEnabledInLocalStorage = ()=>{
return localStorage.getItem('ep_darkMode')==='false';
}
// Specific hash to display the skin variants builder popup
if (window.location.hash.toLowerCase() === '#skinvariantsbuilder') {
$('#skin-variants').addClass('popup-show');
@ -60,4 +78,8 @@ if (window.location.hash.toLowerCase() === '#skinvariantsbuilder') {
updateSkinVariantsClasses(getNewClasses());
}
exports.isDarkMode = isDarkMode;
exports.setDarkModeInLocalStorage = setDarkModeInLocalStorage
exports.isWhiteModeEnabledInLocalStorage = isWhiteModeEnabledInLocalStorage
exports.isDarkModeEnabledInLocalStorage = isDarkModeEnabledInLocalStorage
exports.updateSkinVariantsClasses = updateSkinVariantsClasses;

View file

@ -85,3 +85,43 @@
#delete-pad {
background-color: #ff7b72;
}
#theme-switcher div {
position: relative;
width: 30px;
background-color: white;
height: 10px;
border-radius: 5px;
align-self: center;
}
#theme-switcher {
display: flex;
margin-top: 20px;
flex-direction: row;
}
#theme-switcher div span {
width: 15px;
display: block;
height: 15px;
border-radius: 20px;
position: absolute;
top: -2px;
background-color: white;
transition: background-color 0.25s;
}
html.super-light-editor #theme-switcher div {
background-color: #ccc;
}
html.super-light-editor #theme-switcher div span {
left: 0;
background-color: var(--primary-color);;
}
html.super-dark-editor #theme-switcher div span {
right: 0;
background-color: var(--primary-color);;
}

View file

@ -164,11 +164,23 @@
<% e.end_block(); %>
</div>
<button data-l10n-id="pad.settings.deletePad" id="delete-pad">Delete pad</button>
<h2 data-l10n-id="pad.settings.about">About</h2>
<div id="theme-switcher" style="display: none;">
<svg width="2rem" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" />
</svg>
<div>
<span aria-label="theme-switcher-knob"></span>
</div>
<svg width="2rem" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" />
</svg>
</div>
<h2 data-l10n-id="pad.settings.about">About</h2>
<span data-l10n-id="pad.settings.poweredBy">Powered by</span>
<a href="https://etherpad.org" target="_blank" referrerpolicy="no-referrer" rel="noopener">Etherpad</a>
<% if (settings.exposeVersion) { %>(commit <%=settings.gitVersion()%>)<% } %>
</div></div>
<% if (settings.exposeVersion) { %>(commit <%= settings.gitVersion %>)<% } %> </div></div>
<!------------------------->

View file

@ -11,7 +11,10 @@
},
"devDependencies": {
"ep_etherpad-lite": "workspace:../src",
"typescript": "^5.9.2",
"vite": "^7.1.3"
"typescript": "^5.9.3",
"vite": "npm:rolldown-vite@latest"
},
"overrides": {
"vite": "npm:rolldown-vite@latest"
}
}

View file

@ -9,7 +9,7 @@ export default defineConfig({
transformMixedEsModules: true,
},
outDir: resolve(__dirname, '../src/static/oidc'),
rollupOptions: {
rolldownOptions: {
input: {
main: resolve(__dirname, 'consent.html'),
nested: resolve(__dirname, 'login.html'),