Skip to content

Commit fa5aed4

Browse files
committed
Fixed docker build.
1 parent 4d97c3c commit fa5aed4

36 files changed

+243
-967
lines changed

.dockerignore

+1
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ Dockerfile
2424

2525
settings.json
2626
src/node_modules
27+
admin/node_modules

.github/workflows/backend-tests.yml

+24
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ jobs:
5454
-
5555
name: Install all dependencies and symlink for ep_etherpad-lite
5656
run: bin/installDeps.sh
57+
- name: Install admin ui
58+
working-directory: admin
59+
run: pnpm install
60+
- name: Build admin ui
61+
working-directory: admin
62+
run: pnpm build
5763
-
5864
name: Run the backend tests
5965
run: pnpm test
@@ -105,6 +111,12 @@ jobs:
105111
-
106112
name: Install all dependencies and symlink for ep_etherpad-lite
107113
run: bin/installDeps.sh
114+
- name: Install admin ui
115+
working-directory: admin
116+
run: pnpm install
117+
- name: Build admin ui
118+
working-directory: admin
119+
run: pnpm build
108120
-
109121
name: Install Etherpad plugins
110122
run: >
@@ -163,6 +175,12 @@ jobs:
163175
-
164176
name: Install all dependencies and symlink for ep_etherpad-lite
165177
run: bin/installOnWindows.bat
178+
- name: Install admin ui
179+
working-directory: admin
180+
run: pnpm install
181+
- name: Build admin ui
182+
working-directory: admin
183+
run: pnpm build
166184
-
167185
name: Fix up the settings.json
168186
run: |
@@ -207,6 +225,12 @@ jobs:
207225
${{ runner.os }}-pnpm-store-
208226
- name: Only install direct dependencies
209227
run: pnpm config set auto-install-peers false
228+
- name: Install admin ui
229+
working-directory: admin
230+
run: pnpm install
231+
- name: Build admin ui
232+
working-directory: admin
233+
run: pnpm build
210234
-
211235
name: Install Etherpad plugins
212236
# The --legacy-peer-deps flag is required to work around a bug in npm

.github/workflows/frontend-admin-tests.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ jobs:
1212
name: with plugins
1313
runs-on: ubuntu-latest
1414

15-
# node: [16, 19, 20] >> Disabled node 16 and 18 because they do not work
1615
strategy:
1716
fail-fast: false
1817
matrix:
@@ -83,11 +82,11 @@ jobs:
8382
run: "sed -i 's/\"enableAdminUITests\": false/\"enableAdminUITests\": true,\\n\"users\":{\"admin\":{\"password\":\"changeme\",\"is_admin\":true}}/' settings.json"
8483
-
8584
name: increase maxHttpBufferSize
86-
run: "sed -i 's/\"maxHttpBufferSize\": 10000/\"maxHttpBufferSize\": 100000/' settings.json"
85+
run: "sed -i 's/\"maxHttpBufferSize\": 10000/\"maxHttpBufferSize\": 10000000/' settings.json"
8786
-
8887
name: Disable import/export rate limiting
8988
run: |
90-
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 1000000/' -i settings.json
89+
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 100000000/' -i settings.json
9190
-
9291
name: Remove standard frontend test files, so only admin tests are run
9392
run: mv src/tests/frontend/specs/* /tmp && mv /tmp/admin*.js src/tests/frontend/specs

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ out/
2323
/src/bin/etherpad-1.deb
2424
/src/bin/node.exe
2525
plugin_packages
26-
pnpm-lock.yaml
26+
pnpm-lock.yaml
27+
/src/templates/admin

Dockerfile

+10-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
#
55
# Author: muxator
66

7+
FROM node:alpine as adminBuild
8+
9+
WORKDIR /opt/etherpad-lite
10+
COPY ./admin ./admin
11+
RUN cd ./admin && npm install -g pnpm && pnpm install && pnpm run build --outDir ./dist
12+
13+
714
FROM node:alpine as build
815
LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite"
916

@@ -99,16 +106,18 @@ COPY --chown=etherpad:etherpad ./pnpm-workspace.yaml ./package.json ./
99106
FROM build as development
100107

101108
COPY --chown=etherpad:etherpad ./src/package.json .npmrc ./src/pnpm-lock.yaml ./src/
109+
COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/admin/dist ./src/templates/admin
102110

103111
RUN bin/installDeps.sh && { [ -z "${ETHERPAD_PLUGINS}" ] || \
104112
pnpm install --workspace-root ${ETHERPAD_PLUGINS}; }
105-
113+
106114
FROM build as production
107115

108116
ENV NODE_ENV=production
109117
ENV ETHERPAD_PRODUCTION=true
110118

111119
COPY --chown=etherpad:etherpad ./src ./src
120+
COPY --chown=etherpad:etherpad --from=adminBuild /opt/etherpad-lite/admin/dist ./src/templates/admin
112121

113122
RUN bin/installDeps.sh && { [ -z "${ETHERPAD_PLUGINS}" ] || \
114123
pnpm install --workspace-root ${ETHERPAD_PLUGINS}; } && \

admin/index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
5-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
65
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Vite + React + TS</title>
6+
<title>Etherpad Admin Dashboard</title>
7+
<link rel="icon" href="/favicon.ico">
88
</head>
99
<body>
1010
<div id="root"></div>

admin/pnpm-workspace.yaml

Whitespace-only changes.

admin/src/App.tsx

+17-6
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,38 @@ import {useEffect} from 'react'
22
import './App.css'
33
import {connect} from 'socket.io-client'
44
import {isJSONClean} from './utils/utils.ts'
5-
import {NavLink, Outlet} from "react-router-dom";
5+
import {NavLink, Outlet, useNavigate} from "react-router-dom";
66
import {useStore} from "./store/store.ts";
77
import {LoadingScreen} from "./utils/LoadingScreen.tsx";
8-
import {ToastDialog} from "./utils/Toast.tsx";
98
import {Trans, useTranslation} from "react-i18next";
109

11-
10+
const WS_URL = import.meta.env.DEV? 'http://localhost:9001' : ''
1211
export const App = ()=> {
1312
const setSettings = useStore(state => state.setSettings);
1413
const {t} = useTranslation()
14+
const navigate = useNavigate()
15+
16+
useEffect(() => {
17+
fetch('/admin-auth/', {
18+
method: 'POST'
19+
}).then((value)=>{
20+
if(!value.ok){
21+
navigate('/login')
22+
}
23+
}).catch(()=>{
24+
navigate('/login')
25+
})
26+
}, []);
1527

1628
useEffect(() => {
1729
document.title = t('admin.page-title')
1830

1931
useStore.getState().setShowLoading(true);
20-
const settingSocket = connect('http://localhost:9001/settings', {
32+
const settingSocket = connect(`${WS_URL}/settings`, {
2133
transports: ['websocket'],
2234
});
2335

24-
const pluginsSocket = connect('http://localhost:9001/pluginfw/installer', {
36+
const pluginsSocket = connect(`${WS_URL}/pluginfw/installer`, {
2537
transports: ['websocket'],
2638
})
2739

@@ -74,7 +86,6 @@ export const App = ()=> {
7486

7587
return <div id="wrapper">
7688
<LoadingScreen/>
77-
<ToastDialog/>
7889
<div className="menu">
7990
<h1>Etherpad</h1>
8091
<ul>

admin/src/index.css

+24
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,25 @@ pre {
339339
}
340340

341341

342+
.dialog-confirm-overlay {
343+
position: fixed;
344+
inset: 0;
345+
background-color: rgba(0, 0, 0, 0.5);
346+
z-index: 100;
347+
}
348+
349+
350+
.dialog-confirm-content {
351+
position: fixed;
352+
top: 50%;
353+
left: 50%;
354+
background-color: white;
355+
transform: translate(-50%, -50%);
356+
padding: 20px;
357+
z-index: 101;
358+
}
359+
360+
342361
.dialog-content {
343362
position: fixed;
344363
top: 50%;
@@ -463,3 +482,8 @@ pre {
463482
grid-template-columns: repeat(2, minmax(0, 1fr));
464483
gap: 20px
465484
}
485+
486+
.search-field {
487+
width: 50%;
488+
padding: 5px;
489+
}

admin/src/localization/i18n.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ const LazyImportPlugin: BackendModule = {
2828
try {
2929
json = JSON.parse(await localeJSON.text())
3030
} catch(e) {
31-
callback(true, null);
31+
callback(new Error("Error loading"), null);
3232
}
3333

3434

3535
callback(null, json);
3636
},
3737

38-
save: function (language, namespace, data) {
38+
save: function () {
3939
},
4040

41-
create: function (languages, namespace, key, fallbackValue) {
41+
create: function () {
4242
/* save the missing translation */
4343
},
4444
};

admin/src/main.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import * as Toast from '@radix-ui/react-toast'
1111
import {I18nextProvider} from "react-i18next";
1212
import i18n from "./localization/i18n.ts";
1313
import {PadPage} from "./pages/PadPage.tsx";
14+
import {ToastDialog} from "./utils/Toast.tsx";
1415

1516
const router = createBrowserRouter(createRoutesFromElements(
1617
<><Route element={<App/>}>
@@ -31,7 +32,8 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
3132
<React.StrictMode>
3233
<I18nextProvider i18n={i18n}>
3334
<Toast.Provider>
34-
<RouterProvider router={router}/>
35+
<ToastDialog/>
36+
<RouterProvider router={router}/>
3537
</Toast.Provider>
3638
</I18nextProvider>
3739
</React.StrictMode>,

admin/src/pages/HelpPage.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export const HelpPage = () => {
1010
useEffect(() => {
1111
if(!settingsSocket) return;
1212
settingsSocket?.on('reply:help', (data) => {
13-
console.log(data)
1413
setHelpData(data)
1514
});
1615

@@ -19,11 +18,11 @@ export const HelpPage = () => {
1918

2019
const renderHooks = (hooks:Record<string, Record<string, string>>) => {
2120
return Object.keys(hooks).map((hookName, i) => {
22-
return <div key={i}>
21+
return <div key={hookName+i}>
2322
<h3>{hookName}</h3>
2423
<ul>
2524
{Object.keys(hooks[hookName]).map((hook, i) => <li>{hook}
26-
<ul key={i}>
25+
<ul key={hookName+hook+i}>
2726
{Object.keys(hooks[hookName][hook]).map((subHook, i) => <li key={i}>{subHook}</li>)}
2827
</ul>
2928
</li>)}

admin/src/pages/HomePage.tsx

+29-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {useStore} from "../store/store.ts";
22
import {useEffect, useState} from "react";
33
import {InstalledPlugin, PluginDef, SearchParams} from "./Plugin.ts";
44
import {useDebounce} from "../utils/useDebounce.ts";
5-
import {Trans} from "react-i18next";
5+
import {Trans, useTranslation} from "react-i18next";
66

77

88
export const HomePage = () => {
@@ -17,6 +17,7 @@ export const HomePage = () => {
1717
searchTerm: ''
1818
})
1919
const [searchTerm, setSearchTerm] = useState<string>('')
20+
const {t} = useTranslation()
2021

2122

2223
useEffect(() => {
@@ -30,8 +31,18 @@ export const HomePage = () => {
3031
setInstalledPlugins(data.installed)
3132
})
3233

33-
pluginsSocket.on('results:updatable', () => {
34-
console.log("Finished install")
34+
pluginsSocket.on('results:updatable', (data) => {
35+
data.updatable.forEach((pluginName: string) => {
36+
setInstalledPlugins(installedPlugins.map(plugin => {
37+
if (plugin.name === pluginName) {
38+
return {
39+
...plugin,
40+
updatable: true
41+
}
42+
}
43+
return plugin
44+
}))
45+
})
3546
})
3647

3748
pluginsSocket.on('finished:install', () => {
@@ -118,19 +129,25 @@ export const HomePage = () => {
118129
return <tr key={index}>
119130
<td>{plugin.name}</td>
120131
<td>{plugin.version}</td>
121-
<td onClick={() => {
122-
}}>
123-
<button disabled={plugin.name == "ep_etherpad-lite"} onClick={() => uninstallPlugin(plugin.name)}><Trans i18nKey="admin_plugins.installed_uninstall.value"/></button>
132+
<td>
133+
{
134+
plugin.updatable ?
135+
<button onClick={() => installPlugin(plugin.name)}>Update</button>
136+
: <button disabled={plugin.name == "ep_etherpad-lite"}
137+
onClick={() => uninstallPlugin(plugin.name)}><Trans
138+
i18nKey="admin_plugins.installed_uninstall.value"/></button>
139+
140+
}
124141
</td>
125-
</tr>
126-
})}
127-
</tbody>
128-
</table>
142+
</tr>
143+
})}
144+
</tbody>
145+
</table>
129146

130147

131-
<h2><Trans i18nKey="admin_plugins.available"/></h2>
148+
<h2><Trans i18nKey="admin_plugins.available"/></h2>
132149

133-
<input type="text" value={searchTerm} onChange={v=>{
150+
<input className="search-field" placeholder={t('admin_plugins.available_search.placeholder')} type="text" value={searchTerm} onChange={v=>{
134151
setSearchTerm(v.target.value)
135152
}}/>
136153

admin/src/pages/LoginScreen.tsx

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
import {useState} from "react";
2+
import {useStore} from "../store/store.ts";
3+
import {useNavigate} from "react-router-dom";
24

35
export const LoginScreen = ()=>{
6+
const navigate = useNavigate()
47
const [username, setUsername] = useState('')
58
const [password, setPassword] = useState('')
69

710
const login = ()=>{
8-
fetch('/api/auth', {
9-
method: 'GET',
11+
fetch('/admin-auth/', {
12+
method: 'POST',
1013
headers:{
1114
Authorization: `Basic ${btoa(`${username}:${password}`)}`
1215
}
1316
}).then(r=>{
14-
console.log(r.status)
17+
if(!r.ok) {
18+
useStore.getState().setToastState({
19+
open: true,
20+
title: "Login failed",
21+
success: false
22+
})
23+
} else {
24+
navigate('/')
25+
}
1526
}).catch(e=>{
1627
console.error(e)
1728
})

0 commit comments

Comments
 (0)