Merge branch 'develop'
This commit is contained in:
commit
8a7dfce330
421 changed files with 18315 additions and 16207 deletions
|
@ -24,3 +24,4 @@ Dockerfile
|
||||||
|
|
||||||
settings.json
|
settings.json
|
||||||
src/node_modules
|
src/node_modules
|
||||||
|
admin/node_modules
|
||||||
|
|
18
.env.default
Normal file
18
.env.default
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Please copy and rename this file.
|
||||||
|
#
|
||||||
|
# !Attention!
|
||||||
|
# Always ensure to load the env variables in every terminal session.
|
||||||
|
# Otherwise the env variables will not be available
|
||||||
|
|
||||||
|
DOCKER_COMPOSE_APP_DEV_PORT_PUBLISHED=9001
|
||||||
|
DOCKER_COMPOSE_APP_DEV_PORT_TARGET=9001
|
||||||
|
|
||||||
|
# IMPORTANT: When the env var DEFAULT_PAD_TEXT is unset or empty, then the pad is not established (not the landing page).
|
||||||
|
# The env var DEFAULT_PAD_TEXT seems to be mandatory in the latest version of etherpad.
|
||||||
|
DOCKER_COMPOSE_APP_DEV_ENV_DEFAULT_PAD_TEXT="Welcome to etherpad"
|
||||||
|
|
||||||
|
DOCKER_COMPOSE_APP_DEV_ADMIN_PASSWORD=
|
||||||
|
|
||||||
|
DOCKER_COMPOSE_POSTGRES_DEV_ENV_POSTGRES_DATABASE=db
|
||||||
|
DOCKER_COMPOSE_POSTGRES_DEV_ENV_POSTGRES_PASSWORD=etherpad-lite-password
|
||||||
|
DOCKER_COMPOSE_POSTGRES_DEV_ENV_POSTGRES_USER=etherpad-lite-user
|
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
|
@ -14,8 +14,3 @@ updates:
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
versioning-strategy: "increase"
|
versioning-strategy: "increase"
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/src/bin/doc"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
versioning-strategy: "increase"
|
|
||||||
|
|
165
.github/workflows/backend-tests.yml
vendored
165
.github/workflows/backend-tests.yml
vendored
|
@ -27,22 +27,42 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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 libreoffice
|
name: Install libreoffice
|
||||||
run: |
|
uses: awalsh128/cache-apt-pkgs-action@v1.4.2
|
||||||
sudo add-apt-repository -y ppa:libreoffice/ppa
|
with:
|
||||||
sudo apt update
|
packages: libreoffice libreoffice-pdfimport
|
||||||
sudo apt install -y --no-install-recommends libreoffice libreoffice-pdfimport
|
version: 1.0
|
||||||
-
|
-
|
||||||
name: Install all dependencies and symlink for ep_etherpad-lite
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
|
- name: Install admin ui
|
||||||
|
working-directory: admin
|
||||||
|
run: pnpm install
|
||||||
|
- name: Build admin ui
|
||||||
|
working-directory: admin
|
||||||
|
run: pnpm build
|
||||||
-
|
-
|
||||||
name: Run the backend tests
|
name: Run the backend tests
|
||||||
run: cd src && npm test
|
run: pnpm test
|
||||||
|
|
||||||
withpluginsLinux:
|
withpluginsLinux:
|
||||||
# run on pushes to any branch
|
# run on pushes to any branch
|
||||||
|
@ -64,22 +84,43 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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 libreoffice
|
name: Install libreoffice
|
||||||
run: |
|
uses: awalsh128/cache-apt-pkgs-action@v1.4.2
|
||||||
sudo add-apt-repository -y ppa:libreoffice/ppa
|
with:
|
||||||
sudo apt update
|
packages: libreoffice libreoffice-pdfimport
|
||||||
sudo apt install -y --no-install-recommends libreoffice libreoffice-pdfimport
|
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
|
||||||
|
- name: Build admin ui
|
||||||
|
working-directory: admin
|
||||||
|
run: pnpm build
|
||||||
-
|
-
|
||||||
name: Install Etherpad plugins
|
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: >
|
run: >
|
||||||
npm install --no-save --legacy-peer-deps
|
pnpm install --workspace-root
|
||||||
ep_align
|
ep_align
|
||||||
ep_author_hover
|
ep_author_hover
|
||||||
ep_cursortrace
|
ep_cursortrace
|
||||||
|
@ -93,21 +134,9 @@ jobs:
|
||||||
ep_spellcheck
|
ep_spellcheck
|
||||||
ep_subscript_and_superscript
|
ep_subscript_and_superscript
|
||||||
ep_table_of_contents
|
ep_table_of_contents
|
||||||
# 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
|
|
||||||
# in the top-level node_modules. As of v6.14.10, npm's hoist logic appears
|
|
||||||
# to be buggy, because it sometimes removes dependencies from
|
|
||||||
# src/node_modules but fails to add them to the top-level node_modules.
|
|
||||||
# Even if npm correctly hoists the dependencies, the hoisting seems to
|
|
||||||
# confuse tools such as `npm outdated`, `npm update`, and some ESLint
|
|
||||||
# rules.
|
|
||||||
-
|
|
||||||
name: Install all dependencies and symlink for ep_etherpad-lite
|
|
||||||
run: src/bin/installDeps.sh
|
|
||||||
-
|
-
|
||||||
name: Run the backend tests
|
name: Run the backend tests
|
||||||
run: cd src && npm test
|
run: pnpm test
|
||||||
|
|
||||||
withoutpluginsWindows:
|
withoutpluginsWindows:
|
||||||
# run on pushes to any branch
|
# run on pushes to any branch
|
||||||
|
@ -125,13 +154,33 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installOnWindows.bat
|
run: bin/installOnWindows.bat
|
||||||
|
- name: Install admin ui
|
||||||
|
working-directory: admin
|
||||||
|
run: pnpm install
|
||||||
|
- name: Build admin ui
|
||||||
|
working-directory: admin
|
||||||
|
run: pnpm build
|
||||||
-
|
-
|
||||||
name: Fix up the settings.json
|
name: Fix up the settings.json
|
||||||
run: |
|
run: |
|
||||||
|
@ -139,7 +188,7 @@ jobs:
|
||||||
powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json"
|
powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json"
|
||||||
-
|
-
|
||||||
name: Run the backend tests
|
name: Run the backend tests
|
||||||
run: cd src && npm test
|
run: cd src && pnpm test
|
||||||
|
|
||||||
withpluginsWindows:
|
withpluginsWindows:
|
||||||
# run on pushes to any branch
|
# run on pushes to any branch
|
||||||
|
@ -157,17 +206,37 @@ jobs:
|
||||||
-
|
-
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 21
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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 admin ui
|
||||||
|
working-directory: admin
|
||||||
|
run: pnpm install
|
||||||
|
- name: Build admin ui
|
||||||
|
working-directory: admin
|
||||||
|
run: pnpm build
|
||||||
-
|
-
|
||||||
name: Install Etherpad plugins
|
name: Install Etherpad plugins
|
||||||
# The --legacy-peer-deps flag is required to work around a bug in npm
|
# The --legacy-peer-deps flag is required to work around a bug in npm
|
||||||
# v7: https://github.com/npm/cli/issues/2199
|
# v7: https://github.com/npm/cli/issues/2199
|
||||||
run: >
|
run: >
|
||||||
npm install --no-save --legacy-peer-deps
|
pnpm install --workspace-root
|
||||||
ep_align
|
ep_align
|
||||||
ep_author_hover
|
ep_author_hover
|
||||||
ep_cursortrace
|
ep_cursortrace
|
||||||
|
@ -192,7 +261,7 @@ jobs:
|
||||||
# rules.
|
# rules.
|
||||||
-
|
-
|
||||||
name: Install all dependencies and symlink for ep_etherpad-lite
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installOnWindows.bat
|
run: bin/installOnWindows.bat
|
||||||
-
|
-
|
||||||
name: Fix up the settings.json
|
name: Fix up the settings.json
|
||||||
run: |
|
run: |
|
||||||
|
@ -200,4 +269,4 @@ jobs:
|
||||||
powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json"
|
powershell -Command "(gc settings.json.holder) -replace '\"points\": 10', '\"points\": 1000' | Out-File -encoding ASCII settings.json"
|
||||||
-
|
-
|
||||||
name: Run the backend tests
|
name: Run the backend tests
|
||||||
run: cd src && npm test
|
run: cd src && pnpm test
|
||||||
|
|
26
.github/workflows/docker.yml
vendored
26
.github/workflows/docker.yml
vendored
|
@ -30,6 +30,7 @@ jobs:
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
target: production
|
||||||
load: true
|
load: true
|
||||||
tags: ${{ env.TEST_TAG }}
|
tags: ${{ env.TEST_TAG }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
|
@ -39,16 +40,28 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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: Test
|
name: Test
|
||||||
run: |
|
run: |
|
||||||
docker run --rm -d -p 9001:9001 --name test ${{ env.TEST_TAG }}
|
docker run --rm -d -p 9001:9001 --name test ${{ env.TEST_TAG }}
|
||||||
|
./bin/installDeps.sh
|
||||||
docker logs -f test &
|
docker logs -f test &
|
||||||
./src/bin/installDeps.sh
|
|
||||||
while true; do
|
while true; do
|
||||||
echo "Waiting for Docker container to start..."
|
echo "Waiting for Docker container to start..."
|
||||||
status=$(docker container inspect -f '{{.State.Health.Status}}' test) || exit 1
|
status=$(docker container inspect -f '{{.State.Health.Status}}' test) || exit 1
|
||||||
|
@ -58,7 +71,7 @@ jobs:
|
||||||
*) printf %s\\n "unexpected status: ${status}" >&2; exit 1;;
|
*) printf %s\\n "unexpected status: ${status}" >&2; exit 1;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
(cd src && npm run test-container)
|
(cd src && pnpm run test-container)
|
||||||
git clean -dxf .
|
git clean -dxf .
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
|
@ -85,6 +98,7 @@ jobs:
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
target: production
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
|
125
.github/workflows/frontend-admin-tests.yml
vendored
125
.github/workflows/frontend-admin-tests.yml
vendored
|
@ -12,11 +12,10 @@ jobs:
|
||||||
name: with plugins
|
name: with plugins
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
# node: [16, 19, 20] >> Disabled node 16 and 18 because they do not work
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node: [19, 20, 21]
|
node: [20, 21]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
|
@ -32,16 +31,30 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
-
|
run_install: false
|
||||||
name: Install etherpad plugins
|
- name: Get pnpm store directory
|
||||||
# We intentionally install an old ep_align version to test upgrades to
|
shell: bash
|
||||||
# the minor version number. The --legacy-peer-deps flag is required to
|
run: |
|
||||||
# work around a bug in npm v7: https://github.com/npm/cli/issues/2199
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
run: npm install --no-save --legacy-peer-deps ep_align@0.2.27
|
- 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 etherpad plugins
|
||||||
|
# # We intentionally install an old ep_align version to test upgrades to
|
||||||
|
# # the minor version number. 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 ep_align@0.2.27
|
||||||
# Etherpad core dependencies must be installed after installing the
|
# Etherpad core dependencies must be installed after installing the
|
||||||
# plugin's dependencies, otherwise npm will try to hoist common
|
# plugin's dependencies, otherwise npm will try to hoist common
|
||||||
# dependencies by removing them from src/node_modules and installing them
|
# dependencies by removing them from src/node_modules and installing them
|
||||||
|
@ -53,10 +66,10 @@ jobs:
|
||||||
# rules.
|
# rules.
|
||||||
-
|
-
|
||||||
name: Install all dependencies and symlink for ep_etherpad-lite
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
#-
|
||||||
name: Install etherpad plugins
|
# name: Install etherpad plugins
|
||||||
run: rm -Rf node_modules/ep_align/static/tests/*
|
# run: rm -Rf node_modules/ep_align/static/tests/*
|
||||||
-
|
-
|
||||||
name: export GIT_HASH to env
|
name: export GIT_HASH to env
|
||||||
id: environment
|
id: environment
|
||||||
|
@ -66,31 +79,67 @@ jobs:
|
||||||
run: cp settings.json.template settings.json
|
run: cp settings.json.template settings.json
|
||||||
-
|
-
|
||||||
name: Write custom settings.json that enables the Admin UI tests
|
name: Write custom settings.json that enables the Admin UI tests
|
||||||
run: "sed -i 's/\"enableAdminUITests\": false/\"enableAdminUITests\": true,\\n\"users\":{\"admin\":{\"password\":\"changeme\",\"is_admin\":true}}/' settings.json"
|
run: "sed -i 's/\"enableAdminUITests\": false/\"enableAdminUITests\": true,\\n\"users\":{\"admin\":{\"password\":\"changeme1\",\"is_admin\":true}}/' settings.json"
|
||||||
-
|
-
|
||||||
name: increase maxHttpBufferSize
|
name: increase maxHttpBufferSize
|
||||||
run: "sed -i 's/\"maxHttpBufferSize\": 10000/\"maxHttpBufferSize\": 100000/' settings.json"
|
run: "sed -i 's/\"maxHttpBufferSize\": 10000/\"maxHttpBufferSize\": 10000000/' settings.json"
|
||||||
-
|
-
|
||||||
name: Disable import/export rate limiting
|
name: Disable import/export rate limiting
|
||||||
run: |
|
run: |
|
||||||
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 1000000/' -i settings.json
|
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 100000000/' -i settings.json
|
||||||
-
|
- name: Build admin frontend
|
||||||
name: Remove standard frontend test files, so only admin tests are run
|
working-directory: admin
|
||||||
run: mv src/tests/frontend/specs/* /tmp && mv /tmp/admin*.js src/tests/frontend/specs
|
|
||||||
-
|
|
||||||
uses: saucelabs/sauce-connect-action@v2.3.6
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.SAUCE_USERNAME }}
|
|
||||||
accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
|
|
||||||
tunnelIdentifier: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
|
||||||
-
|
|
||||||
name: Run the frontend admin tests
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
|
||||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
|
||||||
SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
|
||||||
TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
|
||||||
GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
|
||||||
run: |
|
run: |
|
||||||
src/tests/frontend/travis/adminrunner.sh
|
pnpm install
|
||||||
|
pnpm run build
|
||||||
|
# name: Run the frontend admin tests
|
||||||
|
# shell: bash
|
||||||
|
# env:
|
||||||
|
# SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
||||||
|
# SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||||
|
# SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
||||||
|
# TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||||
|
# GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
||||||
|
# run: |
|
||||||
|
# src/tests/frontend/travis/adminrunner.sh
|
||||||
|
#-
|
||||||
|
# uses: saucelabs/sauce-connect-action@v2.3.6
|
||||||
|
# with:
|
||||||
|
# username: ${{ secrets.SAUCE_USERNAME }}
|
||||||
|
# accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||||
|
# tunnelIdentifier: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||||
|
#-
|
||||||
|
# name: Run the frontend admin tests
|
||||||
|
# shell: bash
|
||||||
|
# env:
|
||||||
|
# SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
||||||
|
# SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||||
|
# SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
||||||
|
# TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||||
|
# GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
||||||
|
# run: |
|
||||||
|
# src/tests/frontend/travis/adminrunner.sh
|
||||||
|
- name: Run the frontend admin tests
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
pnpm run dev &
|
||||||
|
connected=false
|
||||||
|
can_connect() {
|
||||||
|
curl -sSfo /dev/null http://localhost:9001/ || return 1
|
||||||
|
connected=true
|
||||||
|
}
|
||||||
|
now() { date +%s; }
|
||||||
|
start=$(now)
|
||||||
|
while [ $(($(now) - $start)) -le 15 ] && ! can_connect; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
cd src
|
||||||
|
pnpm exec playwright install
|
||||||
|
pnpm exec playwright install-deps
|
||||||
|
pnpm run test-admin
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-report-${{ matrix.node }}
|
||||||
|
path: src/playwright-report/
|
||||||
|
retention-days: 30
|
||||||
|
|
295
.github/workflows/frontend-tests.yml
vendored
295
.github/workflows/frontend-tests.yml
vendored
|
@ -7,10 +7,141 @@ permissions:
|
||||||
contents: read # to fetch code (actions/checkout)
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
withoutplugins:
|
playwright-chrome:
|
||||||
name: without plugins
|
name: Playwright Chrome
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Generate Sauce Labs strings
|
||||||
|
id: sauce_strings
|
||||||
|
run: |
|
||||||
|
printf %s\\n '::set-output name=name::${{ github.workflow }} - ${{ github.job }}'
|
||||||
|
printf %s\\n '::set-output name=tunnel_id::${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}'
|
||||||
|
-
|
||||||
|
name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
-
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 21
|
||||||
|
- uses: pnpm/action-setup@v3
|
||||||
|
name: Install pnpm
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
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') }}
|
||||||
|
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
|
||||||
|
run: bin/installDeps.sh
|
||||||
|
-
|
||||||
|
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: Run the frontend tests
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
pnpm run dev &
|
||||||
|
connected=false
|
||||||
|
can_connect() {
|
||||||
|
curl -sSfo /dev/null http://localhost:9001/ || return 1
|
||||||
|
connected=true
|
||||||
|
}
|
||||||
|
now() { date +%s; }
|
||||||
|
start=$(now)
|
||||||
|
while [ $(($(now) - $start)) -le 15 ] && ! can_connect; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
cd src
|
||||||
|
pnpm exec playwright install chromium --with-deps
|
||||||
|
pnpm run test-ui --project=chromium
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-report-${{ matrix.node }}-chrome
|
||||||
|
path: src/playwright-report/
|
||||||
|
retention-days: 30
|
||||||
|
playwright-firefox:
|
||||||
|
name: Playwright Firefox
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Generate Sauce Labs strings
|
||||||
|
id: sauce_strings
|
||||||
|
run: |
|
||||||
|
printf %s\\n '::set-output name=name::${{ github.workflow }} - ${{ github.job }}'
|
||||||
|
printf %s\\n '::set-output name=tunnel_id::${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}'
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 21
|
||||||
|
- uses: pnpm/action-setup@v3
|
||||||
|
name: Install pnpm
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
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') }}
|
||||||
|
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
|
||||||
|
run: bin/installDeps.sh
|
||||||
|
- 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: Run the frontend tests
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
pnpm run dev &
|
||||||
|
connected=false
|
||||||
|
can_connect() {
|
||||||
|
curl -sSfo /dev/null http://localhost:9001/ || return 1
|
||||||
|
connected=true
|
||||||
|
}
|
||||||
|
now() { date +%s; }
|
||||||
|
start=$(now)
|
||||||
|
while [ $(($(now) - $start)) -le 15 ] && ! can_connect; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
cd src
|
||||||
|
pnpm exec playwright install firefox --with-deps
|
||||||
|
pnpm run test-ui --project=firefox
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-report-${{ matrix.node }}-firefox
|
||||||
|
path: src/playwright-report/
|
||||||
|
retention-days: 30
|
||||||
|
playwright-webkit:
|
||||||
|
name: Playwright Webkit
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.actor != 'dependabot[bot]' }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
|
@ -25,127 +156,59 @@ jobs:
|
||||||
-
|
-
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 21
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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') }}
|
||||||
|
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
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
-
|
||||||
name: export GIT_HASH to env
|
name: export GIT_HASH to env
|
||||||
id: environment
|
id: environment
|
||||||
run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})"
|
run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})"
|
||||||
-
|
-
|
||||||
name: Create settings.json
|
name: Create settings.json
|
||||||
run: cp settings.json.template settings.json
|
run: cp ./src/tests/settings.json settings.json
|
||||||
-
|
- name: Run the frontend tests
|
||||||
name: Disable import/export rate limiting
|
|
||||||
run: |
|
|
||||||
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 100000000/' -i settings.json
|
|
||||||
-
|
|
||||||
uses: saucelabs/sauce-connect-action@v2.3.6
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.SAUCE_USERNAME }}
|
|
||||||
accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
|
|
||||||
tunnelIdentifier: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
|
||||||
-
|
|
||||||
name: Run the frontend tests
|
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
|
||||||
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
|
||||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
|
||||||
SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
|
||||||
TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
|
||||||
GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
|
||||||
run: |
|
run: |
|
||||||
src/tests/frontend/travis/runner.sh
|
pnpm run dev &
|
||||||
|
connected=false
|
||||||
withplugins:
|
can_connect() {
|
||||||
name: with plugins
|
curl -sSfo /dev/null http://localhost:9001/ || return 1
|
||||||
runs-on: ubuntu-latest
|
connected=true
|
||||||
if: ${{ github.actor != 'dependabot[bot]' }}
|
}
|
||||||
|
now() { date +%s; }
|
||||||
steps:
|
start=$(now)
|
||||||
-
|
while [ $(($(now) - $start)) -le 15 ] && ! can_connect; do
|
||||||
name: Generate Sauce Labs strings
|
sleep 1
|
||||||
id: sauce_strings
|
done
|
||||||
run: |
|
cd src
|
||||||
printf %s\\n '::set-output name=name::${{ github.workflow }} - ${{ github.job }}'
|
pnpm exec playwright install webkit --with-deps
|
||||||
printf %s\\n '::set-output name=tunnel_id::${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}'
|
pnpm run test-ui --project=webkit || true
|
||||||
-
|
- uses: actions/upload-artifact@v4
|
||||||
name: Checkout repository
|
if: always()
|
||||||
uses: actions/checkout@v4
|
|
||||||
-
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
name: playwright-report-${{ matrix.node }}-webkit
|
||||||
cache: 'npm'
|
path: src/playwright-report/
|
||||||
cache-dependency-path: |
|
retention-days: 30
|
||||||
src/package-lock.json
|
|
||||||
src/bin/doc/package-lock.json
|
|
||||||
-
|
|
||||||
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: >
|
|
||||||
npm install --no-save --legacy-peer-deps
|
|
||||||
ep_align
|
|
||||||
ep_author_hover
|
|
||||||
ep_cursortrace
|
|
||||||
ep_embedmedia
|
|
||||||
ep_font_size
|
|
||||||
ep_hash_auth
|
|
||||||
ep_headings2
|
|
||||||
ep_image_upload
|
|
||||||
ep_markdown
|
|
||||||
ep_readonly_guest
|
|
||||||
ep_set_title_on_pad
|
|
||||||
ep_spellcheck
|
|
||||||
ep_subscript_and_superscript
|
|
||||||
ep_table_of_contents
|
|
||||||
# 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
|
|
||||||
# in the top-level node_modules. As of v6.20.10, npm's hoist logic appears
|
|
||||||
# to be buggy, because it sometimes removes dependencies from
|
|
||||||
# src/node_modules but fails to add them to the top-level node_modules.
|
|
||||||
# Even if npm correctly hoists the dependencies, the hoisting seems to
|
|
||||||
# confuse tools such as `npm outdated`, `npm update`, and some ESLint
|
|
||||||
# rules.
|
|
||||||
-
|
|
||||||
name: Install all dependencies and symlink for ep_etherpad-lite
|
|
||||||
run: src/bin/installDeps.sh
|
|
||||||
-
|
|
||||||
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 settings.json.template settings.json
|
|
||||||
-
|
|
||||||
name: Disable import/export rate limiting
|
|
||||||
run: |
|
|
||||||
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 1000000/' -i settings.json
|
|
||||||
# XXX we should probably run all tests, because plugins could effect their results
|
|
||||||
-
|
|
||||||
name: Remove standard frontend test files, so only plugin tests are run
|
|
||||||
run: rm src/tests/frontend/specs/*
|
|
||||||
-
|
|
||||||
uses: saucelabs/sauce-connect-action@v2.3.6
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.SAUCE_USERNAME }}
|
|
||||||
accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
|
|
||||||
tunnelIdentifier: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
|
||||||
-
|
|
||||||
name: Run the frontend tests
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
|
||||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
|
||||||
SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
|
||||||
TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
|
||||||
GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
|
||||||
run: |
|
|
||||||
src/tests/frontend/travis/runner.sh
|
|
||||||
|
|
7
.github/workflows/lint-package-lock.yml
vendored
7
.github/workflows/lint-package-lock.yml
vendored
|
@ -23,13 +23,6 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: |
|
|
||||||
src/package-lock.json
|
|
||||||
src/bin/doc/package-lock.json
|
|
||||||
-
|
|
||||||
name: Install lockfile-lint
|
|
||||||
run: npm install --no-save lockfile-lint --legacy-peer-deps
|
|
||||||
-
|
-
|
||||||
name: Run lockfile-lint on package-lock.json
|
name: Run lockfile-lint on package-lock.json
|
||||||
run: >
|
run: >
|
||||||
|
|
80
.github/workflows/load-test.yml
vendored
80
.github/workflows/load-test.yml
vendored
|
@ -23,16 +23,30 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
-
|
||||||
name: Install etherpad-load-test
|
name: Install etherpad-load-test
|
||||||
run: sudo npm install -g etherpad-load-test
|
run: sudo npm install -g etherpad-load-test-socket-io
|
||||||
-
|
-
|
||||||
name: Run load test
|
name: Run load test
|
||||||
run: src/tests/frontend/travis/runnerLoadTest.sh 25 50
|
run: src/tests/frontend/travis/runnerLoadTest.sh 25 50
|
||||||
|
@ -53,19 +67,33 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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 etherpad-load-test
|
name: Install etherpad-load-test
|
||||||
run: sudo npm install -g etherpad-load-test
|
run: pnpm install -g etherpad-load-test-socket-io
|
||||||
-
|
-
|
||||||
name: Install etherpad plugins
|
name: Install etherpad plugins
|
||||||
# The --legacy-peer-deps flag is required to work around a bug in npm v7:
|
# The --legacy-peer-deps flag is required to work around a bug in npm v7:
|
||||||
# https://github.com/npm/cli/issues/2199
|
# https://github.com/npm/cli/issues/2199
|
||||||
run: >
|
run: >
|
||||||
npm install --no-save --legacy-peer-deps
|
pnpm install --workspace-root
|
||||||
ep_align
|
ep_align
|
||||||
ep_author_hover
|
ep_author_hover
|
||||||
ep_cursortrace
|
ep_cursortrace
|
||||||
|
@ -89,7 +117,7 @@ jobs:
|
||||||
# rules.
|
# rules.
|
||||||
-
|
-
|
||||||
name: Install all dependencies and symlink for ep_etherpad-lite
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
-
|
||||||
name: Run load test
|
name: Run load test
|
||||||
run: src/tests/frontend/travis/runnerLoadTest.sh 25 50
|
run: src/tests/frontend/travis/runnerLoadTest.sh 25 50
|
||||||
|
@ -110,16 +138,30 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
-
|
||||||
name: Install etherpad-load-test
|
name: Install etherpad-load-test
|
||||||
run: sudo npm install -g etherpad-load-test
|
run: sudo npm install -g etherpad-load-test-socket-io
|
||||||
-
|
-
|
||||||
name: Run load test
|
name: Run load test
|
||||||
run: src/tests/frontend/travis/runnerLoadTest.sh 5000 5
|
run: src/tests/frontend/travis/runnerLoadTest.sh 5000 5
|
||||||
|
|
46
.github/workflows/perform-type-check.yml
vendored
Normal file
46
.github/workflows/perform-type-check.yml
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
name: "Perform type checks"
|
||||||
|
|
||||||
|
# any branch is useful for testing before a PR is submitted
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
performTypeCheck:
|
||||||
|
if: |
|
||||||
|
(github.event_name != 'pull_request')
|
||||||
|
|| (github.event.pull_request.head.repo.id != github.event.pull_request.base.repo.id)
|
||||||
|
name: perform type check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- uses: pnpm/action-setup@v3
|
||||||
|
name: Install pnpm
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
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
|
||||||
|
run: ./bin/installDeps.sh
|
||||||
|
- name: Perform type check
|
||||||
|
working-directory: ./src
|
||||||
|
run: npm run ts-check
|
25
.github/workflows/rate-limit.yml
vendored
25
.github/workflows/rate-limit.yml
vendored
|
@ -23,17 +23,30 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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: docker network
|
name: docker network
|
||||||
run: docker network create --subnet=172.23.42.0/16 ep_net
|
run: docker network create --subnet=172.23.42.0/16 ep_net
|
||||||
-
|
-
|
||||||
name: build docker image
|
name: build docker image
|
||||||
run: |
|
run: |
|
||||||
docker build -f Dockerfile -t epl-debian-slim .
|
docker build -f Dockerfile -t epl-debian-slim --build-arg NODE_ENV=develop .
|
||||||
docker build -f src/tests/ratelimit/Dockerfile.nginx -t nginx-latest .
|
docker build -f src/tests/ratelimit/Dockerfile.nginx -t nginx-latest .
|
||||||
docker build -f src/tests/ratelimit/Dockerfile.anotherip -t anotherip .
|
docker build -f src/tests/ratelimit/Dockerfile.anotherip -t anotherip .
|
||||||
-
|
-
|
||||||
|
@ -44,7 +57,7 @@ jobs:
|
||||||
docker run --rm --network ep_net --ip 172.23.42.3 --name anotherip -dt anotherip
|
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
|
name: install dependencies and create symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
-
|
||||||
name: run rate limit test
|
name: run rate limit test
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -29,14 +29,11 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: |
|
|
||||||
src/package-lock.json
|
|
||||||
src/bin/doc/package-lock.json
|
|
||||||
-
|
-
|
||||||
name: Install Etherpad plugins
|
name: Install Etherpad plugins
|
||||||
# The --legacy-peer-deps flag is required to work around a bug in npm
|
# Important: Installer for old master which does not have pnpm right now
|
||||||
# v7: https://github.com/npm/cli/issues/2199
|
# The --legacy-peer-deps flag is required to work around a bug in npm v7:
|
||||||
|
# https://github.com/npm/cli/issues/2199
|
||||||
run: >
|
run: >
|
||||||
npm install --no-save --legacy-peer-deps
|
npm install --no-save --legacy-peer-deps
|
||||||
ep_align
|
ep_align
|
||||||
|
@ -52,15 +49,6 @@ jobs:
|
||||||
ep_spellcheck
|
ep_spellcheck
|
||||||
ep_subscript_and_superscript
|
ep_subscript_and_superscript
|
||||||
ep_table_of_contents
|
ep_table_of_contents
|
||||||
# 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
|
|
||||||
# in the top-level node_modules. As of v6.14.10, npm's hoist logic appears
|
|
||||||
# to be buggy, because it sometimes removes dependencies from
|
|
||||||
# src/node_modules but fails to add them to the top-level node_modules.
|
|
||||||
# Even if npm correctly hoists the dependencies, the hoisting seems to
|
|
||||||
# confuse tools such as `npm outdated`, `npm update`, and some ESLint
|
|
||||||
# rules.
|
|
||||||
-
|
-
|
||||||
name: Install all dependencies and symlink for ep_etherpad-lite
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: src/bin/installDeps.sh
|
||||||
|
@ -82,18 +70,44 @@ jobs:
|
||||||
# For pull requests, ${GITHUB_SHA} is the automatically generated merge
|
# For pull requests, ${GITHUB_SHA} is the automatically generated merge
|
||||||
# commit that merges the PR's source branch to its destination branch.
|
# commit that merges the PR's source branch to its destination branch.
|
||||||
run: git checkout "${GITHUB_SHA}"
|
run: git checkout "${GITHUB_SHA}"
|
||||||
|
- uses: pnpm/action-setup@v3
|
||||||
|
name: Install pnpm
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
run_install: false
|
||||||
|
- name: Only install direct dependencies
|
||||||
|
run: pnpm config set auto-install-peers false
|
||||||
|
-
|
||||||
|
name: Install libreoffice
|
||||||
|
uses: awalsh128/cache-apt-pkgs-action@v1.4.2
|
||||||
|
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: Install all dependencies and symlink for ep_etherpad-lite
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
-
|
||||||
name: Run the backend tests
|
name: Run the backend tests
|
||||||
run: cd src && npm test
|
run: pnpm test
|
||||||
-
|
-
|
||||||
name: Install Cypress
|
name: Install Cypress
|
||||||
run: cd src && npm install cypress --legacy-peer-deps
|
working-directory: ./src
|
||||||
|
run: pnpm install cypress
|
||||||
-
|
-
|
||||||
name: Run Etherpad & Test Frontend
|
name: Run Etherpad & Test Frontend
|
||||||
|
working-directory: ./src
|
||||||
run: |
|
run: |
|
||||||
node src/node/server.js &
|
pnpm run dev &
|
||||||
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
|
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
|
||||||
./src/node_modules/cypress/bin/cypress run --config-file src/tests/frontend/cypress/cypress.config.js
|
./node_modules/cypress/bin/cypress run --config-file tests/frontend/cypress/cypress.config.js
|
||||||
|
|
72
.github/workflows/windows.yml
vendored
72
.github/workflows/windows.yml
vendored
|
@ -28,23 +28,37 @@ jobs:
|
||||||
-
|
-
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 21
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
src/package-lock.json
|
with:
|
||||||
src/bin/doc/package-lock.json
|
version: 8
|
||||||
|
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
|
name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: src/bin/installDeps.sh
|
run: bin/installDeps.sh
|
||||||
-
|
-
|
||||||
name: Run the backend tests
|
name: Run the backend tests
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: cd src && npm test
|
run: cd src && pnpm test
|
||||||
-
|
-
|
||||||
name: Build the .zip
|
name: Build the .zip
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: src/bin/buildForWindows.sh
|
run: bin/buildForWindows.sh
|
||||||
-
|
-
|
||||||
name: Archive production artifacts
|
name: Archive production artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
@ -75,9 +89,9 @@ jobs:
|
||||||
run: 7z x etherpad-win.zip -oetherpad-zip
|
run: 7z x etherpad-win.zip -oetherpad-zip
|
||||||
-
|
-
|
||||||
name: Create installer
|
name: Create installer
|
||||||
uses: joncloud/makensis-action@v3.7
|
uses: joncloud/makensis-action@v4.1
|
||||||
with:
|
with:
|
||||||
script-file: 'src/bin/nsis/etherpad.nsi'
|
script-file: 'bin/nsis/etherpad.nsi'
|
||||||
-
|
-
|
||||||
name: Archive production artifacts
|
name: Archive production artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
@ -109,27 +123,43 @@ jobs:
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'npm'
|
- uses: pnpm/action-setup@v3
|
||||||
cache-dependency-path: |
|
name: Install pnpm
|
||||||
etherpad/src/package-lock.json
|
with:
|
||||||
etherpad/src/bin/doc/package-lock.json
|
version: 8
|
||||||
-
|
run_install: false
|
||||||
name: Install Cypress
|
- name: Get pnpm store directory
|
||||||
run: cd etherpad && cd src && npm install cypress --legacy-peer-deps
|
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
|
||||||
|
run: .\bin\installOnWindows.bat
|
||||||
|
working-directory: etherpad
|
||||||
-
|
-
|
||||||
name: Run Etherpad
|
name: Run Etherpad
|
||||||
|
working-directory: etherpad/src
|
||||||
run: |
|
run: |
|
||||||
cd etherpad
|
pnpm install cypress
|
||||||
node node_modules\ep_etherpad-lite\node\server.js &
|
.\node_modules\.bin\cypress.cmd install --force
|
||||||
|
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
|
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
|
||||||
src\node_modules\cypress\bin\cypress run --config-file src\tests\frontendcypress\cypress.config.js
|
pnpm exec cypress run --config-file ./tests/frontend/cypress/cypress.config.js
|
||||||
# On release, upload windows zip to GitHub release tab
|
# On release, upload windows zip to GitHub release tab
|
||||||
-
|
-
|
||||||
name: Rename to etherpad-lite-win.zip
|
name: Rename to etherpad-lite-win.zip
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: mv etherpad-win.zip etherpad-lite-win.zip
|
run: mv etherpad-win.zip etherpad-lite-win.zip
|
||||||
- name: upload binaries to release
|
- name: upload binaries to release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
if: ${{startsWith(github.ref, 'refs/tags/v') }}
|
if: ${{startsWith(github.ref, 'refs/tags/v') }}
|
||||||
with:
|
with:
|
||||||
files: etherpad-lite-win.zip
|
files: etherpad-lite-win.zip
|
||||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -6,6 +6,7 @@ node_modules
|
||||||
APIKEY.txt
|
APIKEY.txt
|
||||||
SESSIONKEY.txt
|
SESSIONKEY.txt
|
||||||
var/dirty.db
|
var/dirty.db
|
||||||
|
.env
|
||||||
*~
|
*~
|
||||||
*.patch
|
*.patch
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
@ -22,3 +23,7 @@ out/
|
||||||
/src/bin/etherpad-1.deb
|
/src/bin/etherpad-1.deb
|
||||||
/src/bin/node.exe
|
/src/bin/node.exe
|
||||||
plugin_packages
|
plugin_packages
|
||||||
|
/src/templates/admin
|
||||||
|
/src/test-results
|
||||||
|
playwright-report
|
||||||
|
state.json
|
||||||
|
|
1
.npmrc
Normal file
1
.npmrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
auto-install-peers=false
|
32
.travis.yml
32
.travis.yml
|
@ -55,7 +55,7 @@ jobs:
|
||||||
- *set_loglevel_warn
|
- *set_loglevel_warn
|
||||||
- *enable_admin_tests
|
- *enable_admin_tests
|
||||||
- "src/tests/frontend/travis/sauce_tunnel.sh"
|
- "src/tests/frontend/travis/sauce_tunnel.sh"
|
||||||
- "src/bin/installDeps.sh"
|
- "bin/installDeps.sh"
|
||||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||||
script:
|
script:
|
||||||
- "./src/tests/frontend/travis/runner.sh"
|
- "./src/tests/frontend/travis/runner.sh"
|
||||||
|
@ -63,22 +63,22 @@ jobs:
|
||||||
install:
|
install:
|
||||||
- *install_libreoffice
|
- *install_libreoffice
|
||||||
- *set_loglevel_warn
|
- *set_loglevel_warn
|
||||||
- "src/bin/installDeps.sh"
|
- "bin/installDeps.sh"
|
||||||
- "cd src && npm install && cd -"
|
- "cd src && pnpm install && cd -"
|
||||||
script:
|
script:
|
||||||
- "cd src && npm test"
|
- "cd src && pnpm test"
|
||||||
- name: "Test the Dockerfile"
|
- name: "Test the Dockerfile"
|
||||||
install:
|
install:
|
||||||
- "cd src && npm install && cd -"
|
- "cd src && pnpm install && cd -"
|
||||||
script:
|
script:
|
||||||
- "docker build -t etherpad:test ."
|
- "docker build -t etherpad:test ."
|
||||||
- "docker run -d -p 9001:9001 etherpad:test && sleep 3"
|
- "docker run -d -p 9001:9001 etherpad:test && sleep 3"
|
||||||
- "cd src && npm run test-container"
|
- "cd src && pnpm run test-container"
|
||||||
- name: "Load test Etherpad without Plugins"
|
- name: "Load test Etherpad without Plugins"
|
||||||
install:
|
install:
|
||||||
- *set_loglevel_warn
|
- *set_loglevel_warn
|
||||||
- "src/bin/installDeps.sh"
|
- "bin/installDeps.sh"
|
||||||
- "cd src && npm install && cd -"
|
- "cd src && pnpm install && cd -"
|
||||||
- "npm install -g etherpad-load-test"
|
- "npm install -g etherpad-load-test"
|
||||||
script:
|
script:
|
||||||
- "src/tests/frontend/travis/runnerLoadTest.sh"
|
- "src/tests/frontend/travis/runnerLoadTest.sh"
|
||||||
|
@ -90,7 +90,7 @@ jobs:
|
||||||
- *set_loglevel_warn
|
- *set_loglevel_warn
|
||||||
- *enable_admin_tests
|
- *enable_admin_tests
|
||||||
- "src/tests/frontend/travis/sauce_tunnel.sh"
|
- "src/tests/frontend/travis/sauce_tunnel.sh"
|
||||||
- "src/bin/installDeps.sh"
|
- "bin/installDeps.sh"
|
||||||
- "rm src/tests/frontend/specs/*"
|
- "rm src/tests/frontend/specs/*"
|
||||||
- *install_plugins
|
- *install_plugins
|
||||||
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
- "export GIT_HASH=$(git rev-parse --verify --short HEAD)"
|
||||||
|
@ -105,22 +105,22 @@ jobs:
|
||||||
install:
|
install:
|
||||||
- *install_libreoffice
|
- *install_libreoffice
|
||||||
- *set_loglevel_warn
|
- *set_loglevel_warn
|
||||||
- "src/bin/installDeps.sh"
|
- "bin/installDeps.sh"
|
||||||
- *install_plugins
|
- *install_plugins
|
||||||
- "cd src && npm install && cd -"
|
- "cd src && pnpm install && cd -"
|
||||||
script:
|
script:
|
||||||
- "cd src && npm test"
|
- "cd src && pnpm test"
|
||||||
- name: "Test the Dockerfile"
|
- name: "Test the Dockerfile"
|
||||||
install:
|
install:
|
||||||
- "cd src && npm install && cd -"
|
- "cd src && pnpm install && cd -"
|
||||||
script:
|
script:
|
||||||
- "docker build -t etherpad:test ."
|
- "docker build -t etherpad:test ."
|
||||||
- "docker run -d -p 9001:9001 etherpad:test && sleep 3"
|
- "docker run -d -p 9001:9001 etherpad:test && sleep 3"
|
||||||
- "cd src && npm run test-container"
|
- "cd src && pnpm run test-container"
|
||||||
- name: "Load test Etherpad with Plugins"
|
- name: "Load test Etherpad with Plugins"
|
||||||
install:
|
install:
|
||||||
- *set_loglevel_warn
|
- *set_loglevel_warn
|
||||||
- "src/bin/installDeps.sh"
|
- "bin/installDeps.sh"
|
||||||
- *install_plugins
|
- *install_plugins
|
||||||
- "cd src && npm install && cd -"
|
- "cd src && npm install && cd -"
|
||||||
- "npm install -g etherpad-load-test"
|
- "npm install -g etherpad-load-test"
|
||||||
|
@ -135,7 +135,7 @@ jobs:
|
||||||
- "docker run -p 8081:80 --rm --network ep_net --ip 172.23.42.1 -d nginx-latest"
|
- "docker run -p 8081:80 --rm --network ep_net --ip 172.23.42.1 -d nginx-latest"
|
||||||
- "docker run --name etherpad-docker -p 9000:9001 --rm --network ep_net --ip 172.23.42.2 -e 'TRUST_PROXY=true' epl-debian-slim &"
|
- "docker run --name etherpad-docker -p 9000:9001 --rm --network ep_net --ip 172.23.42.2 -e 'TRUST_PROXY=true' epl-debian-slim &"
|
||||||
- "docker run --rm --network ep_net --ip 172.23.42.3 --name anotherip -dt anotherip"
|
- "docker run --rm --network ep_net --ip 172.23.42.3 --name anotherip -dt anotherip"
|
||||||
- "./src/bin/installDeps.sh"
|
- "./bin/installDeps.sh"
|
||||||
script:
|
script:
|
||||||
- "cd src/tests/ratelimit && bash testlimits.sh"
|
- "cd src/tests/ratelimit && bash testlimits.sh"
|
||||||
|
|
||||||
|
|
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -1,3 +1,27 @@
|
||||||
|
# 2.0.0
|
||||||
|
|
||||||
|
|
||||||
|
### Compatibility changes
|
||||||
|
|
||||||
|
- Socket io has been updated to 4.7.5. This means that the json.send function won't work anymore and needs to be changed to .emit('message', myObj)
|
||||||
|
- Deprecating npm version 6 in favor of pnpm: We have made the decision to switch to the well established pnpm (https://pnpm.io/). It works by symlinking dependencies into a global directory allowing you to have a cleaner and more reliable environment.
|
||||||
|
- Introducing Typescript to the Etherpad core: Etherpad core logic has been rewritten in Typescript allowing for compiler checking of errors.
|
||||||
|
- Rewritten Admin Panel: The Admin panel has been rewritten in React and now features a more pleasant user experience. It now also features an integrated pad searching with sorting functionality.
|
||||||
|
|
||||||
|
### Notable enhancements and fixes
|
||||||
|
|
||||||
|
* Bugfixes
|
||||||
|
- Live Plugin Manager: The live plugin manager caused problems when a plugin had depdendencies defined. This issue is now resolved.
|
||||||
|
|
||||||
|
* Enhancements
|
||||||
|
- pnpm Workspaces: In addition to pnpm we introduced workspaces. A clean way to manage multiple bounded contexts like the admin panel or the bin folder.
|
||||||
|
- Bin folder: The bin folder has been moved from the src folder to the root folder. This change was necessary as the contained scripts do not represent core functionality of the user.
|
||||||
|
- Starting Etherpad: Etherpad can now be started with a single command: `pnpm run prod` in the root directory.
|
||||||
|
- Installing Etherpad: Etherpad no longer symlinks itself in the root directory. This is now also taken care by pnpm, and it just creates a node_modules folder with the src directory`s ep_etherpad-lite folder
|
||||||
|
- Plugins can now be installed simply via the command: `pnpm run install-plugins first-plugin second-plugin` or if you want to install from path you can do:
|
||||||
|
`pnpm run install-plugins --path ../path-to-plugin`
|
||||||
|
|
||||||
|
|
||||||
# 1.9.7
|
# 1.9.7
|
||||||
|
|
||||||
### Notable enhancements and fixes
|
### Notable enhancements and fixes
|
||||||
|
|
73
Dockerfile
73
Dockerfile
|
@ -4,9 +4,21 @@
|
||||||
#
|
#
|
||||||
# Author: muxator
|
# Author: muxator
|
||||||
|
|
||||||
FROM node:lts-alpine
|
FROM node:alpine as adminBuild
|
||||||
|
|
||||||
|
WORKDIR /opt/etherpad-lite
|
||||||
|
COPY ./admin ./admin
|
||||||
|
RUN cd ./admin && npm install -g pnpm && pnpm install && pnpm run build --outDir ./dist
|
||||||
|
|
||||||
|
|
||||||
|
FROM node:alpine as build
|
||||||
LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite"
|
LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite"
|
||||||
|
|
||||||
|
# Set these arguments when building the image from behind a proxy
|
||||||
|
ARG http_proxy=
|
||||||
|
ARG https_proxy=
|
||||||
|
ARG no_proxy=
|
||||||
|
|
||||||
ARG TIMEZONE=
|
ARG TIMEZONE=
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
|
@ -44,11 +56,6 @@ ARG INSTALL_ABIWORD=
|
||||||
# INSTALL_LIBREOFFICE=true
|
# INSTALL_LIBREOFFICE=true
|
||||||
ARG INSTALL_SOFFICE=
|
ARG INSTALL_SOFFICE=
|
||||||
|
|
||||||
# By default, Etherpad container is built and run in "production" mode. This is
|
|
||||||
# leaner (development dependencies are not installed) and runs faster (among
|
|
||||||
# other things, assets are minified & compressed).
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
ENV ETHERPAD_PRODUCTION=true
|
|
||||||
# Install dependencies required for modifying access.
|
# Install dependencies required for modifying access.
|
||||||
RUN apk add shadow bash
|
RUN apk add shadow bash
|
||||||
# Follow the principle of least privilege: run as unprivileged user.
|
# Follow the principle of least privilege: run as unprivileged user.
|
||||||
|
@ -63,8 +70,6 @@ ARG EP_UID=5001
|
||||||
ARG EP_GID=0
|
ARG EP_GID=0
|
||||||
ARG EP_SHELL=
|
ARG EP_SHELL=
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
|
|
||||||
RUN groupadd --system ${EP_GID:+--gid "${EP_GID}" --non-unique} etherpad && \
|
RUN groupadd --system ${EP_GID:+--gid "${EP_GID}" --non-unique} etherpad && \
|
||||||
useradd --system ${EP_UID:+--uid "${EP_UID}" --non-unique} --gid etherpad \
|
useradd --system ${EP_UID:+--uid "${EP_UID}" --non-unique} --gid etherpad \
|
||||||
${EP_HOME:+--home-dir "${EP_HOME}"} --create-home \
|
${EP_HOME:+--home-dir "${EP_HOME}"} --create-home \
|
||||||
|
@ -77,10 +82,11 @@ RUN mkdir -p "${EP_DIR}" && chown etherpad:etherpad "${EP_DIR}"
|
||||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
|
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
|
||||||
RUN \
|
RUN \
|
||||||
mkdir -p /usr/share/man/man1 && \
|
mkdir -p /usr/share/man/man1 && \
|
||||||
npm install npm@6 -g && \
|
npm install pnpm -g && \
|
||||||
apk update && apk upgrade && \
|
apk update && apk upgrade && \
|
||||||
apk add \
|
apk add \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
curl \
|
||||||
git \
|
git \
|
||||||
${INSTALL_ABIWORD:+abiword abiword-plugin-command} \
|
${INSTALL_ABIWORD:+abiword abiword-plugin-command} \
|
||||||
${INSTALL_SOFFICE:+libreoffice openjdk8-jre libreoffice-common}
|
${INSTALL_SOFFICE:+libreoffice openjdk8-jre libreoffice-common}
|
||||||
|
@ -89,32 +95,45 @@ USER etherpad
|
||||||
|
|
||||||
WORKDIR "${EP_DIR}"
|
WORKDIR "${EP_DIR}"
|
||||||
|
|
||||||
COPY --chown=etherpad:etherpad ./ ./
|
# etherpads version feature requires this. Only copy what is really needed
|
||||||
|
COPY --chown=etherpad:etherpad ./.git/HEAD ./.git/HEAD
|
||||||
|
COPY --chown=etherpad:etherpad ./.git/refs ./.git/refs
|
||||||
|
COPY --chown=etherpad:etherpad ${SETTINGS} ./settings.json
|
||||||
|
COPY --chown=etherpad:etherpad ./var ./var
|
||||||
|
COPY --chown=etherpad:etherpad ./bin ./bin
|
||||||
|
COPY --chown=etherpad:etherpad ./pnpm-workspace.yaml ./package.json ./
|
||||||
|
|
||||||
|
FROM build as development
|
||||||
|
|
||||||
|
COPY --chown=etherpad:etherpad ./src/package.json .npmrc ./src/pnpm-lock.yaml ./src/
|
||||||
|
COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/admin/dist ./src/templates/admin
|
||||||
|
|
||||||
|
RUN bin/installDeps.sh && \
|
||||||
|
{ [ -z "${ETHERPAD_PLUGINS}" ] || pnpm run install-plugins ${ETHERPAD_PLUGINS}; }
|
||||||
|
|
||||||
|
FROM build as production
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV ETHERPAD_PRODUCTION=true
|
||||||
|
|
||||||
|
COPY --chown=etherpad:etherpad ./src ./src
|
||||||
|
COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/admin/dist ./src/templates/admin
|
||||||
|
|
||||||
|
RUN bin/installDeps.sh && rm -rf ~/.npm && \
|
||||||
|
{ [ -z "${ETHERPAD_PLUGINS}" ] || pnpm run install-plugins ${ETHERPAD_PLUGINS}; }
|
||||||
|
|
||||||
# Plugins must be installed before installing Etherpad's dependencies, otherwise
|
|
||||||
# npm will try to hoist common dependencies by removing them from
|
|
||||||
# src/node_modules and installing them in the top-level node_modules. As of
|
|
||||||
# v6.14.10, npm's hoist logic appears to be buggy, because it sometimes removes
|
|
||||||
# dependencies from src/node_modules but fails to add them to the top-level
|
|
||||||
# node_modules. Even if npm correctly hoists the dependencies, the hoisting
|
|
||||||
# seems to confuse tools such as `npm outdated`, `npm update`, and some ESLint
|
|
||||||
# rules.
|
|
||||||
RUN { [ -z "${ETHERPAD_PLUGINS}" ] || \
|
|
||||||
npm install --no-save --legacy-peer-deps ${ETHERPAD_PLUGINS}; } && \
|
|
||||||
src/bin/installDeps.sh && \
|
|
||||||
rm -rf ~/.npm
|
|
||||||
|
|
||||||
# Copy the configuration file.
|
# Copy the configuration file.
|
||||||
COPY --chown=etherpad:etherpad ${SETTINGS} "${EP_DIR}"/settings.json
|
COPY --chown=etherpad:etherpad ${SETTINGS} "${EP_DIR}"/settings.json
|
||||||
|
|
||||||
# Fix group permissions
|
# Fix group permissions
|
||||||
RUN chmod -R g=u .
|
# Note: For some reason increases image size from 257 to 334.
|
||||||
|
# RUN chmod -R g=u .
|
||||||
|
|
||||||
USER root
|
|
||||||
RUN cd src && npm link
|
|
||||||
USER etherpad
|
USER etherpad
|
||||||
|
|
||||||
HEALTHCHECK --interval=20s --timeout=3s CMD ["etherpad-healthcheck"]
|
HEALTHCHECK --interval=5s --timeout=3s \
|
||||||
|
CMD curl --silent http://localhost:9001/health | grep -E "pass|ok|up" > /dev/null || exit 1
|
||||||
|
|
||||||
EXPOSE 9001
|
EXPOSE 9001
|
||||||
CMD ["etherpad"]
|
CMD ["pnpm", "run", "prod"]
|
||||||
|
|
26
README.md
26
README.md
|
@ -56,7 +56,7 @@ Install the latest Node.js LTS per [official install instructions](https://githu
|
||||||
```sh
|
```sh
|
||||||
git clone --branch master https://github.com/ether/etherpad-lite.git &&
|
git clone --branch master https://github.com/ether/etherpad-lite.git &&
|
||||||
cd etherpad-lite &&
|
cd etherpad-lite &&
|
||||||
src/bin/run.sh
|
bin/run.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Manual install
|
#### Manual install
|
||||||
|
@ -70,10 +70,10 @@ You'll need Git and [Node.js](https://nodejs.org/) installed.
|
||||||
https://github.com/ether/etherpad-lite.git`
|
https://github.com/ether/etherpad-lite.git`
|
||||||
3. Change into the new directory containing the cloned source code: `cd
|
3. Change into the new directory containing the cloned source code: `cd
|
||||||
etherpad-lite`
|
etherpad-lite`
|
||||||
4. Run `src/bin/run.sh` and open http://127.0.0.1:9001 in your browser.
|
4. Run `bin/run.sh` and open http://127.0.0.1:9001 in your browser.
|
||||||
|
|
||||||
To update to the latest released version, execute `git pull origin`. The next
|
To update to the latest released version, execute `git pull origin`. The next
|
||||||
start with `src/bin/run.sh` will update the dependencies.
|
start with `bin/run.sh` will update the dependencies.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
|
@ -98,17 +98,17 @@ git.
|
||||||
* or `git clone --branch master
|
* or `git clone --branch master
|
||||||
https://github.com/ether/etherpad-lite.git`
|
https://github.com/ether/etherpad-lite.git`
|
||||||
2. With a "Run as administrator" command prompt execute
|
2. With a "Run as administrator" command prompt execute
|
||||||
`src\bin\installOnWindows.bat`
|
`bin\installOnWindows.bat`
|
||||||
|
|
||||||
Now, run `start.bat` and open http://localhost:9001 in your browser.
|
Now, run `start.bat` and open http://localhost:9001 in your browser.
|
||||||
|
|
||||||
Update to the latest version with `git pull origin`, then run
|
Update to the latest version with `git pull origin`, then run
|
||||||
`src\bin\installOnWindows.bat`, again.
|
`bin\installOnWindows.bat`, again.
|
||||||
|
|
||||||
If cloning to a subdirectory within another project, you may need to do the
|
If cloning to a subdirectory within another project, you may need to do the
|
||||||
following:
|
following:
|
||||||
|
|
||||||
1. Start the server manually (e.g. `node src/node/server.js`)
|
1. Start the server manually (e.g. `node src/node/server.ts`)
|
||||||
2. Edit the db `filename` in `settings.json` to the relative directory with
|
2. Edit the db `filename` in `settings.json` to the relative directory with
|
||||||
the file (e.g. `application/lib/etherpad-lite/var/dirty.db`)
|
the file (e.g. `application/lib/etherpad-lite/var/dirty.db`)
|
||||||
3. Add auto-generated files to the main project `.gitignore`
|
3. Add auto-generated files to the main project `.gitignore`
|
||||||
|
@ -139,9 +139,7 @@ Alternatively, you can install plugins from the command line:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd /path/to/etherpad-lite
|
cd /path/to/etherpad-lite
|
||||||
# The `--no-save` and `--legacy-peer-deps` arguments are necessary to work
|
pnpm run install-plugins ep_${plugin_name}
|
||||||
# around npm quirks.
|
|
||||||
npm install --no-save --legacy-peer-deps ep_${plugin_name}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Also see [the plugin wiki
|
Also see [the plugin wiki
|
||||||
|
@ -153,7 +151,7 @@ Run the following command in your Etherpad folder to get all of the features
|
||||||
visible in the above demo gif:
|
visible in the above demo gif:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install --no-save --legacy-peer-deps \
|
pnpm run install-plugins \
|
||||||
ep_align \
|
ep_align \
|
||||||
ep_comments_page \
|
ep_comments_page \
|
||||||
ep_embedded_hyperlinks2 \
|
ep_embedded_hyperlinks2 \
|
||||||
|
@ -182,7 +180,7 @@ following plugins:
|
||||||
### Tweak the settings
|
### Tweak the settings
|
||||||
|
|
||||||
You can modify the settings in `settings.json`. If you need to handle multiple
|
You can modify the settings in `settings.json`. If you need to handle multiple
|
||||||
settings files, you can pass the path to a settings file to `src/bin/run.sh`
|
settings files, you can pass the path to a settings file to `bin/run.sh`
|
||||||
using the `-s|--settings` option: this allows you to run multiple Etherpad
|
using the `-s|--settings` option: this allows you to run multiple Etherpad
|
||||||
instances from the same installation. Similarly, `--credentials` can be used to
|
instances from the same installation. Similarly, `--credentials` can be used to
|
||||||
give a settings override file, `--apikey` to give a different APIKEY.txt file
|
give a settings override file, `--apikey` to give a different APIKEY.txt file
|
||||||
|
@ -226,11 +224,11 @@ Documentation can be found in `doc/`.
|
||||||
|
|
||||||
### Things you should know
|
### Things you should know
|
||||||
|
|
||||||
You can debug Etherpad using `src/bin/debugRun.sh`.
|
You can debug Etherpad using `bin/debugRun.sh`.
|
||||||
|
|
||||||
You can run Etherpad quickly launching `src/bin/fastRun.sh`. It's convenient for
|
You can run Etherpad quickly launching `bin/fastRun.sh`. It's convenient for
|
||||||
developers and advanced users. Be aware that it will skip the dependencies
|
developers and advanced users. Be aware that it will skip the dependencies
|
||||||
update, so remember to run `src/bin/installDeps.sh` after installing a new
|
update, so remember to run `bin/installDeps.sh` after installing a new
|
||||||
dependency or upgrading version.
|
dependency or upgrading version.
|
||||||
|
|
||||||
If you want to find out how Etherpad's `Easysync` works (the library that makes
|
If you want to find out how Etherpad's `Easysync` works (the library that makes
|
||||||
|
|
18
admin/.eslintrc.cjs
Normal file
18
admin/.eslintrc.cjs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: { browser: true, es2020: true },
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:react-hooks/recommended',
|
||||||
|
],
|
||||||
|
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
plugins: ['react-refresh'],
|
||||||
|
rules: {
|
||||||
|
'react-refresh/only-export-components': [
|
||||||
|
'warn',
|
||||||
|
{ allowConstantExport: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
24
admin/.gitignore
vendored
Normal file
24
admin/.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
30
admin/README.md
Normal file
30
admin/README.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# React + TypeScript + Vite
|
||||||
|
|
||||||
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||||
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||||
|
|
||||||
|
## Expanding the ESLint configuration
|
||||||
|
|
||||||
|
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||||
|
|
||||||
|
- Configure the top-level `parserOptions` property like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
// other rules...
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module',
|
||||||
|
project: ['./tsconfig.json', './tsconfig.node.json'],
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
||||||
|
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
||||||
|
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
14
admin/index.html
Normal file
14
admin/index.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Etherpad Admin Dashboard</title>
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<div id="loading"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
39
admin/package.json
Normal file
39
admin/package.json
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"private": true,
|
||||||
|
"version": "2.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
|
"@radix-ui/react-toast": "^1.1.5",
|
||||||
|
"i18next": "^23.10.1",
|
||||||
|
"i18next-browser-languagedetector": "^7.2.0",
|
||||||
|
"lucide-react": "^0.356.0",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-hook-form": "^7.51.0",
|
||||||
|
"react-i18next": "^14.1.0",
|
||||||
|
"react-router-dom": "^6.22.3",
|
||||||
|
"zustand": "^4.5.2",
|
||||||
|
"@types/react": "^18.2.56",
|
||||||
|
"@types/react-dom": "^18.2.19",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
||||||
|
"@typescript-eslint/parser": "^7.0.2",
|
||||||
|
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.5",
|
||||||
|
"socket.io-client": "^4.7.4",
|
||||||
|
"typescript": "^5.2.2",
|
||||||
|
"vite": "^5.1.4",
|
||||||
|
"vite-plugin-static-copy": "^1.0.1",
|
||||||
|
"vite-plugin-svgr": "^4.2.0"
|
||||||
|
}
|
||||||
|
}
|
BIN
admin/public/Karla-Bold.ttf
Normal file
BIN
admin/public/Karla-Bold.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-BoldItalic.ttf
Normal file
BIN
admin/public/Karla-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-ExtraBold.ttf
Normal file
BIN
admin/public/Karla-ExtraBold.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-ExtraBoldItalic.ttf
Normal file
BIN
admin/public/Karla-ExtraBoldItalic.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-ExtraLight.ttf
Normal file
BIN
admin/public/Karla-ExtraLight.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-ExtraLightItalic.ttf
Normal file
BIN
admin/public/Karla-ExtraLightItalic.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-Italic.ttf
Normal file
BIN
admin/public/Karla-Italic.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-Light.ttf
Normal file
BIN
admin/public/Karla-Light.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-LightItalic.ttf
Normal file
BIN
admin/public/Karla-LightItalic.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-Medium.ttf
Normal file
BIN
admin/public/Karla-Medium.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-MediumItalic.ttf
Normal file
BIN
admin/public/Karla-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-Regular.ttf
Normal file
BIN
admin/public/Karla-Regular.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-SemiBold.ttf
Normal file
BIN
admin/public/Karla-SemiBold.ttf
Normal file
Binary file not shown.
BIN
admin/public/Karla-SemiBoldItalic.ttf
Normal file
BIN
admin/public/Karla-SemiBoldItalic.ttf
Normal file
Binary file not shown.
28
admin/public/ep_admin_pads/ar.json
Normal file
28
admin/public/ep_admin_pads/ar.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Meno25",
|
||||||
|
"محمد أحمد عبد الفتاح"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "فعل",
|
||||||
|
"ep_adminpads2_autoupdate-label": "التحديث التلقائي على تغييرات الوسادة",
|
||||||
|
"ep_adminpads2_autoupdate.title": "لتمكين أو تعطيل التحديثات التلقائية للاستعلام الحالي.",
|
||||||
|
"ep_adminpads2_confirm": "هل تريد حقًا حذف الوسادة {{padID}}؟",
|
||||||
|
"ep_adminpads2_delete.value": "حذف",
|
||||||
|
"ep_adminpads2_last-edited": "آخر تعديل",
|
||||||
|
"ep_adminpads2_loading": "جارٍ التحميل...",
|
||||||
|
"ep_adminpads2_manage-pads": "إدارة الفوط",
|
||||||
|
"ep_adminpads2_no-results": "لا توجد نتائج.",
|
||||||
|
"ep_adminpads2_pad-user-count": "عدد المستخدمين الوسادة",
|
||||||
|
"ep_adminpads2_padname": "بادنام",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "مصطلح البحث",
|
||||||
|
"ep_adminpads2_search-button.value": "بحث",
|
||||||
|
"ep_adminpads2_search-done": "اكتمل البحث",
|
||||||
|
"ep_adminpads2_search-error-explanation": "واجه الخادم خطأً أثناء البحث عن منصات:",
|
||||||
|
"ep_adminpads2_search-error-title": "فشل في الحصول على قائمة الوسادة",
|
||||||
|
"ep_adminpads2_search-heading": "ابحث عن الفوط",
|
||||||
|
"ep_adminpads2_title": "إدارة الوسادة",
|
||||||
|
"ep_adminpads2_unknown-error": "خطأ غير معروف",
|
||||||
|
"ep_adminpads2_unknown-status": "حالة غير معروفة"
|
||||||
|
}
|
23
admin/public/ep_admin_pads/bn.json
Normal file
23
admin/public/ep_admin_pads/bn.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"আজিজ",
|
||||||
|
"আফতাবুজ্জামান"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "কার্য",
|
||||||
|
"ep_adminpads2_delete.value": "মুছে ফেলুন",
|
||||||
|
"ep_adminpads2_last-edited": "সর্বশেষ সম্পাদিত",
|
||||||
|
"ep_adminpads2_loading": "লোড হচ্ছে...",
|
||||||
|
"ep_adminpads2_manage-pads": "প্যাড পরিচালনা করুন",
|
||||||
|
"ep_adminpads2_no-results": "ফলাফল নেই",
|
||||||
|
"ep_adminpads2_padname": "প্যাডের নাম",
|
||||||
|
"ep_adminpads2_search-button.value": "অনুসন্ধান",
|
||||||
|
"ep_adminpads2_search-done": "অনুসন্ধান সম্পূর্ণ",
|
||||||
|
"ep_adminpads2_search-error-explanation": "প্যাড অনুসন্ধান করার সময় সার্ভার একটি ত্রুটির সম্মুখীন হয়েছে:",
|
||||||
|
"ep_adminpads2_search-error-title": "প্যাডের তালিকা পেতে ব্যর্থ",
|
||||||
|
"ep_adminpads2_search-heading": "প্যাড অনুসন্ধান করুন",
|
||||||
|
"ep_adminpads2_title": "প্যাড প্রশাসন",
|
||||||
|
"ep_adminpads2_unknown-error": "অজানা ত্রুটি",
|
||||||
|
"ep_adminpads2_unknown-status": "অজানা অবস্থা"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/ca.json
Normal file
27
admin/public/ep_admin_pads/ca.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Mguix"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Acció",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Actualització automàtica en cas de canvis de pad",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Activa o desactiva les actualitzacions automàtiques per a la consulta actual.",
|
||||||
|
"ep_adminpads2_confirm": "Esteu segur que voleu suprimir el pad {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Esborrar",
|
||||||
|
"ep_adminpads2_last-edited": "Darrera modificació",
|
||||||
|
"ep_adminpads2_loading": "S’està carregant…",
|
||||||
|
"ep_adminpads2_manage-pads": "Gestiona els pads",
|
||||||
|
"ep_adminpads2_no-results": "No hi ha cap resultat",
|
||||||
|
"ep_adminpads2_pad-user-count": "Nombre d'usuaris de pads",
|
||||||
|
"ep_adminpads2_padname": "Nom del pad",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Terme de cerca",
|
||||||
|
"ep_adminpads2_search-button.value": "Cercar",
|
||||||
|
"ep_adminpads2_search-done": "Cerca completa",
|
||||||
|
"ep_adminpads2_search-error-explanation": "El servidor ha trobat un error mentre buscava pads:",
|
||||||
|
"ep_adminpads2_search-error-title": "No s'ha pogut obtenir la llista del pad",
|
||||||
|
"ep_adminpads2_search-heading": "Cerca pads",
|
||||||
|
"ep_adminpads2_title": "Administració del pad",
|
||||||
|
"ep_adminpads2_unknown-error": "Error desconegut",
|
||||||
|
"ep_adminpads2_unknown-status": "Estat desconegut"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/cs.json
Normal file
27
admin/public/ep_admin_pads/cs.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Spotter"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Akce",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Automatická aktualizace změn Padu",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Povolí nebo zakáže automatické aktualizace pro aktuální dotaz.",
|
||||||
|
"ep_adminpads2_confirm": "Opravdu chcete odstranit pad {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Smazat",
|
||||||
|
"ep_adminpads2_last-edited": "Naposledy upraveno",
|
||||||
|
"ep_adminpads2_loading": "Načítání…",
|
||||||
|
"ep_adminpads2_manage-pads": "Spravovat pady",
|
||||||
|
"ep_adminpads2_no-results": "Žádné výsledky",
|
||||||
|
"ep_adminpads2_pad-user-count": "Počet uživatelů padu",
|
||||||
|
"ep_adminpads2_padname": "Název padu",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Hledaný výraz",
|
||||||
|
"ep_adminpads2_search-button.value": "Hledat",
|
||||||
|
"ep_adminpads2_search-done": "Hledání dokončeno",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Při hledání padů došlo k chybě serveru:",
|
||||||
|
"ep_adminpads2_search-error-title": "Seznam padů se nepodařilo získat",
|
||||||
|
"ep_adminpads2_search-heading": "Hledat pady",
|
||||||
|
"ep_adminpads2_title": "Správa Padu",
|
||||||
|
"ep_adminpads2_unknown-error": "Neznámá chyba",
|
||||||
|
"ep_adminpads2_unknown-status": "Neznámý stav"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/cy.json
Normal file
27
admin/public/ep_admin_pads/cy.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Robin Owain"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Gweithred",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Diweddaru newidiadau pad yn otomatig",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Galluogi neu analluogi diweddaru'r ymholiad cyfredol.",
|
||||||
|
"ep_adminpads2_confirm": "Siwr eich bod am ddileu'r pad {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Dileu",
|
||||||
|
"ep_adminpads2_last-edited": "Golygwyd ddiwethaf",
|
||||||
|
"ep_adminpads2_loading": "Wrthi'n llwytho...",
|
||||||
|
"ep_adminpads2_manage-pads": "Rheoli'r padiau",
|
||||||
|
"ep_adminpads2_no-results": "Dim canlyniad",
|
||||||
|
"ep_adminpads2_pad-user-count": "Cyfri defnyddiwr pad",
|
||||||
|
"ep_adminpads2_padname": "Enwpad",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Term chwilio",
|
||||||
|
"ep_adminpads2_search-button.value": "Chwilio",
|
||||||
|
"ep_adminpads2_search-done": "Wedi gorffen",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Nam ar y gweinydd wrth chwilio'r padiau:",
|
||||||
|
"ep_adminpads2_search-error-title": "Methwyd a chael y rhestr pad",
|
||||||
|
"ep_adminpads2_search-heading": "Chwilio am badiau",
|
||||||
|
"ep_adminpads2_title": "Gweinyddiaeth y pad",
|
||||||
|
"ep_adminpads2_unknown-error": "Nam o ryw fath",
|
||||||
|
"ep_adminpads2_unknown-status": "Statws anhysbys"
|
||||||
|
}
|
14
admin/public/ep_admin_pads/da.json
Normal file
14
admin/public/ep_admin_pads/da.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Saederup92"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Handling",
|
||||||
|
"ep_adminpads2_delete.value": "Slet",
|
||||||
|
"ep_adminpads2_last-edited": "Sidst redigeret",
|
||||||
|
"ep_adminpads2_loading": "Indlæser...",
|
||||||
|
"ep_adminpads2_no-results": "Ingen resultater",
|
||||||
|
"ep_adminpads2_unknown-error": "Ukendt fejl",
|
||||||
|
"ep_adminpads2_unknown-status": "Ukendt status"
|
||||||
|
}
|
32
admin/public/ep_admin_pads/de.json
Normal file
32
admin/public/ep_admin_pads/de.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Brettchenweber",
|
||||||
|
"Justman10000",
|
||||||
|
"Lorisobi",
|
||||||
|
"SamTV",
|
||||||
|
"Umlaut",
|
||||||
|
"Zunkelty"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Aktion",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Automatisch bei Pad-Änderungen updaten",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Aktiviert oder deaktiviert automatische Aktualisierungen für die aktuelle Abfrage.",
|
||||||
|
"ep_adminpads2_confirm": "Willst du das Pad {{padID}} wirklich löschen?",
|
||||||
|
"ep_adminpads2_delete.value": "Löschen",
|
||||||
|
"ep_adminpads2_last-edited": "Zuletzt bearbeitet",
|
||||||
|
"ep_adminpads2_loading": "Lädt...",
|
||||||
|
"ep_adminpads2_manage-pads": "Pads verwalten",
|
||||||
|
"ep_adminpads2_no-results": "Keine Ergebnisse",
|
||||||
|
"ep_adminpads2_pad-user-count": "Nutzerzahl des Pads",
|
||||||
|
"ep_adminpads2_padname": "Padname",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Suchbegriff",
|
||||||
|
"ep_adminpads2_search-button.value": "Suche",
|
||||||
|
"ep_adminpads2_search-done": "Suche vollendet",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Der Server ist bei der Suche nach Pads auf einen Fehler gestoßen:",
|
||||||
|
"ep_adminpads2_search-error-title": "Pad-Liste konnte nicht abgerufen werden",
|
||||||
|
"ep_adminpads2_search-heading": "Nach Pads suchen",
|
||||||
|
"ep_adminpads2_title": "Pad-Verwaltung",
|
||||||
|
"ep_adminpads2_unknown-error": "Unbekannter Fehler",
|
||||||
|
"ep_adminpads2_unknown-status": "Unbekannter Status"
|
||||||
|
}
|
28
admin/public/ep_admin_pads/diq.json
Normal file
28
admin/public/ep_admin_pads/diq.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"1917 Ekim Devrimi",
|
||||||
|
"Mirzali"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Hereketi",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Vurnayışanê pedi otomatik rocane kerê",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Persê mewcudi rê rocaneyışanê otomatika aktiv ke ya zi dewrê ra vecê",
|
||||||
|
"ep_adminpads2_confirm": "Şıma qayılê pedê {{padID}} bıesternê?",
|
||||||
|
"ep_adminpads2_delete.value": "Bestere",
|
||||||
|
"ep_adminpads2_last-edited": "Vurnayışo peyên",
|
||||||
|
"ep_adminpads2_loading": "Bar beno...",
|
||||||
|
"ep_adminpads2_manage-pads": "Pedan idare kerê",
|
||||||
|
"ep_adminpads2_no-results": "Netice çıniyo",
|
||||||
|
"ep_adminpads2_pad-user-count": "Amarê karberanê pedi",
|
||||||
|
"ep_adminpads2_padname": "Padname",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "termê cıgêrayış",
|
||||||
|
"ep_adminpads2_search-button.value": "Cı geyre",
|
||||||
|
"ep_adminpads2_search-done": "Cıgeyrayışi temam",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Server cıgeyrayışê pedan de yew xetaya raşt ame",
|
||||||
|
"ep_adminpads2_search-error-title": "Lista pedi nêgêriye",
|
||||||
|
"ep_adminpads2_search-heading": "Pedan cıgeyrayış",
|
||||||
|
"ep_adminpads2_title": "İdarey pedi",
|
||||||
|
"ep_adminpads2_unknown-error": "Xetaya nêzanıtiye",
|
||||||
|
"ep_adminpads2_unknown-status": "Weziyeto nêzanaye"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/dsb.json
Normal file
27
admin/public/ep_admin_pads/dsb.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Michawiki"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Akcija",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Pśi změnach na zapisniku awtomatiski aktualizěrowaś",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Zmóžnja abo znjemóžnja awtomatiske aktualizacije za aktualne wótpšašowanje.",
|
||||||
|
"ep_adminpads2_confirm": "Cośo napšawdu zapisnik {{padID}} lašowaś?",
|
||||||
|
"ep_adminpads2_delete.value": "Lašowaś",
|
||||||
|
"ep_adminpads2_last-edited": "Slědna změna",
|
||||||
|
"ep_adminpads2_loading": "Zacytujo se...",
|
||||||
|
"ep_adminpads2_manage-pads": "Zapisniki zastojaś",
|
||||||
|
"ep_adminpads2_no-results": "Žedne wuslědki",
|
||||||
|
"ep_adminpads2_pad-user-count": "Licba wužywarjow zapisnika",
|
||||||
|
"ep_adminpads2_padname": "Mě zapisnika",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Pytańske zapśimjeśe",
|
||||||
|
"ep_adminpads2_search-button.value": "Pytaś",
|
||||||
|
"ep_adminpads2_search-done": "Pytanje dokóńcone",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Serwer jo starcył na zmólku, mjaztym až jo pytał za zapisnikami:",
|
||||||
|
"ep_adminpads2_search-error-title": "Lisćina zapisnikow njedajo se wobstaraś",
|
||||||
|
"ep_adminpads2_search-heading": "Za zapisnikami pytaś",
|
||||||
|
"ep_adminpads2_title": "Zapisnikowa administracija",
|
||||||
|
"ep_adminpads2_unknown-error": "Njeznata zmólka",
|
||||||
|
"ep_adminpads2_unknown-status": "Njeznaty status"
|
||||||
|
}
|
16
admin/public/ep_admin_pads/el.json
Normal file
16
admin/public/ep_admin_pads/el.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Norhorn"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_delete.value": "Διαγραφή",
|
||||||
|
"ep_adminpads2_last-edited": "Τελευταία απεξεργασία",
|
||||||
|
"ep_adminpads2_loading": "Φόρτωση…",
|
||||||
|
"ep_adminpads2_no-results": "Κανένα αποτέλεσμα",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Αναζήτηση όρων",
|
||||||
|
"ep_adminpads2_search-button.value": "Αναζήτηση",
|
||||||
|
"ep_adminpads2_search-done": "Ολοκλήρωση αναζήτησης",
|
||||||
|
"ep_adminpads2_unknown-error": "Άγνωστο σφάλμα",
|
||||||
|
"ep_adminpads2_unknown-status": "Άγνωστη κατάσταση"
|
||||||
|
}
|
22
admin/public/ep_admin_pads/en.json
Normal file
22
admin/public/ep_admin_pads/en.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"ep_adminpads2_action": "Action",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Auto-update on pad changes",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Enables or disables automatic updates for the current query.",
|
||||||
|
"ep_adminpads2_confirm": "Do you really want to delete the pad {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Delete",
|
||||||
|
"ep_adminpads2_last-edited": "Last edited",
|
||||||
|
"ep_adminpads2_loading": "Loading…",
|
||||||
|
"ep_adminpads2_manage-pads": "Manage pads",
|
||||||
|
"ep_adminpads2_no-results": "No results",
|
||||||
|
"ep_adminpads2_pad-user-count": "Pad user count",
|
||||||
|
"ep_adminpads2_padname": "Padname",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Search term",
|
||||||
|
"ep_adminpads2_search-button.value": "Search",
|
||||||
|
"ep_adminpads2_search-done": "Search complete",
|
||||||
|
"ep_adminpads2_search-error-explanation": "The server encountered an error while searching for pads:",
|
||||||
|
"ep_adminpads2_search-error-title": "Failed to get pad list",
|
||||||
|
"ep_adminpads2_search-heading": "Search for pads",
|
||||||
|
"ep_adminpads2_title": "Pad administration",
|
||||||
|
"ep_adminpads2_unknown-error": "Unknown error",
|
||||||
|
"ep_adminpads2_unknown-status": "Unknown status"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/eu.json
Normal file
27
admin/public/ep_admin_pads/eu.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Izendegi"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Ekintza",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Automatikoki eguneratu pad-aren aldaketak daudenean",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Oraingo kontsultarako eguneratze automatikoak gaitu edo desgaitzen du.",
|
||||||
|
"ep_adminpads2_confirm": "Ziur zaude {{padID}} pad-a ezabatu nahi duzula?",
|
||||||
|
"ep_adminpads2_delete.value": "Ezabatu",
|
||||||
|
"ep_adminpads2_last-edited": "Azkenengoz editatua",
|
||||||
|
"ep_adminpads2_loading": "Kargatzen...",
|
||||||
|
"ep_adminpads2_manage-pads": "Kudeatu pad-ak",
|
||||||
|
"ep_adminpads2_no-results": "Emaitzarik ez",
|
||||||
|
"ep_adminpads2_pad-user-count": "Pad-erabiltzaile kopurua",
|
||||||
|
"ep_adminpads2_padname": "Pad-izena",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Bilaketa testua",
|
||||||
|
"ep_adminpads2_search-button.value": "Bilatu",
|
||||||
|
"ep_adminpads2_search-done": "Bilaketa osatu da",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Zerbitzariak errore bat izan du pad-ak bilatzean:",
|
||||||
|
"ep_adminpads2_search-error-title": "Pad-zerrenda eskuratzeak huts egin du",
|
||||||
|
"ep_adminpads2_search-heading": "Bilatu pad-ak",
|
||||||
|
"ep_adminpads2_title": "Pad-en kudeaketa",
|
||||||
|
"ep_adminpads2_unknown-error": "Errore ezezaguna",
|
||||||
|
"ep_adminpads2_unknown-status": "Egoera ezezaguna"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/ff.json
Normal file
27
admin/public/ep_admin_pads/ff.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Ibrahima Malal Sarr"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Baɗal",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Hesɗitin e jaajol tuma baylagol faɗo",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Hurminat walla daaƴa kesɗitine jaaje wonannde ɗaɓɓitannde wonaande.",
|
||||||
|
"ep_adminpads2_confirm": "Aɗa yiɗi e jaati momtude faɗo {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Momtu",
|
||||||
|
"ep_adminpads2_last-edited": "Taƴtaa sakket",
|
||||||
|
"ep_adminpads2_loading": "Nana loowa…",
|
||||||
|
"ep_adminpads2_manage-pads": "Toppito paɗe",
|
||||||
|
"ep_adminpads2_no-results": "Alaa njaltudi",
|
||||||
|
"ep_adminpads2_pad-user-count": "Limoore huutorɓe faɗo",
|
||||||
|
"ep_adminpads2_padname": "Innde faɗo",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Helmere njiilaw",
|
||||||
|
"ep_adminpads2_search-button.value": "Yiylo",
|
||||||
|
"ep_adminpads2_search-done": "Njiylaw timmii",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Sarworde ndee hawrii e juumre tuma nde yiylotoo faɗo:",
|
||||||
|
"ep_adminpads2_search-error-title": "Horiima heɓde doggol paɗe",
|
||||||
|
"ep_adminpads2_search-heading": "Yiylo paɗe",
|
||||||
|
"ep_adminpads2_title": "Yiylorde paɗe",
|
||||||
|
"ep_adminpads2_unknown-error": "Juumre nde anndaaka",
|
||||||
|
"ep_adminpads2_unknown-status": "Ngonka ka anndaaka"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/fi.json
Normal file
27
admin/public/ep_admin_pads/fi.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Artnay",
|
||||||
|
"Kyykaarme",
|
||||||
|
"MITO",
|
||||||
|
"Maantietäjä",
|
||||||
|
"Yupik"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Toiminto",
|
||||||
|
"ep_adminpads2_delete.value": "Poista",
|
||||||
|
"ep_adminpads2_last-edited": "Viimeksi muokattu",
|
||||||
|
"ep_adminpads2_loading": "Ladataan...",
|
||||||
|
"ep_adminpads2_manage-pads": "Hallitse muistioita",
|
||||||
|
"ep_adminpads2_no-results": "Ei tuloksia",
|
||||||
|
"ep_adminpads2_pad-user-count": "Pad-käyttäjien määrä",
|
||||||
|
"ep_adminpads2_padname": "Muistion nimi",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Haettava teksti",
|
||||||
|
"ep_adminpads2_search-button.value": "Etsi",
|
||||||
|
"ep_adminpads2_search-done": "Haku valmis",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Palvelimessa tapahtui virhe etsiessään muistioita:",
|
||||||
|
"ep_adminpads2_search-error-title": "Pad-luettelon hakeminen epäonnistui",
|
||||||
|
"ep_adminpads2_search-heading": "Etsi sisältöä",
|
||||||
|
"ep_adminpads2_unknown-error": "Tuntematon virhe",
|
||||||
|
"ep_adminpads2_unknown-status": "Tuntematon tila"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/fr.json
Normal file
27
admin/public/ep_admin_pads/fr.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Verdy p"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Action",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Mise à jour automatique en cas de changements du bloc-notes",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Active ou désactive les mises à jour automatiques pour la requête actuelle.",
|
||||||
|
"ep_adminpads2_confirm": "Voulez-vous vraiment supprimer le bloc-notes {{padID}} ?",
|
||||||
|
"ep_adminpads2_delete.value": "Supprimer",
|
||||||
|
"ep_adminpads2_last-edited": "Dernière modification",
|
||||||
|
"ep_adminpads2_loading": "Chargement en cours...",
|
||||||
|
"ep_adminpads2_manage-pads": "Gérer les bloc-notes",
|
||||||
|
"ep_adminpads2_no-results": "Aucun résultat",
|
||||||
|
"ep_adminpads2_pad-user-count": "Nombre d’utilisateurs du bloc-notes",
|
||||||
|
"ep_adminpads2_padname": "Nom du bloc-notes",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Terme de recherche",
|
||||||
|
"ep_adminpads2_search-button.value": "Rechercher",
|
||||||
|
"ep_adminpads2_search-done": "Recherche terminée",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Le serveur a rencontré une erreur en cherchant des blocs-notes :",
|
||||||
|
"ep_adminpads2_search-error-title": "Échec d’obtention de la liste de blocs-notes",
|
||||||
|
"ep_adminpads2_search-heading": "Rechercher des blocs-notes",
|
||||||
|
"ep_adminpads2_title": "Administration du bloc-notes",
|
||||||
|
"ep_adminpads2_unknown-error": "Erreur inconnue",
|
||||||
|
"ep_adminpads2_unknown-status": "État inconnu"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/gl.json
Normal file
27
admin/public/ep_admin_pads/gl.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Ghose"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Accións",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Actualización automática dos cambios",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Activa ou desactiva as actualizacións automáticas para a consulta actual.",
|
||||||
|
"ep_adminpads2_confirm": "Tes a certeza de querer eliminar o pad {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Eliminar",
|
||||||
|
"ep_adminpads2_last-edited": "Última edición",
|
||||||
|
"ep_adminpads2_loading": "Cargando…",
|
||||||
|
"ep_adminpads2_manage-pads": "Xestionar pads",
|
||||||
|
"ep_adminpads2_no-results": "Sen resultados",
|
||||||
|
"ep_adminpads2_pad-user-count": "Usuarias neste pad",
|
||||||
|
"ep_adminpads2_padname": "Nome do pad",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Buscar termo",
|
||||||
|
"ep_adminpads2_search-button.value": "Buscar",
|
||||||
|
"ep_adminpads2_search-done": "Busca completa",
|
||||||
|
"ep_adminpads2_search-error-explanation": "O servidor atopou un fallo cando buscaba pads:",
|
||||||
|
"ep_adminpads2_search-error-title": "Non se obtivo a lista de pads",
|
||||||
|
"ep_adminpads2_search-heading": "Buscar pads",
|
||||||
|
"ep_adminpads2_title": "Administración do pad",
|
||||||
|
"ep_adminpads2_unknown-error": "Erro descoñecido",
|
||||||
|
"ep_adminpads2_unknown-status": "Estado descoñecido"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/he.json
Normal file
27
admin/public/ep_admin_pads/he.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"YaronSh"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "פעולה",
|
||||||
|
"ep_adminpads2_autoupdate-label": "לעדכן אוטומטית כשהמחברת נערכת",
|
||||||
|
"ep_adminpads2_autoupdate.title": "הפעלה או השבתה של עדכונים אוטומטיים לשאילתה הנוכחית.",
|
||||||
|
"ep_adminpads2_confirm": "למחוק את המחברת {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "מחיקה",
|
||||||
|
"ep_adminpads2_last-edited": "עריכה אחרונה",
|
||||||
|
"ep_adminpads2_loading": "בטעינה…",
|
||||||
|
"ep_adminpads2_manage-pads": "ניהול מחברות",
|
||||||
|
"ep_adminpads2_no-results": "אין תוצאות",
|
||||||
|
"ep_adminpads2_pad-user-count": "ספירת משתמשים במחברת",
|
||||||
|
"ep_adminpads2_padname": "שם המחברת",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "הביטוי לחיפוש",
|
||||||
|
"ep_adminpads2_search-button.value": "חיפוש",
|
||||||
|
"ep_adminpads2_search-done": "החיפוש הושלם",
|
||||||
|
"ep_adminpads2_search-error-explanation": "השרת נתקל בשגיאה בעת חיפוש מחברות:",
|
||||||
|
"ep_adminpads2_search-error-title": "קבלת רשימת המחברות נכשלה",
|
||||||
|
"ep_adminpads2_search-heading": "חיפוש אחר מחברות",
|
||||||
|
"ep_adminpads2_title": "ניהול מחברות",
|
||||||
|
"ep_adminpads2_unknown-error": "שגיאה בלתי־ידועה",
|
||||||
|
"ep_adminpads2_unknown-status": "מצב לא ידוע"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/hsb.json
Normal file
27
admin/public/ep_admin_pads/hsb.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Michawiki"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Akcija",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Při změnach na zapisniku awtomatisce aktualizować",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Zmóžnja abo znjemóžnja awtomatiske aktualizacije za aktualne wotprašowanje.",
|
||||||
|
"ep_adminpads2_confirm": "Chceće woprawdźe zapisnik {{padID}} zhašeć?",
|
||||||
|
"ep_adminpads2_delete.value": "Zhašeć",
|
||||||
|
"ep_adminpads2_last-edited": "Poslednja změna",
|
||||||
|
"ep_adminpads2_loading": "Začituje so...",
|
||||||
|
"ep_adminpads2_manage-pads": "Zapisniki rjadować",
|
||||||
|
"ep_adminpads2_no-results": "Žane wuslědki.",
|
||||||
|
"ep_adminpads2_pad-user-count": "Ličba wužiwarjow zapisnika",
|
||||||
|
"ep_adminpads2_padname": "Mjeno zapisnika",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Pytanske zapřijeće",
|
||||||
|
"ep_adminpads2_search-button.value": "Pytać",
|
||||||
|
"ep_adminpads2_search-done": "Pytanje dokónčene",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Serwer je na zmylk storčił, mjeztym zo je za zapisnikami pytał:",
|
||||||
|
"ep_adminpads2_search-error-title": "Lisćina zapisnikow njeda so wobstarać",
|
||||||
|
"ep_adminpads2_search-heading": "Za zapisnikami pytać",
|
||||||
|
"ep_adminpads2_title": "Zapisnikowa administracija",
|
||||||
|
"ep_adminpads2_unknown-error": "Njeznaty zmylk",
|
||||||
|
"ep_adminpads2_unknown-status": "Njeznaty status"
|
||||||
|
}
|
25
admin/public/ep_admin_pads/hu.json
Normal file
25
admin/public/ep_admin_pads/hu.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": []
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Művelet",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Változáskor jegyzetfüzet önműködő frissítése",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Önműködő frissítése az jelenlegi lekérdezéshez be- vagy kikapcsolása.",
|
||||||
|
"ep_adminpads2_confirm": "Biztosan törölni szeretné a(z) {{padID}} jegyzetfüzetet?",
|
||||||
|
"ep_adminpads2_delete.value": "Törlés",
|
||||||
|
"ep_adminpads2_last-edited": "Utoljára szerkesztve",
|
||||||
|
"ep_adminpads2_loading": "Betöltés folyamatban…",
|
||||||
|
"ep_adminpads2_manage-pads": "Jegyzetfüzetek kezelése",
|
||||||
|
"ep_adminpads2_no-results": "Nincs találat",
|
||||||
|
"ep_adminpads2_pad-user-count": "Jegyzetfüzet felhasználók száma",
|
||||||
|
"ep_adminpads2_padname": "Jegyzetfüzet név",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Keresési kifejezés",
|
||||||
|
"ep_adminpads2_search-button.value": "Keresés",
|
||||||
|
"ep_adminpads2_search-done": "Keresés befejezve",
|
||||||
|
"ep_adminpads2_search-error-explanation": "A kiszolgáló hibát észlelt a jegyzetfüzetek keresésekor:",
|
||||||
|
"ep_adminpads2_search-error-title": "Nem sikerült lekérni a jegyzetfüzet listát",
|
||||||
|
"ep_adminpads2_search-heading": "Jegyzetfüzetek keresése",
|
||||||
|
"ep_adminpads2_title": "Jegyzetfüzet felügyelete",
|
||||||
|
"ep_adminpads2_unknown-error": "Ismeretlen hiba",
|
||||||
|
"ep_adminpads2_unknown-status": "Ismeretlen állapot"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/ia.json
Normal file
27
admin/public/ep_admin_pads/ia.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"McDutchie"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Action",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Actualisar automaticamente le pad in caso de cambiamentos",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Activa o disactiva le actualisationes automatic pro le consulta actual.",
|
||||||
|
"ep_adminpads2_confirm": "Es tu secur de voler deler le pad {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Deler",
|
||||||
|
"ep_adminpads2_last-edited": "Ultime modification",
|
||||||
|
"ep_adminpads2_loading": "Cargamento in curso…",
|
||||||
|
"ep_adminpads2_manage-pads": "Gerer pads",
|
||||||
|
"ep_adminpads2_no-results": "Nulle resultato",
|
||||||
|
"ep_adminpads2_pad-user-count": "Numero de usatores del pad",
|
||||||
|
"ep_adminpads2_padname": "Nomine del pad",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Termino de recerca",
|
||||||
|
"ep_adminpads2_search-button.value": "Cercar",
|
||||||
|
"ep_adminpads2_search-done": "Recerca terminate",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Le servitor ha incontrate un error durante le recerca de pads:",
|
||||||
|
"ep_adminpads2_search-error-title": "Non poteva obtener le lista de pads",
|
||||||
|
"ep_adminpads2_search-heading": "Cercar pads",
|
||||||
|
"ep_adminpads2_title": "Administration de pads",
|
||||||
|
"ep_adminpads2_unknown-error": "Error incognite",
|
||||||
|
"ep_adminpads2_unknown-status": "Stato incognite"
|
||||||
|
}
|
16
admin/public/ep_admin_pads/it.json
Normal file
16
admin/public/ep_admin_pads/it.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Beta16",
|
||||||
|
"Luca.favorido"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Azione",
|
||||||
|
"ep_adminpads2_delete.value": "Cancella",
|
||||||
|
"ep_adminpads2_last-edited": "Ultima modifica",
|
||||||
|
"ep_adminpads2_loading": "Caricamento…",
|
||||||
|
"ep_adminpads2_no-results": "Nessun risultato",
|
||||||
|
"ep_adminpads2_search-button.value": "Cerca",
|
||||||
|
"ep_adminpads2_unknown-error": "Errore sconosciuto",
|
||||||
|
"ep_adminpads2_unknown-status": "Stato sconosciuto"
|
||||||
|
}
|
13
admin/public/ep_admin_pads/kn.json
Normal file
13
admin/public/ep_admin_pads/kn.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"ಮಲ್ನಾಡಾಚ್ ಕೊಂಕ್ಣೊ"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "ಕ್ರಿಯೆ",
|
||||||
|
"ep_adminpads2_delete.value": "ಅಳಿಸು",
|
||||||
|
"ep_adminpads2_loading": "ತುಂಬಿಸಲಾಗುತ್ತಿದೆ…",
|
||||||
|
"ep_adminpads2_no-results": "ಯಾವ ಫಲಿತಾಂಶಗಳೂ ಇಲ್ಲ",
|
||||||
|
"ep_adminpads2_search-button.value": "ಹುಡುಕು",
|
||||||
|
"ep_adminpads2_unknown-error": "ಅಪರಿಚಿತ ದೋಷ"
|
||||||
|
}
|
28
admin/public/ep_admin_pads/ko.json
Normal file
28
admin/public/ep_admin_pads/ko.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Ykhwong",
|
||||||
|
"그냥기여자"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "동작",
|
||||||
|
"ep_adminpads2_autoupdate-label": "패드 변경 시 자동 업데이트",
|
||||||
|
"ep_adminpads2_autoupdate.title": "현재 쿼리의 자동 업데이트를 활성화하거나 비활성화합니다.",
|
||||||
|
"ep_adminpads2_confirm": "{{padID}} 패드를 삭제하시겠습니까?",
|
||||||
|
"ep_adminpads2_delete.value": "삭제",
|
||||||
|
"ep_adminpads2_last-edited": "최근 편집",
|
||||||
|
"ep_adminpads2_loading": "불러오는 중...",
|
||||||
|
"ep_adminpads2_manage-pads": "패드 관리",
|
||||||
|
"ep_adminpads2_no-results": "결과 없음",
|
||||||
|
"ep_adminpads2_pad-user-count": "패드 사용자 수",
|
||||||
|
"ep_adminpads2_padname": "패드 이름",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "검색어",
|
||||||
|
"ep_adminpads2_search-button.value": "검색",
|
||||||
|
"ep_adminpads2_search-done": "검색 완료",
|
||||||
|
"ep_adminpads2_search-error-explanation": "패드 검색 중 서버에 오류가 발생했습니다:",
|
||||||
|
"ep_adminpads2_search-error-title": "패드 목록 가져오기 실패",
|
||||||
|
"ep_adminpads2_search-heading": "패드 검색",
|
||||||
|
"ep_adminpads2_title": "패드 관리",
|
||||||
|
"ep_adminpads2_unknown-error": "알 수 없는 오류",
|
||||||
|
"ep_adminpads2_unknown-status": "알 수 없는 상태"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/krc.json
Normal file
27
admin/public/ep_admin_pads/krc.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Къарачайлы"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Этиу",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Блокнот тюрлендириулеринде автомат халда джангыртыу",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Баргъан излем ючюн автомат халда джангыртыуланы джандын неда джукълат.",
|
||||||
|
"ep_adminpads2_confirm": "{{padID}} блокнотну керти да кетерирге излеймисиз?",
|
||||||
|
"ep_adminpads2_delete.value": "Кетер",
|
||||||
|
"ep_adminpads2_last-edited": "Ахыр тюзетиу",
|
||||||
|
"ep_adminpads2_loading": "Джюклениу…",
|
||||||
|
"ep_adminpads2_manage-pads": "Блокнотланы оноуун эт",
|
||||||
|
"ep_adminpads2_no-results": "Эсебле джокъдула",
|
||||||
|
"ep_adminpads2_pad-user-count": "Блокнот хайырланыучуланы саны",
|
||||||
|
"ep_adminpads2_padname": "Блокнот ат",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Терминни изле",
|
||||||
|
"ep_adminpads2_search-button.value": "Изле",
|
||||||
|
"ep_adminpads2_search-done": "Излеу тамамланды",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Сервер, блокнотланы излеген заманда халат табды:",
|
||||||
|
"ep_adminpads2_search-error-title": "Блокнот тизмеси алынамады",
|
||||||
|
"ep_adminpads2_search-heading": "Блокнотла ючюн излеу",
|
||||||
|
"ep_adminpads2_title": "Блокнот башчылыкъ",
|
||||||
|
"ep_adminpads2_unknown-error": "Билинмеген халат",
|
||||||
|
"ep_adminpads2_unknown-status": "Билинмеген турум"
|
||||||
|
}
|
16
admin/public/ep_admin_pads/lb.json
Normal file
16
admin/public/ep_admin_pads/lb.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Robby",
|
||||||
|
"Volvox"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_confirm": "Wëllt Dir de Pad {{padID}} wierklech läschen?",
|
||||||
|
"ep_adminpads2_delete.value": "Läschen",
|
||||||
|
"ep_adminpads2_loading": "Lueden...",
|
||||||
|
"ep_adminpads2_no-results": "Keng Resultater",
|
||||||
|
"ep_adminpads2_padname": "Padnumm",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Sichbegrëff",
|
||||||
|
"ep_adminpads2_search-button.value": "Sichen",
|
||||||
|
"ep_adminpads2_unknown-error": "Onbekannte Feeler"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/lt.json
Normal file
27
admin/public/ep_admin_pads/lt.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Nokeoo"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Veiksmas",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Automatinis bloknoto keitimų naujinimas",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Įjungia arba išjungia automatinius dabartinės užklausos atnaujinimus.",
|
||||||
|
"ep_adminpads2_confirm": "Ar tikrai norite ištrinti bloknotą {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Ištrinti",
|
||||||
|
"ep_adminpads2_last-edited": "Paskutinis pakeitimas",
|
||||||
|
"ep_adminpads2_loading": "Įkeliama…",
|
||||||
|
"ep_adminpads2_manage-pads": "Tvarkyti bloknotą",
|
||||||
|
"ep_adminpads2_no-results": "Nėra rezultatų",
|
||||||
|
"ep_adminpads2_pad-user-count": "Bloknoto naudotojų skaičius",
|
||||||
|
"ep_adminpads2_padname": "Bloknoto pavadinimas",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Paieškos terminas",
|
||||||
|
"ep_adminpads2_search-button.value": "Paieška",
|
||||||
|
"ep_adminpads2_search-done": "Paieška baigta",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Serveris susidūrė su klaida ieškant bloknotų:",
|
||||||
|
"ep_adminpads2_search-error-title": "Nepavyko gauti bloknotų sąrašo",
|
||||||
|
"ep_adminpads2_search-heading": "Ieškokite bloknotų",
|
||||||
|
"ep_adminpads2_title": "Bloknotų administravimas",
|
||||||
|
"ep_adminpads2_unknown-error": "Nežinoma klaida",
|
||||||
|
"ep_adminpads2_unknown-status": "Nežinoma būsena"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/mk.json
Normal file
27
admin/public/ep_admin_pads/mk.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Bjankuloski06"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Дејство",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Самоподнова при измени во тетратката",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Овозможува или оневозможува самоподнова на тековното барање.",
|
||||||
|
"ep_adminpads2_confirm": "Дали навистина сакате да ја избришете тетратката {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Избриши",
|
||||||
|
"ep_adminpads2_last-edited": "Последно уредување",
|
||||||
|
"ep_adminpads2_loading": "Вчитувам…",
|
||||||
|
"ep_adminpads2_manage-pads": "Раководење со тетратки",
|
||||||
|
"ep_adminpads2_no-results": "Нема исход",
|
||||||
|
"ep_adminpads2_pad-user-count": "Корисници на тетратката",
|
||||||
|
"ep_adminpads2_padname": "Назив на тетратката",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Пребаран поим",
|
||||||
|
"ep_adminpads2_search-button.value": "Пребарај",
|
||||||
|
"ep_adminpads2_search-done": "Пребарувањето заврши",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Опслужувачот наиде на грешка при пребарувањето на тетратки:",
|
||||||
|
"ep_adminpads2_search-error-title": "Не можев да го добијам списокот на тетратки",
|
||||||
|
"ep_adminpads2_search-heading": "Пребарај по тетратките",
|
||||||
|
"ep_adminpads2_title": "Администрација на тетратки",
|
||||||
|
"ep_adminpads2_unknown-error": "Непозната грешка",
|
||||||
|
"ep_adminpads2_unknown-status": "Непозната состојба"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/my.json
Normal file
27
admin/public/ep_admin_pads/my.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Andibecker"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "လုပ်ဆောင်ချက်",
|
||||||
|
"ep_adminpads2_autoupdate-label": "pad အပြောင်းအလဲများတွင်အလိုအလျောက်အပ်ဒိတ်လုပ်ပါ",
|
||||||
|
"ep_adminpads2_autoupdate.title": "လက်ရှိမေးမြန်းမှုအတွက်အလိုအလျောက်အပ်ဒိတ်များကိုဖွင့်ပါသို့မဟုတ်ပိတ်ပါ။",
|
||||||
|
"ep_adminpads2_confirm": "pad {{padID}} ကိုသင်တကယ်ဖျက်ချင်လား။",
|
||||||
|
"ep_adminpads2_delete.value": "ဖျက်ပါ",
|
||||||
|
"ep_adminpads2_last-edited": "နောက်ဆုံးတည်းဖြတ်သည်",
|
||||||
|
"ep_adminpads2_loading": "ဖွင့်နေသည်…",
|
||||||
|
"ep_adminpads2_manage-pads": "pads များကိုစီမံပါ",
|
||||||
|
"ep_adminpads2_no-results": "ရလဒ်မရှိပါ",
|
||||||
|
"ep_adminpads2_pad-user-count": "Pad အသုံးပြုသူအရေအတွက်",
|
||||||
|
"ep_adminpads2_padname": "Padname",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "ဝေါဟာရရှာဖွေပါ",
|
||||||
|
"ep_adminpads2_search-button.value": "ရှာဖွေပါ",
|
||||||
|
"ep_adminpads2_search-done": "ရှာဖွေမှုပြီးပါပြီ",
|
||||||
|
"ep_adminpads2_search-error-explanation": "pads များကိုရှာဖွေစဉ်ဆာဗာသည်အမှားတစ်ခုကြုံခဲ့သည်။",
|
||||||
|
"ep_adminpads2_search-error-title": "pad စာရင်းရယူရန်မအောင်မြင်ပါ",
|
||||||
|
"ep_adminpads2_search-heading": "pads များကိုရှာဖွေပါ",
|
||||||
|
"ep_adminpads2_title": "Pad စီမံခန့်ခွဲမှု",
|
||||||
|
"ep_adminpads2_unknown-error": "အမည်မသိအမှား",
|
||||||
|
"ep_adminpads2_unknown-status": "အခြေအနေမသိ"
|
||||||
|
}
|
13
admin/public/ep_admin_pads/nb.json
Normal file
13
admin/public/ep_admin_pads/nb.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"EdoAug"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Handling",
|
||||||
|
"ep_adminpads2_last-edited": "Sist redigert",
|
||||||
|
"ep_adminpads2_loading": "Laster …",
|
||||||
|
"ep_adminpads2_no-results": "Ingen resultater",
|
||||||
|
"ep_adminpads2_search-button.value": "Søk",
|
||||||
|
"ep_adminpads2_search-done": "Søk fullført"
|
||||||
|
}
|
29
admin/public/ep_admin_pads/nl.json
Normal file
29
admin/public/ep_admin_pads/nl.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Aranka",
|
||||||
|
"McDutchie",
|
||||||
|
"Spinster"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Handeling",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Automatisch bijwerken bij aanpassingen aan de pad",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Schakelt automatische updates voor de huidige query in of uit.",
|
||||||
|
"ep_adminpads2_confirm": "Wil je de pad {{padID}} echt verwijderen?",
|
||||||
|
"ep_adminpads2_delete.value": "Verwijderen",
|
||||||
|
"ep_adminpads2_last-edited": "Laatst bewerkt",
|
||||||
|
"ep_adminpads2_loading": "Bezig met laden...",
|
||||||
|
"ep_adminpads2_manage-pads": "Pads beheren",
|
||||||
|
"ep_adminpads2_no-results": "Geen resultaten",
|
||||||
|
"ep_adminpads2_pad-user-count": "Aantal gebruikers van de pad",
|
||||||
|
"ep_adminpads2_padname": "Naam van de pad",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Zoekterm",
|
||||||
|
"ep_adminpads2_search-button.value": "Zoeken",
|
||||||
|
"ep_adminpads2_search-done": "Zoekopdracht voltooid",
|
||||||
|
"ep_adminpads2_search-error-explanation": "De server heeft een fout aangetroffen tijdens het zoeken naar pads:",
|
||||||
|
"ep_adminpads2_search-error-title": "Kan lijst met pads niet ophalen",
|
||||||
|
"ep_adminpads2_search-heading": "Pads zoeken",
|
||||||
|
"ep_adminpads2_title": "Administratie van pad",
|
||||||
|
"ep_adminpads2_unknown-error": "Onbekende fout",
|
||||||
|
"ep_adminpads2_unknown-status": "Onbekende status"
|
||||||
|
}
|
21
admin/public/ep_admin_pads/oc.json
Normal file
21
admin/public/ep_admin_pads/oc.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Quentí"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Accion",
|
||||||
|
"ep_adminpads2_delete.value": "Suprimir",
|
||||||
|
"ep_adminpads2_last-edited": "Darrièra edicion",
|
||||||
|
"ep_adminpads2_loading": "Cargament…",
|
||||||
|
"ep_adminpads2_manage-pads": "Gerir los pads",
|
||||||
|
"ep_adminpads2_no-results": "Pas cap de resultat",
|
||||||
|
"ep_adminpads2_padname": "Nom del pad",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Tèrme de recèrca",
|
||||||
|
"ep_adminpads2_search-button.value": "Recercar",
|
||||||
|
"ep_adminpads2_search-done": "Recèrca acabada",
|
||||||
|
"ep_adminpads2_search-heading": "Cercar de pads",
|
||||||
|
"ep_adminpads2_title": "Administracion de pad",
|
||||||
|
"ep_adminpads2_unknown-error": "Error desconeguda",
|
||||||
|
"ep_adminpads2_unknown-status": "Estat desconegut"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/pms.json
Normal file
27
admin/public/ep_admin_pads/pms.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Borichèt"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Assion",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Agiornament automàtich an sle modìfiche ëd plancia",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Abilité o disabilité j'agiornament automàtich për l'arcesta atual.",
|
||||||
|
"ep_adminpads2_confirm": "Veul-lo për da bon dëscancelé la plancia {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Dëscancelé",
|
||||||
|
"ep_adminpads2_last-edited": "Modificà l'ùltima vira",
|
||||||
|
"ep_adminpads2_loading": "Cariament…",
|
||||||
|
"ep_adminpads2_manage-pads": "Gestì le plance",
|
||||||
|
"ep_adminpads2_no-results": "Gnun arzultà",
|
||||||
|
"ep_adminpads2_pad-user-count": "Conteur ëd plancia dl'utent",
|
||||||
|
"ep_adminpads2_padname": "Nòm ëd plancia",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Tèrmin d'arserca",
|
||||||
|
"ep_adminpads2_search-button.value": "Arserca",
|
||||||
|
"ep_adminpads2_search-done": "Arserca completà",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Ël servent a l'ha rancontrà n'eror an sërcand dle plance:",
|
||||||
|
"ep_adminpads2_search-error-title": "Falì a oten-e la lista ëd plance",
|
||||||
|
"ep_adminpads2_search-heading": "Arserca ëd plance",
|
||||||
|
"ep_adminpads2_title": "Aministrassion ëd plance",
|
||||||
|
"ep_adminpads2_unknown-error": "Eror nen conossù",
|
||||||
|
"ep_adminpads2_unknown-status": "Statù nen conossù"
|
||||||
|
}
|
30
admin/public/ep_admin_pads/pt-br.json
Normal file
30
admin/public/ep_admin_pads/pt-br.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Duke of Wikipädia",
|
||||||
|
"Eduardo Addad de Oliveira",
|
||||||
|
"Eduardoaddad",
|
||||||
|
"YuriNikolai"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Ação",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Atualizar notas automaticamente",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Habilita ou desabilita atualizações automáticas para a consulta atual.",
|
||||||
|
"ep_adminpads2_confirm": "Você realmente deseja excluir a nota {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Excluir",
|
||||||
|
"ep_adminpads2_last-edited": "Última edição",
|
||||||
|
"ep_adminpads2_loading": "Carregando…",
|
||||||
|
"ep_adminpads2_manage-pads": "Gerenciar notas",
|
||||||
|
"ep_adminpads2_no-results": "Sem resultados",
|
||||||
|
"ep_adminpads2_pad-user-count": "Número de utilizadores na nota",
|
||||||
|
"ep_adminpads2_padname": "Nome da nota",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Termo de pesquisa",
|
||||||
|
"ep_adminpads2_search-button.value": "Pesquisar",
|
||||||
|
"ep_adminpads2_search-done": "Busca completa",
|
||||||
|
"ep_adminpads2_search-error-explanation": "O servidor encontrou um erro enquanto procurava por notas:",
|
||||||
|
"ep_adminpads2_search-error-title": "Falha ao buscar lista de notas",
|
||||||
|
"ep_adminpads2_search-heading": "Pesquisar por notas",
|
||||||
|
"ep_adminpads2_title": "Administração de notas",
|
||||||
|
"ep_adminpads2_unknown-error": "Erro desconhecido",
|
||||||
|
"ep_adminpads2_unknown-status": "Status desconhecido"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/pt.json
Normal file
27
admin/public/ep_admin_pads/pt.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Guilha"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Ação",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Atualizar automaticamente as notas",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Ativa ou desativa atualizações automáticas na consulta atual.",
|
||||||
|
"ep_adminpads2_confirm": "Tencionas mesmo eliminar a nota {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Eliminar",
|
||||||
|
"ep_adminpads2_last-edited": "Última edição",
|
||||||
|
"ep_adminpads2_loading": "A carregar...",
|
||||||
|
"ep_adminpads2_manage-pads": "Gerir notas",
|
||||||
|
"ep_adminpads2_no-results": "Sem resultados",
|
||||||
|
"ep_adminpads2_pad-user-count": "Número de utilizadores na nota",
|
||||||
|
"ep_adminpads2_padname": "Nome da nota",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Procurar termo",
|
||||||
|
"ep_adminpads2_search-button.value": "Procurar",
|
||||||
|
"ep_adminpads2_search-done": "Procura completa",
|
||||||
|
"ep_adminpads2_search-error-explanation": "O servidor encontrou um erro enquanto procurava por notas:",
|
||||||
|
"ep_adminpads2_search-error-title": "Falha ao obter lista de notas",
|
||||||
|
"ep_adminpads2_search-heading": "Procurar por notas",
|
||||||
|
"ep_adminpads2_title": "Administração da nota",
|
||||||
|
"ep_adminpads2_unknown-error": "Erro desconhecido",
|
||||||
|
"ep_adminpads2_unknown-status": "Estado desconhecido"
|
||||||
|
}
|
10
admin/public/ep_admin_pads/qqq.json
Normal file
10
admin/public/ep_admin_pads/qqq.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"BryanDavis"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "{{Identical|Action}}",
|
||||||
|
"ep_adminpads2_delete.value": "{{Identical|Delete}}",
|
||||||
|
"ep_adminpads2_search-button.value": "{{Identical|Search}}"
|
||||||
|
}
|
31
admin/public/ep_admin_pads/ru.json
Normal file
31
admin/public/ep_admin_pads/ru.json
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"DDPAT",
|
||||||
|
"Ice bulldog",
|
||||||
|
"Megakott",
|
||||||
|
"Okras",
|
||||||
|
"Pacha Tchernof"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Действие",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Автообновление при изменении документа",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Включает или отключает автоматические обновления для текущего запроса.",
|
||||||
|
"ep_adminpads2_confirm": "Вы действительно хотите удалить документ {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Удалить",
|
||||||
|
"ep_adminpads2_last-edited": "Последнее изменение",
|
||||||
|
"ep_adminpads2_loading": "Загружается…",
|
||||||
|
"ep_adminpads2_manage-pads": "Управление документами",
|
||||||
|
"ep_adminpads2_no-results": "Нет результатов",
|
||||||
|
"ep_adminpads2_pad-user-count": "Количество пользователей документа",
|
||||||
|
"ep_adminpads2_padname": "Название документа",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Искать термин",
|
||||||
|
"ep_adminpads2_search-button.value": "Найти",
|
||||||
|
"ep_adminpads2_search-done": "Поиск завершён",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Сервер обнаружил ошибку при поиске документов:",
|
||||||
|
"ep_adminpads2_search-error-title": "Не удалось получить список документов",
|
||||||
|
"ep_adminpads2_search-heading": "Поиск документов",
|
||||||
|
"ep_adminpads2_title": "Администрирование документов",
|
||||||
|
"ep_adminpads2_unknown-error": "Неизвестная ошибка",
|
||||||
|
"ep_adminpads2_unknown-status": "Неизвестный статус"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/sc.json
Normal file
27
admin/public/ep_admin_pads/sc.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Adr mm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Atzione",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Atualizatzione automàtica de is modìficas de su pad",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Ativat o disativat is atualizatziones automàticas pro sa chirca atuale.",
|
||||||
|
"ep_adminpads2_confirm": "Seguru chi boles cantzellare su pad {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Cantzella",
|
||||||
|
"ep_adminpads2_last-edited": "Ùrtima modìfica",
|
||||||
|
"ep_adminpads2_loading": "Carrighende...",
|
||||||
|
"ep_adminpads2_manage-pads": "Gesti is pads",
|
||||||
|
"ep_adminpads2_no-results": "Nissunu resurtadu",
|
||||||
|
"ep_adminpads2_pad-user-count": "Nùmeru de utentes de pads",
|
||||||
|
"ep_adminpads2_padname": "Nòmine de su pad",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Tèrmine de chirca",
|
||||||
|
"ep_adminpads2_search-button.value": "Chirca",
|
||||||
|
"ep_adminpads2_search-done": "Chirca cumpleta",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Su serbidore at agatadu un'errore chirchende pads:",
|
||||||
|
"ep_adminpads2_search-error-title": "Impossìbile otènnere sa lista de pads",
|
||||||
|
"ep_adminpads2_search-heading": "Chirca pads",
|
||||||
|
"ep_adminpads2_title": "Amministratzione de su pad",
|
||||||
|
"ep_adminpads2_unknown-error": "Errore disconnotu",
|
||||||
|
"ep_adminpads2_unknown-status": "Istadu disconnotu"
|
||||||
|
}
|
14
admin/public/ep_admin_pads/sdc.json
Normal file
14
admin/public/ep_admin_pads/sdc.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"F Samaritani"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Azioni",
|
||||||
|
"ep_adminpads2_delete.value": "Canzella",
|
||||||
|
"ep_adminpads2_loading": "carrigghendi...",
|
||||||
|
"ep_adminpads2_no-results": "Nisciun risulthaddu",
|
||||||
|
"ep_adminpads2_search-button.value": "Zercha",
|
||||||
|
"ep_adminpads2_search-heading": "Zirchà dati",
|
||||||
|
"ep_adminpads2_unknown-error": "Errori ischunisciddu"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/sk.json
Normal file
27
admin/public/ep_admin_pads/sk.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Yardom78"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Akcia",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Automatická aktualizácia zmien na poznámkovom bloku",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Zapne alebo vypne automatickú aktualizáciu.",
|
||||||
|
"ep_adminpads2_confirm": "Skutočne chcete vymazať poznámkový blok {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Vymazať",
|
||||||
|
"ep_adminpads2_last-edited": "Posledná úprava",
|
||||||
|
"ep_adminpads2_loading": "Načítavanie...",
|
||||||
|
"ep_adminpads2_manage-pads": "Spravovať poznámkové bloky",
|
||||||
|
"ep_adminpads2_no-results": "Žiadne výsledky",
|
||||||
|
"ep_adminpads2_pad-user-count": "Počet používateľov poznámkového bloku",
|
||||||
|
"ep_adminpads2_padname": "Názov poznámkového bloku",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Hľadať výraz",
|
||||||
|
"ep_adminpads2_search-button.value": "Hľadať",
|
||||||
|
"ep_adminpads2_search-done": "Hľadanie dokončené",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Pri hľadaní poznámkového bloku došlo k chybe:",
|
||||||
|
"ep_adminpads2_search-error-title": "Nepodarilo sa získať zoznam poznámkových blokov",
|
||||||
|
"ep_adminpads2_search-heading": "Hľadať poznámkový blok",
|
||||||
|
"ep_adminpads2_title": "Správa poznámkového bloku",
|
||||||
|
"ep_adminpads2_unknown-error": "Neznáma chyba",
|
||||||
|
"ep_adminpads2_unknown-status": "Neznámy stav"
|
||||||
|
}
|
20
admin/public/ep_admin_pads/skr-arab.json
Normal file
20
admin/public/ep_admin_pads/skr-arab.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Saraiki"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "عمل",
|
||||||
|
"ep_adminpads2_delete.value": "مٹاؤ",
|
||||||
|
"ep_adminpads2_last-edited": "چھیکڑی تبدیلی",
|
||||||
|
"ep_adminpads2_loading": "لوڈ تھین٘دا پئے۔۔۔",
|
||||||
|
"ep_adminpads2_manage-pads": "پیڈ منیج کرو",
|
||||||
|
"ep_adminpads2_no-results": "کوئی نتیجہ کائنی",
|
||||||
|
"ep_adminpads2_padname": "پیڈ ناں",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "ٹرم ڳولو",
|
||||||
|
"ep_adminpads2_search-button.value": "ڳولو",
|
||||||
|
"ep_adminpads2_search-done": "ڳولݨ پورا تھیا",
|
||||||
|
"ep_adminpads2_search-heading": "پیڈاں دی ڳول",
|
||||||
|
"ep_adminpads2_unknown-error": "نامعلوم غلطی",
|
||||||
|
"ep_adminpads2_unknown-status": "نامعلوم حالت"
|
||||||
|
}
|
28
admin/public/ep_admin_pads/sl.json
Normal file
28
admin/public/ep_admin_pads/sl.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Eleassar",
|
||||||
|
"HairyFotr"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Dejanje",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Samodejno posodabljanje ob spremembah blokcev",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Omogoči ali onemogoči samodejne posodobitve za trenutno poizvedbo.",
|
||||||
|
"ep_adminpads2_confirm": "Ali res želite izbrisati blokec {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Izbriši",
|
||||||
|
"ep_adminpads2_last-edited": "Zadnje urejanje",
|
||||||
|
"ep_adminpads2_loading": "Nalaganje ...",
|
||||||
|
"ep_adminpads2_manage-pads": "Upravljanje blokcev",
|
||||||
|
"ep_adminpads2_no-results": "Ni zadetkov",
|
||||||
|
"ep_adminpads2_pad-user-count": "Število urejevalcev blokca",
|
||||||
|
"ep_adminpads2_padname": "Ime blokca",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Iskalni izraz",
|
||||||
|
"ep_adminpads2_search-button.value": "Išči",
|
||||||
|
"ep_adminpads2_search-done": "Iskanje končano",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Strežnik je med iskanjem blokcev naletel na napako:",
|
||||||
|
"ep_adminpads2_search-error-title": "Ni bilo mogoče pridobiti seznama blokcev",
|
||||||
|
"ep_adminpads2_search-heading": "Iskanje blokcev",
|
||||||
|
"ep_adminpads2_title": "Upravljanje blokcev",
|
||||||
|
"ep_adminpads2_unknown-error": "Neznana napaka",
|
||||||
|
"ep_adminpads2_unknown-status": "Neznano stanje"
|
||||||
|
}
|
13
admin/public/ep_admin_pads/smn.json
Normal file
13
admin/public/ep_admin_pads/smn.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Yupik"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_delete.value": "Siho",
|
||||||
|
"ep_adminpads2_last-edited": "Majemustáá nubástittum",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Uuccâmsääni",
|
||||||
|
"ep_adminpads2_search-button.value": "Uusâ",
|
||||||
|
"ep_adminpads2_unknown-error": "Tubdâmettum feilâ",
|
||||||
|
"ep_adminpads2_unknown-status": "Tubdâmettum tile"
|
||||||
|
}
|
16
admin/public/ep_admin_pads/sms.json
Normal file
16
admin/public/ep_admin_pads/sms.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Yupik"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_delete.value": "Jaukkâd",
|
||||||
|
"ep_adminpads2_last-edited": "Mââimõssân muttum",
|
||||||
|
"ep_adminpads2_no-results": "Ij käunnʼjam ni mii",
|
||||||
|
"ep_adminpads2_padname": "Mošttʼtõspõʹmmai nõmm",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Ooccâmsääʹnn",
|
||||||
|
"ep_adminpads2_search-button.value": "Ooʒʒ",
|
||||||
|
"ep_adminpads2_search-heading": "Ooʒʒ mošttʼtõspõʹmmjid",
|
||||||
|
"ep_adminpads2_unknown-error": "Toobdteʹmes vââʹǩǩ",
|
||||||
|
"ep_adminpads2_unknown-status": "Toobdteʹmes status"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/sq.json
Normal file
27
admin/public/ep_admin_pads/sq.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Besnik b"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Veprim",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Vetëpërditësohu, kur nga ndryshime blloku",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Aktivizon ose çaktivizon përditësim të automatizuara për kërkesën e tanishme.",
|
||||||
|
"ep_adminpads2_confirm": "Doni vërtet të fshihet blloku {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Fshije",
|
||||||
|
"ep_adminpads2_last-edited": "Përpunuar së fundi më",
|
||||||
|
"ep_adminpads2_loading": "Po ngarkohet…",
|
||||||
|
"ep_adminpads2_manage-pads": "Administroni blloqe",
|
||||||
|
"ep_adminpads2_no-results": "S’ka përfundime",
|
||||||
|
"ep_adminpads2_pad-user-count": "Numër përdoruesish blloku",
|
||||||
|
"ep_adminpads2_padname": "Emër blloku",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Term kërkimi",
|
||||||
|
"ep_adminpads2_search-button.value": "Kërko",
|
||||||
|
"ep_adminpads2_search-done": "Kërkim i plotë",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Shërbyesi hasi një gabim teksa kërkohej për blloqe:",
|
||||||
|
"ep_adminpads2_search-error-title": "S’u arrit të merrej listë blloqesh",
|
||||||
|
"ep_adminpads2_search-heading": "Kërkoni për blloqe",
|
||||||
|
"ep_adminpads2_title": "Administrim blloku",
|
||||||
|
"ep_adminpads2_unknown-error": "Gabim i panjohur",
|
||||||
|
"ep_adminpads2_unknown-status": "Gjendje e panjohur"
|
||||||
|
}
|
28
admin/public/ep_admin_pads/sv.json
Normal file
28
admin/public/ep_admin_pads/sv.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Bengtsson96",
|
||||||
|
"WikiPhoenix"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Åtgärd",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Uppdatera automatiskt när blocket ändras",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Aktivera eller inaktivera automatiska uppdatering för nuvarande förfrågan.",
|
||||||
|
"ep_adminpads2_confirm": "Vill du verkligen radera blocket {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Radera",
|
||||||
|
"ep_adminpads2_last-edited": "Senast redigerad",
|
||||||
|
"ep_adminpads2_loading": "Läser in …",
|
||||||
|
"ep_adminpads2_manage-pads": "Hantera block",
|
||||||
|
"ep_adminpads2_no-results": "Inga resultat",
|
||||||
|
"ep_adminpads2_pad-user-count": "Antal blockanvändare",
|
||||||
|
"ep_adminpads2_padname": "Blocknamn",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Sökord",
|
||||||
|
"ep_adminpads2_search-button.value": "Sök",
|
||||||
|
"ep_adminpads2_search-done": "Sökning slutförd",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Servern stötte på ett fel vid sökning efter block:",
|
||||||
|
"ep_adminpads2_search-error-title": "Misslyckades att hämta blocklista",
|
||||||
|
"ep_adminpads2_search-heading": "Sök efter block",
|
||||||
|
"ep_adminpads2_title": "Blockadministration",
|
||||||
|
"ep_adminpads2_unknown-error": "Okänt fel",
|
||||||
|
"ep_adminpads2_unknown-status": "Okänd status"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/sw.json
Normal file
27
admin/public/ep_admin_pads/sw.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Andibecker"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Hatua",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Sasisha kiotomatiki kwenye mabadiliko ya pedi",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Huwasha au kulemaza sasisho otomatiki kwa hoja ya sasa.",
|
||||||
|
"ep_adminpads2_confirm": "Je! Kweli unataka kufuta pedi {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Futa",
|
||||||
|
"ep_adminpads2_last-edited": "Ilihaririwa mwisho",
|
||||||
|
"ep_adminpads2_loading": "Inapakia...",
|
||||||
|
"ep_adminpads2_manage-pads": "Dhibiti pedi",
|
||||||
|
"ep_adminpads2_no-results": "Hakuna matokeo",
|
||||||
|
"ep_adminpads2_pad-user-count": "Hesabu ya mtumiaji wa pedi",
|
||||||
|
"ep_adminpads2_padname": "Jina la utani",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Neno la utaftaji",
|
||||||
|
"ep_adminpads2_search-button.value": "Tafuta",
|
||||||
|
"ep_adminpads2_search-done": "Utafutaji umekamilika",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Seva ilipata hitilafu wakati wa kutafuta pedi:",
|
||||||
|
"ep_adminpads2_search-error-title": "Imeshindwa kupata orodha ya pedi",
|
||||||
|
"ep_adminpads2_search-heading": "Tafuta pedi",
|
||||||
|
"ep_adminpads2_title": "Usimamizi wa pedi",
|
||||||
|
"ep_adminpads2_unknown-error": "Hitilafu isiyojulikana",
|
||||||
|
"ep_adminpads2_unknown-status": "Hali isiyojulikana"
|
||||||
|
}
|
27
admin/public/ep_admin_pads/th.json
Normal file
27
admin/public/ep_admin_pads/th.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Andibecker"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "การกระทำ",
|
||||||
|
"ep_adminpads2_autoupdate-label": "อัปเดตอัตโนมัติเมื่อเปลี่ยนแผ่น",
|
||||||
|
"ep_adminpads2_autoupdate.title": "เปิดหรือปิดการอัปเดตอัตโนมัติสำหรับคิวรีปัจจุบัน",
|
||||||
|
"ep_adminpads2_confirm": "คุณต้องการลบแพด {{padID}} จริงหรือไม่",
|
||||||
|
"ep_adminpads2_delete.value": "ลบ",
|
||||||
|
"ep_adminpads2_last-edited": "แก้ไขล่าสุด",
|
||||||
|
"ep_adminpads2_loading": "กำลังโหลด…",
|
||||||
|
"ep_adminpads2_manage-pads": "จัดการแผ่นรอง",
|
||||||
|
"ep_adminpads2_no-results": "ไม่มีผลลัพธ์",
|
||||||
|
"ep_adminpads2_pad-user-count": "จำนวนผู้ใช้แพด",
|
||||||
|
"ep_adminpads2_padname": "นามแฝง",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "คำที่ต้องการค้นหา",
|
||||||
|
"ep_adminpads2_search-button.value": "ค้นหา",
|
||||||
|
"ep_adminpads2_search-done": "ค้นหาเสร็จสมบูรณ์",
|
||||||
|
"ep_adminpads2_search-error-explanation": "เซิร์ฟเวอร์พบข้อผิดพลาดขณะค้นหาแผ่นอิเล็กโทรด:",
|
||||||
|
"ep_adminpads2_search-error-title": "ไม่สามารถรับรายการแผ่นรอง",
|
||||||
|
"ep_adminpads2_search-heading": "ค้นหาแผ่นรอง",
|
||||||
|
"ep_adminpads2_title": "การบริหารแผ่น",
|
||||||
|
"ep_adminpads2_unknown-error": "ข้อผิดพลาดที่ไม่รู้จัก",
|
||||||
|
"ep_adminpads2_unknown-status": "ไม่ทราบสถานะ"
|
||||||
|
}
|
17
admin/public/ep_admin_pads/tl.json
Normal file
17
admin/public/ep_admin_pads/tl.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Mrkczr"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Kilos",
|
||||||
|
"ep_adminpads2_delete.value": "Burahin",
|
||||||
|
"ep_adminpads2_last-edited": "Huling binago",
|
||||||
|
"ep_adminpads2_loading": "Naglo-load...",
|
||||||
|
"ep_adminpads2_no-results": "Walang mga resulta",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Mga katagang hahanapin:",
|
||||||
|
"ep_adminpads2_search-button.value": "Hanapin",
|
||||||
|
"ep_adminpads2_search-done": "Natapos na ang paghahanap",
|
||||||
|
"ep_adminpads2_unknown-error": "Hindi nalalamang kamalian",
|
||||||
|
"ep_adminpads2_unknown-status": "Hindi alam na katayuan"
|
||||||
|
}
|
28
admin/public/ep_admin_pads/tr.json
Normal file
28
admin/public/ep_admin_pads/tr.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"Hedda",
|
||||||
|
"MuratTheTurkish"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Eylem",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Bloknot değişikliklerinde otomatik güncelleme",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Mevcut sorgu için otomatik güncellemeleri etkinleştirir veya devre dışı bırakır.",
|
||||||
|
"ep_adminpads2_confirm": "{{padID}} bloknotunu gerçekten silmek istiyor musunuz?",
|
||||||
|
"ep_adminpads2_delete.value": "Sil",
|
||||||
|
"ep_adminpads2_last-edited": "Son düzenleme",
|
||||||
|
"ep_adminpads2_loading": "Yükleniyor...",
|
||||||
|
"ep_adminpads2_manage-pads": "Bloknotları yönet",
|
||||||
|
"ep_adminpads2_no-results": "Sonuç yok",
|
||||||
|
"ep_adminpads2_pad-user-count": "Bloknot kullanıcı sayısı",
|
||||||
|
"ep_adminpads2_padname": "Bloknot adı",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Terimi ara",
|
||||||
|
"ep_adminpads2_search-button.value": "Ara",
|
||||||
|
"ep_adminpads2_search-done": "Arama tamamlandı",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Sunucu, bloknotları ararken bir hatayla karşılaştı:",
|
||||||
|
"ep_adminpads2_search-error-title": "Bloknot listesi alınamadı",
|
||||||
|
"ep_adminpads2_search-heading": "Bloknotları ara",
|
||||||
|
"ep_adminpads2_title": "Bloknot yönetimi",
|
||||||
|
"ep_adminpads2_unknown-error": "Bilinmeyen hata",
|
||||||
|
"ep_adminpads2_unknown-status": "Bilinmeyen durum"
|
||||||
|
}
|
28
admin/public/ep_admin_pads/uk.json
Normal file
28
admin/public/ep_admin_pads/uk.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"DDPAT",
|
||||||
|
"Ice bulldog"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "Дія",
|
||||||
|
"ep_adminpads2_autoupdate-label": "Автоматичне оновлення при зміні майданчика",
|
||||||
|
"ep_adminpads2_autoupdate.title": "Вмикає або вимикає автоматичне оновлення поточного запиту.",
|
||||||
|
"ep_adminpads2_confirm": "Ви дійсно хочете видалити панель {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "Видалити",
|
||||||
|
"ep_adminpads2_last-edited": "Останнє редагування",
|
||||||
|
"ep_adminpads2_loading": "Завантаження…",
|
||||||
|
"ep_adminpads2_manage-pads": "Управління майданчиками",
|
||||||
|
"ep_adminpads2_no-results": "Немає результатів",
|
||||||
|
"ep_adminpads2_pad-user-count": "Кількість майданчиків користувача",
|
||||||
|
"ep_adminpads2_padname": "Назва майданчика",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "Пошуковий термін",
|
||||||
|
"ep_adminpads2_search-button.value": "Пошук",
|
||||||
|
"ep_adminpads2_search-done": "Пошук завершено",
|
||||||
|
"ep_adminpads2_search-error-explanation": "Під час пошуку педів сервер виявив помилку:",
|
||||||
|
"ep_adminpads2_search-error-title": "Не вдалося отримати список панелей",
|
||||||
|
"ep_adminpads2_search-heading": "Пошук майданчиків",
|
||||||
|
"ep_adminpads2_title": "Введення майданчиків",
|
||||||
|
"ep_adminpads2_unknown-error": "Невідома помилка",
|
||||||
|
"ep_adminpads2_unknown-status": "Невідомий статус"
|
||||||
|
}
|
29
admin/public/ep_admin_pads/zh-hans.json
Normal file
29
admin/public/ep_admin_pads/zh-hans.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"GuoPC",
|
||||||
|
"Lakejason0",
|
||||||
|
"沈澄心"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "操作",
|
||||||
|
"ep_adminpads2_autoupdate-label": "在记事本更改时自动更新",
|
||||||
|
"ep_adminpads2_autoupdate.title": "启用或禁用目前查询的自动更新",
|
||||||
|
"ep_adminpads2_confirm": "您确定要删除记事本 {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "删除",
|
||||||
|
"ep_adminpads2_last-edited": "上次编辑于",
|
||||||
|
"ep_adminpads2_loading": "正在加载…",
|
||||||
|
"ep_adminpads2_manage-pads": "管理记事本",
|
||||||
|
"ep_adminpads2_no-results": "没有结果",
|
||||||
|
"ep_adminpads2_pad-user-count": "记事本用户数",
|
||||||
|
"ep_adminpads2_padname": "记事本名称",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "搜索关键词",
|
||||||
|
"ep_adminpads2_search-button.value": "搜索",
|
||||||
|
"ep_adminpads2_search-done": "搜索完成",
|
||||||
|
"ep_adminpads2_search-error-explanation": "搜索记事本时服务器发生错误:",
|
||||||
|
"ep_adminpads2_search-error-title": "获取记事本列表失败",
|
||||||
|
"ep_adminpads2_search-heading": "搜索记事本",
|
||||||
|
"ep_adminpads2_title": "记事本管理",
|
||||||
|
"ep_adminpads2_unknown-error": "未知错误",
|
||||||
|
"ep_adminpads2_unknown-status": "未知状态"
|
||||||
|
}
|
28
admin/public/ep_admin_pads/zh-hant.json
Normal file
28
admin/public/ep_admin_pads/zh-hant.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": [
|
||||||
|
"HellojoeAoPS",
|
||||||
|
"Kly"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ep_adminpads2_action": "操作",
|
||||||
|
"ep_adminpads2_autoupdate-label": "在記事本更改時自動更新",
|
||||||
|
"ep_adminpads2_autoupdate.title": "啟用或停用目前查詢的自動更新。",
|
||||||
|
"ep_adminpads2_confirm": "您確定要刪除記事本 {{padID}}?",
|
||||||
|
"ep_adminpads2_delete.value": "刪除",
|
||||||
|
"ep_adminpads2_last-edited": "上一次編輯",
|
||||||
|
"ep_adminpads2_loading": "載入中…",
|
||||||
|
"ep_adminpads2_manage-pads": "管理記事本",
|
||||||
|
"ep_adminpads2_no-results": "沒有結果",
|
||||||
|
"ep_adminpads2_pad-user-count": "記事本使用者數",
|
||||||
|
"ep_adminpads2_padname": "記事本名稱",
|
||||||
|
"ep_adminpads2_search-box.placeholder": "搜尋關鍵字",
|
||||||
|
"ep_adminpads2_search-button.value": "搜尋",
|
||||||
|
"ep_adminpads2_search-done": "搜尋完成",
|
||||||
|
"ep_adminpads2_search-error-explanation": "當搜尋記事本時伺服器發生錯誤:",
|
||||||
|
"ep_adminpads2_search-error-title": "取得記事本清單失敗",
|
||||||
|
"ep_adminpads2_search-heading": "搜尋記事本",
|
||||||
|
"ep_adminpads2_title": "記事本管理",
|
||||||
|
"ep_adminpads2_unknown-error": "不明錯誤",
|
||||||
|
"ep_adminpads2_unknown-status": "不明狀態"
|
||||||
|
}
|
BIN
admin/public/fond.jpg
Normal file
BIN
admin/public/fond.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
0
admin/src/App.css
Normal file
0
admin/src/App.css
Normal file
110
admin/src/App.tsx
Normal file
110
admin/src/App.tsx
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import {useEffect} from 'react'
|
||||||
|
import './App.css'
|
||||||
|
import {connect} from 'socket.io-client'
|
||||||
|
import {isJSONClean} from './utils/utils.ts'
|
||||||
|
import {NavLink, Outlet, useNavigate} from "react-router-dom";
|
||||||
|
import {useStore} from "./store/store.ts";
|
||||||
|
import {LoadingScreen} from "./utils/LoadingScreen.tsx";
|
||||||
|
import {Trans, useTranslation} from "react-i18next";
|
||||||
|
import {Cable, Construction, Crown, NotepadText, Wrench} from "lucide-react";
|
||||||
|
|
||||||
|
const WS_URL = import.meta.env.DEV? 'http://localhost:9001' : ''
|
||||||
|
export const App = ()=> {
|
||||||
|
const setSettings = useStore(state => state.setSettings);
|
||||||
|
const {t} = useTranslation()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/admin-auth/', {
|
||||||
|
method: 'POST'
|
||||||
|
}).then((value)=>{
|
||||||
|
if(!value.ok){
|
||||||
|
navigate('/login')
|
||||||
|
}
|
||||||
|
}).catch(()=>{
|
||||||
|
navigate('/login')
|
||||||
|
})
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = t('admin.page-title')
|
||||||
|
|
||||||
|
useStore.getState().setShowLoading(true);
|
||||||
|
const settingSocket = connect(`${WS_URL}/settings`, {
|
||||||
|
transports: ['websocket'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const pluginsSocket = connect(`${WS_URL}/pluginfw/installer`, {
|
||||||
|
transports: ['websocket'],
|
||||||
|
})
|
||||||
|
|
||||||
|
pluginsSocket.on('connect', () => {
|
||||||
|
useStore.getState().setPluginsSocket(pluginsSocket);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
settingSocket.on('connect', () => {
|
||||||
|
useStore.getState().setSettingsSocket(settingSocket);
|
||||||
|
useStore.getState().setShowLoading(false)
|
||||||
|
settingSocket.emit('load');
|
||||||
|
console.log('connected');
|
||||||
|
});
|
||||||
|
|
||||||
|
settingSocket.on('disconnect', (reason) => {
|
||||||
|
// The settingSocket.io client will automatically try to reconnect for all reasons other than "io
|
||||||
|
// server disconnect".
|
||||||
|
useStore.getState().setShowLoading(true)
|
||||||
|
if (reason === 'io server disconnect') {
|
||||||
|
settingSocket.connect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
settingSocket.on('settings', (settings) => {
|
||||||
|
/* Check whether the settings.json is authorized to be viewed */
|
||||||
|
if (settings.results === 'NOT_ALLOWED') {
|
||||||
|
console.log('Not allowed to view settings.json')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check to make sure the JSON is clean before proceeding */
|
||||||
|
if (isJSONClean(settings.results)) {
|
||||||
|
setSettings(settings.results);
|
||||||
|
} else {
|
||||||
|
alert('Invalid JSON');
|
||||||
|
}
|
||||||
|
useStore.getState().setShowLoading(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
settingSocket.on('saveprogress', (status)=>{
|
||||||
|
console.log(status)
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
settingSocket.disconnect();
|
||||||
|
pluginsSocket.disconnect()
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <div id="wrapper">
|
||||||
|
<LoadingScreen/>
|
||||||
|
<div className="menu">
|
||||||
|
<div className="inner-menu">
|
||||||
|
<span>
|
||||||
|
<Crown width={40} height={40}/>
|
||||||
|
<h1>Etherpad</h1>
|
||||||
|
</span>
|
||||||
|
<ul>
|
||||||
|
<li><NavLink to="/plugins"><Cable/><Trans i18nKey="admin_plugins"/></NavLink></li>
|
||||||
|
<li><NavLink to={"/settings"}><Wrench/><Trans i18nKey="admin_settings"/></NavLink></li>
|
||||||
|
<li> <NavLink to={"/help"}> <Construction/> <Trans i18nKey="admin_plugins_info"/></NavLink></li>
|
||||||
|
<li><NavLink to={"/pads"}><NotepadText/><Trans i18nKey="ep_admin_pads:ep_adminpads2_manage-pads"/></NavLink></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="innerwrapper">
|
||||||
|
<Outlet/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
16
admin/src/components/IconButton.tsx
Normal file
16
admin/src/components/IconButton.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import {FC, ReactElement} from "react";
|
||||||
|
|
||||||
|
export type IconButtonProps = {
|
||||||
|
icon: JSX.Element,
|
||||||
|
title: string|ReactElement,
|
||||||
|
onClick: ()=>void,
|
||||||
|
className?: string,
|
||||||
|
disabled?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IconButton:FC<IconButtonProps> = ({icon,className,onClick,title, disabled})=>{
|
||||||
|
return <button onClick={onClick} className={"icon-button "+ className} disabled={disabled}>
|
||||||
|
{icon}
|
||||||
|
<span>{title}</span>
|
||||||
|
</button>
|
||||||
|
}
|
14
admin/src/components/SearchField.tsx
Normal file
14
admin/src/components/SearchField.tsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import {ChangeEventHandler, FC} from "react";
|
||||||
|
import {Search} from 'lucide-react'
|
||||||
|
export type SearchFieldProps = {
|
||||||
|
value: string,
|
||||||
|
onChange: ChangeEventHandler<HTMLInputElement>,
|
||||||
|
placeholder?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SearchField:FC<SearchFieldProps> = ({onChange,value, placeholder})=>{
|
||||||
|
return <span className="search-field">
|
||||||
|
<input value={value} onChange={onChange} placeholder={placeholder}/>
|
||||||
|
<Search/>
|
||||||
|
</span>
|
||||||
|
}
|
727
admin/src/index.css
Normal file
727
admin/src/index.css
Normal file
|
@ -0,0 +1,727 @@
|
||||||
|
:root {
|
||||||
|
--etherpad-color: #0f775b;
|
||||||
|
--etherpad-comp: #9C8840;
|
||||||
|
--etherpad-light: #99FF99;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Karla;
|
||||||
|
src: url(/Karla-Regular.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body, #root {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 100%;
|
||||||
|
font-family: "Karla", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *:before, *:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
color: #333;
|
||||||
|
font: 14px helvetica, sans-serif;
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu {
|
||||||
|
height: 100vh;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bolder;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
max-width: 20%;
|
||||||
|
min-width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button{
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
background-color: var(--etherpad-color);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button svg {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button span {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.menu span:first-child {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu span:first-child svg {
|
||||||
|
margin-right: 10px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.menu h1 {
|
||||||
|
font-size: 50px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-menu {
|
||||||
|
border-radius: 0 20px 20px 0;
|
||||||
|
padding: 10px;
|
||||||
|
flex-grow: 100;
|
||||||
|
background-color: var(--etherpad-comp);
|
||||||
|
color: white;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu ul {
|
||||||
|
color: white;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu li a {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu svg {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu li {
|
||||||
|
padding: 10px;
|
||||||
|
color: white;
|
||||||
|
list-style: none;
|
||||||
|
margin-left: 3px;
|
||||||
|
line-height: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.menu li:has(.active) {
|
||||||
|
background-color: #9C885C ;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu li a {
|
||||||
|
color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
div.innerwrapper {
|
||||||
|
background-color: #F0F0F0;
|
||||||
|
overflow: auto;
|
||||||
|
height: 100vh;
|
||||||
|
flex-grow: 100;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.innerwrapper-err {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapper {
|
||||||
|
display: flex;
|
||||||
|
background: none repeat scroll 0px 0px #FFFFFF;
|
||||||
|
box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
min-height: 100%;/*always display a scrollbar*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
margin: 10px 0;
|
||||||
|
height: 1px;
|
||||||
|
background: #aaa;
|
||||||
|
background: -webkit-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||||
|
background: -moz-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||||
|
background: -ms-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||||
|
background: -o-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner {
|
||||||
|
width: 300px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sort {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.sort:after {
|
||||||
|
content: '▲▼'
|
||||||
|
}
|
||||||
|
.sort.up:after {
|
||||||
|
content:'▲'
|
||||||
|
}
|
||||||
|
.sort.down:after {
|
||||||
|
content:'▼'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#installed-plugins thead tr th:nth-child(3) {
|
||||||
|
width: 15%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 3px;
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#available-plugins th:first-child, #available-plugins th:nth-child(2){
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#installed-plugins td>div {
|
||||||
|
position: relative;/* Allows us to position the loading indicator relative to this row */
|
||||||
|
display: inline-block; /*make this fill the whole cell*/
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages {
|
||||||
|
height: 5em;
|
||||||
|
}
|
||||||
|
.messages * {
|
||||||
|
display: none;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.messages .fetching {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; bottom:0; right:0;
|
||||||
|
padding: auto;
|
||||||
|
|
||||||
|
background: rgb(255,255,255);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-progress.progress {
|
||||||
|
padding-top: 20%;
|
||||||
|
background: rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress * {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings {
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 80vh;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#response {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link, a:visited, a:hover, a:focus {
|
||||||
|
color: #333333;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus, a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installed-results a:link,
|
||||||
|
.search-results a:link,
|
||||||
|
.installed-results a:visited,
|
||||||
|
.search-results a:visited,
|
||||||
|
.installed-results a:hover,
|
||||||
|
.search-results a:hover,
|
||||||
|
.installed-results a:focus,
|
||||||
|
.search-results a:focus {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.installed-results a:focus,
|
||||||
|
.search-results a:focus,
|
||||||
|
.installed-results a:hover,
|
||||||
|
.search-results a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
div.innerwrapper {
|
||||||
|
padding: 0 15px 15px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu {
|
||||||
|
padding: 1px 15px 0 15px;
|
||||||
|
position: static;
|
||||||
|
height: auto;
|
||||||
|
border-right: none;
|
||||||
|
width: auto;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table, thead, tbody, td, tr {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead tr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 50%;
|
||||||
|
white-space: normal;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.name {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:before {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
left: 6px;
|
||||||
|
text-align: left;
|
||||||
|
padding-right: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: bold;
|
||||||
|
content: attr(data-label);
|
||||||
|
}
|
||||||
|
|
||||||
|
td:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table input[type="button"] {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.settings-button-bar {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-background {
|
||||||
|
background-image: url("/fond.jpg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-inner-box div {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-inner-box [type=submit]{
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.login-textinput {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fffacc;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
width: 20%;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 40px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-inner-box{
|
||||||
|
position: relative;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--etherpad-color);
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-button {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: var(--etherpad-color);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.dialog-confirm-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.dialog-confirm-content {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
background-color: white;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
padding: 20px;
|
||||||
|
z-index: 101;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
padding: 20px;
|
||||||
|
z-index: 101;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
color: var(--etherpad-color);
|
||||||
|
font-size: 2em;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.ToastViewport {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
width: 390px;
|
||||||
|
max-width: 100vw;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
z-index: 2147483647;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ToastRootSuccess {
|
||||||
|
background-color: lawngreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ToastRootFailure {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ToastRootFailure > .ToastTitle {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ToastRoot {
|
||||||
|
border-radius: 20px;
|
||||||
|
box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
|
||||||
|
padding: 15px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-areas: 'title action' 'description action';
|
||||||
|
grid-template-columns: auto max-content;
|
||||||
|
column-gap: 15px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.ToastRoot[data-state='open'] {
|
||||||
|
animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
.ToastRoot[data-state='closed'] {
|
||||||
|
animation: hide 100ms ease-in;
|
||||||
|
}
|
||||||
|
.ToastRoot[data-swipe='move'] {
|
||||||
|
transform: translateX(var(--radix-toast-swipe-move-x));
|
||||||
|
}
|
||||||
|
.ToastRoot[data-swipe='cancel'] {
|
||||||
|
transform: translateX(0);
|
||||||
|
transition: transform 200ms ease-out;
|
||||||
|
}
|
||||||
|
.ToastRoot[data-swipe='end'] {
|
||||||
|
animation: swipeOut 100ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes hide {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideIn {
|
||||||
|
from {
|
||||||
|
transform: translateX(calc(100% + var(--viewport-padding)));
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes swipeOut {
|
||||||
|
from {
|
||||||
|
transform: translateX(var(--radix-toast-swipe-end-x));
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(calc(100% + var(--viewport-padding)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ToastTitle {
|
||||||
|
grid-area: title;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--slate-12);
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ToastDescription {
|
||||||
|
grid-area: description;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--slate-11);
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ToastAction {
|
||||||
|
grid-area: action;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-block {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-field {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-field input {
|
||||||
|
border-color: transparent;
|
||||||
|
border-radius: 20px;
|
||||||
|
height: 2.5rem;
|
||||||
|
width: 100vh;
|
||||||
|
padding: 5px 5px 5px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-field input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-field svg {
|
||||||
|
position: absolute;
|
||||||
|
left: 3px;
|
||||||
|
bottom: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.search-field svg {
|
||||||
|
color: gray
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin: 25px 0;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-family: sans-serif;
|
||||||
|
min-width: 400px;
|
||||||
|
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
th:first-child {
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th:last-child {
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table thead tr {
|
||||||
|
font-size: 25px;
|
||||||
|
background-color: var(--etherpad-color);
|
||||||
|
color: #ffffff;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tbody tr {
|
||||||
|
border-bottom: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr:nth-child(even) td {
|
||||||
|
background-color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr td {
|
||||||
|
padding: 12px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tbody tr:nth-of-type(even) {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tbody tr:last-of-type {
|
||||||
|
border-bottom: 2px solid #009879;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tbody tr.active-row {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #009879;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.pad-pagination{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pad-pagination button {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: none;
|
||||||
|
color: black;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.pad-pagination button:disabled {
|
||||||
|
background: transparent;
|
||||||
|
color: lightgrey;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pad-pagination span {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pad-pagination >span {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.login-page .login-form .input-control input[type=text], .login-page .login-form .input-control input[type=email], .login-page .login-form .input-control input[type=password], .login-page .signup-form .input-control input[type=text], .login-page .signup-form .input-control input[type=email], .login-page .signup-form .input-control input[type=password], .login-page .forgot-form .input-control input[type=text], .login-page .forgot-form .input-control input[type=email], .login-page .forgot-form .input-control input[type=password] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
display: inline-block;
|
||||||
|
border-bottom: 2px solid #ccc;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
-webkit-transition: all 0.3s ease-in-out;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, button, select, optgroup, textarea {
|
||||||
|
margin: 0;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-input {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-input svg {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
right: 10px;
|
||||||
|
color: #666;
|
||||||
|
}
|
57
admin/src/localization/i18n.ts
Normal file
57
admin/src/localization/i18n.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import i18n from 'i18next'
|
||||||
|
import {initReactI18next} from "react-i18next";
|
||||||
|
import LanguageDetector from 'i18next-browser-languagedetector'
|
||||||
|
|
||||||
|
|
||||||
|
import { BackendModule } from 'i18next';
|
||||||
|
|
||||||
|
const LazyImportPlugin: BackendModule = {
|
||||||
|
type: 'backend',
|
||||||
|
init: function () {
|
||||||
|
},
|
||||||
|
read: async function (language, namespace, callback) {
|
||||||
|
|
||||||
|
let baseURL = import.meta.env.BASE_URL
|
||||||
|
if(namespace === "translation") {
|
||||||
|
// If default we load the translation file
|
||||||
|
baseURL+=`/locales/${language}.json`
|
||||||
|
} else {
|
||||||
|
// Else we load the former plugin translation file
|
||||||
|
baseURL+=`/${namespace}/${language}.json`
|
||||||
|
}
|
||||||
|
|
||||||
|
const localeJSON = await fetch(baseURL, {
|
||||||
|
cache: "force-cache"
|
||||||
|
})
|
||||||
|
let json;
|
||||||
|
|
||||||
|
try {
|
||||||
|
json = JSON.parse(await localeJSON.text())
|
||||||
|
} catch(e) {
|
||||||
|
callback(new Error("Error loading"), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
callback(null, json);
|
||||||
|
},
|
||||||
|
|
||||||
|
save: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
create: function () {
|
||||||
|
/* save the missing translation */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
i18n
|
||||||
|
.use(LanguageDetector)
|
||||||
|
.use(LazyImportPlugin)
|
||||||
|
.use(initReactI18next)
|
||||||
|
.init(
|
||||||
|
{
|
||||||
|
ns: ['translation','ep_admin_pads'],
|
||||||
|
fallbackLng: 'en'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default i18n
|
40
admin/src/main.tsx
Normal file
40
admin/src/main.tsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom/client'
|
||||||
|
import App from './App.tsx'
|
||||||
|
import './index.css'
|
||||||
|
import {createBrowserRouter, createRoutesFromElements, Route, RouterProvider} from "react-router-dom";
|
||||||
|
import {HomePage} from "./pages/HomePage.tsx";
|
||||||
|
import {SettingsPage} from "./pages/SettingsPage.tsx";
|
||||||
|
import {LoginScreen} from "./pages/LoginScreen.tsx";
|
||||||
|
import {HelpPage} from "./pages/HelpPage.tsx";
|
||||||
|
import * as Toast from '@radix-ui/react-toast'
|
||||||
|
import {I18nextProvider} from "react-i18next";
|
||||||
|
import i18n from "./localization/i18n.ts";
|
||||||
|
import {PadPage} from "./pages/PadPage.tsx";
|
||||||
|
import {ToastDialog} from "./utils/Toast.tsx";
|
||||||
|
|
||||||
|
const router = createBrowserRouter(createRoutesFromElements(
|
||||||
|
<><Route element={<App/>}>
|
||||||
|
<Route index element={<HomePage/>}/>
|
||||||
|
<Route path="/plugins" element={<HomePage/>}/>
|
||||||
|
<Route path="/settings" element={<SettingsPage/>}/>
|
||||||
|
<Route path="/help" element={<HelpPage/>}/>
|
||||||
|
<Route path="/pads" element={<PadPage/>}/>
|
||||||
|
</Route><Route path="/login">
|
||||||
|
<Route index element={<LoginScreen/>}/>
|
||||||
|
</Route></>
|
||||||
|
), {
|
||||||
|
basename: import.meta.env.BASE_URL
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<I18nextProvider i18n={i18n}>
|
||||||
|
<Toast.Provider>
|
||||||
|
<ToastDialog/>
|
||||||
|
<RouterProvider router={router}/>
|
||||||
|
</Toast.Provider>
|
||||||
|
</I18nextProvider>
|
||||||
|
</React.StrictMode>,
|
||||||
|
)
|
70
admin/src/pages/HelpPage.tsx
Normal file
70
admin/src/pages/HelpPage.tsx
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import {Trans} from "react-i18next";
|
||||||
|
import {useStore} from "../store/store.ts";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import {HelpObj} from "./Plugin.ts";
|
||||||
|
|
||||||
|
export const HelpPage = () => {
|
||||||
|
const settingsSocket = useStore(state=>state.settingsSocket)
|
||||||
|
const [helpData, setHelpData] = useState<HelpObj>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(!settingsSocket) return;
|
||||||
|
settingsSocket?.on('reply:help', (data) => {
|
||||||
|
setHelpData(data)
|
||||||
|
});
|
||||||
|
|
||||||
|
settingsSocket?.emit('help');
|
||||||
|
}, [settingsSocket]);
|
||||||
|
|
||||||
|
const renderHooks = (hooks:Record<string, Record<string, string>>) => {
|
||||||
|
return Object.keys(hooks).map((hookName, i) => {
|
||||||
|
return <div key={hookName+i}>
|
||||||
|
<h3>{hookName}</h3>
|
||||||
|
<ul>
|
||||||
|
{Object.keys(hooks[hookName]).map((hook, i) => <li>{hook}
|
||||||
|
<ul key={hookName+hook+i}>
|
||||||
|
{Object.keys(hooks[hookName][hook]).map((subHook, i) => <li key={i}>{subHook}</li>)}
|
||||||
|
</ul>
|
||||||
|
</li>)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!helpData) return <div></div>
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<h1><Trans i18nKey="admin_plugins_info.version"/></h1>
|
||||||
|
<div className="help-block">
|
||||||
|
<div><Trans i18nKey="admin_plugins_info.version_number"/></div>
|
||||||
|
<div>{helpData?.epVersion}</div>
|
||||||
|
<div><Trans i18nKey="admin_plugins_info.version_latest"/></div>
|
||||||
|
<div>{helpData.latestVersion}</div>
|
||||||
|
<div>Git sha</div>
|
||||||
|
<div>{helpData.gitCommit}</div>
|
||||||
|
</div>
|
||||||
|
<h2><Trans i18nKey="admin_plugins.installed"/></h2>
|
||||||
|
<ul>
|
||||||
|
{helpData.installedPlugins.map((plugin, i) => <li key={i}>{plugin}</li>)}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><Trans i18nKey="admin_plugins_info.parts"/></h2>
|
||||||
|
<ul>
|
||||||
|
{helpData.installedParts.map((part, i) => <li key={i}>{part}</li>)}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><Trans i18nKey="admin_plugins_info.hooks"/></h2>
|
||||||
|
{
|
||||||
|
renderHooks(helpData.installedServerHooks)
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
<Trans i18nKey="admin_plugins_info.hooks_client"/>
|
||||||
|
{
|
||||||
|
renderHooks(helpData.installedClientHooks)
|
||||||
|
}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
188
admin/src/pages/HomePage.tsx
Normal file
188
admin/src/pages/HomePage.tsx
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
import {useStore} from "../store/store.ts";
|
||||||
|
import {useEffect, useMemo, useState} from "react";
|
||||||
|
import {InstalledPlugin, PluginDef, SearchParams} from "./Plugin.ts";
|
||||||
|
import {useDebounce} from "../utils/useDebounce.ts";
|
||||||
|
import {Trans, useTranslation} from "react-i18next";
|
||||||
|
import {SearchField} from "../components/SearchField.tsx";
|
||||||
|
import {Download, Trash} from "lucide-react";
|
||||||
|
import {IconButton} from "../components/IconButton.tsx";
|
||||||
|
|
||||||
|
|
||||||
|
export const HomePage = () => {
|
||||||
|
const pluginsSocket = useStore(state=>state.pluginsSocket)
|
||||||
|
const [plugins,setPlugins] = useState<PluginDef[]>([])
|
||||||
|
const [installedPlugins, setInstalledPlugins] = useState<InstalledPlugin[]>([])
|
||||||
|
const sortedInstalledPlugins = useMemo(()=>{
|
||||||
|
return installedPlugins.sort((a, b)=>{
|
||||||
|
if(a.name < b.name){
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if(a.name > b.name){
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
|
||||||
|
} ,[installedPlugins])
|
||||||
|
const [searchParams, setSearchParams] = useState<SearchParams>({
|
||||||
|
offset: 0,
|
||||||
|
limit: 99999,
|
||||||
|
sortBy: 'name',
|
||||||
|
sortDir: 'asc',
|
||||||
|
searchTerm: ''
|
||||||
|
})
|
||||||
|
const [searchTerm, setSearchTerm] = useState<string>('')
|
||||||
|
const {t} = useTranslation()
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(!pluginsSocket){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginsSocket.on('results:installed', (data:{
|
||||||
|
installed: InstalledPlugin[]
|
||||||
|
})=>{
|
||||||
|
setInstalledPlugins(data.installed)
|
||||||
|
})
|
||||||
|
|
||||||
|
pluginsSocket.on('results:updatable', (data) => {
|
||||||
|
data.updatable.forEach((pluginName: string) => {
|
||||||
|
setInstalledPlugins(installedPlugins.map(plugin => {
|
||||||
|
if (plugin.name === pluginName) {
|
||||||
|
return {
|
||||||
|
...plugin,
|
||||||
|
updatable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plugin
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
pluginsSocket.on('finished:install', () => {
|
||||||
|
pluginsSocket!.emit('getInstalled');
|
||||||
|
})
|
||||||
|
|
||||||
|
pluginsSocket.on('finished:uninstall', () => {
|
||||||
|
console.log("Finished uninstall")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Reload on reconnect
|
||||||
|
pluginsSocket.on('connect', ()=>{
|
||||||
|
// Initial retrieval of installed plugins
|
||||||
|
pluginsSocket.emit('getInstalled');
|
||||||
|
pluginsSocket.emit('search', searchParams)
|
||||||
|
})
|
||||||
|
|
||||||
|
pluginsSocket.emit('getInstalled');
|
||||||
|
|
||||||
|
// check for updates every 5mins
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
pluginsSocket.emit('checkUpdates');
|
||||||
|
}, 1000 * 60 * 5);
|
||||||
|
|
||||||
|
return ()=>{
|
||||||
|
clearInterval(interval)
|
||||||
|
}
|
||||||
|
}, [pluginsSocket]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!pluginsSocket) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginsSocket?.emit('search', searchParams)
|
||||||
|
|
||||||
|
|
||||||
|
pluginsSocket!.on('results:search', (data: {
|
||||||
|
results: PluginDef[]
|
||||||
|
}) => {
|
||||||
|
setPlugins(data.results)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
}, [searchParams, pluginsSocket]);
|
||||||
|
|
||||||
|
const uninstallPlugin = (pluginName: string)=>{
|
||||||
|
pluginsSocket!.emit('uninstall', pluginName);
|
||||||
|
// Remove plugin
|
||||||
|
setInstalledPlugins(installedPlugins.filter(i=>i.name !== pluginName))
|
||||||
|
}
|
||||||
|
|
||||||
|
const installPlugin = (pluginName: string)=>{
|
||||||
|
pluginsSocket!.emit('install', pluginName);
|
||||||
|
setPlugins(plugins.filter(plugin=>plugin.name !== pluginName))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
useDebounce(()=>{
|
||||||
|
setSearchParams({
|
||||||
|
...searchParams,
|
||||||
|
offset: 0,
|
||||||
|
searchTerm: searchTerm
|
||||||
|
})
|
||||||
|
}, 500, [searchTerm])
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<h1><Trans i18nKey="admin_plugins"/></h1>
|
||||||
|
|
||||||
|
<h2><Trans i18nKey="admin_plugins.installed"/></h2>
|
||||||
|
|
||||||
|
<table id="installed-plugins">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><Trans i18nKey="admin_plugins.name"/></th>
|
||||||
|
<th><Trans i18nKey="admin_plugins.version"/></th>
|
||||||
|
<th><Trans i18nKey="ep_admin_pads:ep_adminpads2_action"/></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody style={{overflow: 'auto'}}>
|
||||||
|
{sortedInstalledPlugins.map((plugin, index) => {
|
||||||
|
return <tr key={index}>
|
||||||
|
<td>{plugin.name}</td>
|
||||||
|
<td>{plugin.version}</td>
|
||||||
|
<td>
|
||||||
|
{
|
||||||
|
plugin.updatable ?
|
||||||
|
<button onClick={() => installPlugin(plugin.name)}>Update</button>
|
||||||
|
: <IconButton disabled={plugin.name == "ep_etherpad-lite"} icon={<Trash/>} title={<Trans i18nKey="admin_plugins.installed_uninstall.value"/>} onClick={() => uninstallPlugin(plugin.name)}/>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><Trans i18nKey="admin_plugins.available"/></h2>
|
||||||
|
<SearchField onChange={v=>{setSearchTerm(v.target.value)}} placeholder={t('admin_plugins.available_search.placeholder')} value={searchTerm}/>
|
||||||
|
|
||||||
|
<table id="available-plugins">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><Trans i18nKey="admin_plugins.name"/></th>
|
||||||
|
<th style={{width: '30%'}}><Trans i18nKey="admin_plugins.description"/></th>
|
||||||
|
<th><Trans i18nKey="admin_plugins.version"/></th>
|
||||||
|
<th><Trans i18nKey="admin_plugins.last-update"/></th>
|
||||||
|
<th><Trans i18nKey="ep_admin_pads:ep_adminpads2_action"/></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody style={{overflow: 'auto'}}>
|
||||||
|
{plugins.map((plugin) => {
|
||||||
|
return <tr key={plugin.name}>
|
||||||
|
<td><a rel="noopener noreferrer" href={`https://npmjs.com/${plugin.name}`} target="_blank">{plugin.name}</a></td>
|
||||||
|
<td>{plugin.description}</td>
|
||||||
|
<td>{plugin.version}</td>
|
||||||
|
<td>{plugin.time}</td>
|
||||||
|
<td>
|
||||||
|
<IconButton icon={<Download/>} onClick={() => installPlugin(plugin.name)} title={<Trans i18nKey="admin_plugins.available_install.value"/>}/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue