mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 06:03:34 +01:00
Merge branch 'develop'
This commit is contained in:
commit
0c68ddce1e
26 changed files with 1561 additions and 1060 deletions
|
@ -1,3 +1,10 @@
|
|||
# 2.2.6
|
||||
|
||||
### Notable enhancements and fixes
|
||||
|
||||
- Added option to delete a pad by the creator. This option can be found in the settings menu. When you click on it you get a confirm dialog and after that you have the chance to completely erase the pad.
|
||||
|
||||
|
||||
# 2.2.5
|
||||
|
||||
### Notable enhancements and fixes
|
||||
|
|
25
README.md
25
README.md
|
@ -174,6 +174,31 @@ following plugins:
|
|||
that each user's chosen color, display name, comment ownership, etc. is
|
||||
strongly linked to their account.
|
||||
|
||||
### Upgrade Etherpad
|
||||
|
||||
Run the following command in your Etherpad folder to upgrade
|
||||
|
||||
1. Stop any running Etherpad (manual, systemd ...)
|
||||
2. Get present version
|
||||
```sh
|
||||
git -P tag --contains
|
||||
```
|
||||
3. List versions available
|
||||
```sh
|
||||
git -P tag --list "v*" --merged
|
||||
```
|
||||
4. Select the version
|
||||
```sh
|
||||
git checkout v2.2.5
|
||||
git switch -c v2.2.5
|
||||
```
|
||||
5. Upgrade Etherpad
|
||||
```sh
|
||||
./bin/run.sh
|
||||
```
|
||||
6. Stop with [CTRL-C]
|
||||
7. Restart your Etherpad service
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Tweak the settings
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "admin",
|
||||
"private": true,
|
||||
"version": "2.2.5",
|
||||
"version": "2.2.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
@ -11,32 +11,32 @@
|
|||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-switch": "^1.1.0"
|
||||
"@radix-ui/react-switch": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@radix-ui/react-dialog": "^1.1.1",
|
||||
"@radix-ui/react-toast": "^1.2.1",
|
||||
"@types/react": "^18.3.8",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
"@typescript-eslint/eslint-plugin": "^8.6.0",
|
||||
"@typescript-eslint/parser": "^8.6.0",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"eslint": "^9.10.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
"i18next": "^23.15.1",
|
||||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-toast": "^1.2.2",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.11.0",
|
||||
"@typescript-eslint/parser": "^8.11.0",
|
||||
"@vitejs/plugin-react-swc": "^3.7.1",
|
||||
"eslint": "^9.13.0",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.13",
|
||||
"i18next": "^23.16.2",
|
||||
"i18next-browser-languagedetector": "^8.0.0",
|
||||
"lucide-react": "^0.441.0",
|
||||
"lucide-react": "^0.453.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-i18next": "^15.0.2",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"typescript": "^5.6.2",
|
||||
"vite": "^5.4.7",
|
||||
"vite-plugin-static-copy": "^1.0.6",
|
||||
"react-hook-form": "^7.53.1",
|
||||
"react-i18next": "^15.1.0",
|
||||
"react-router-dom": "^6.27.0",
|
||||
"socket.io-client": "^4.8.0",
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^5.4.10",
|
||||
"vite-plugin-static-copy": "^2.0.0",
|
||||
"vite-plugin-svgr": "^4.2.0",
|
||||
"zustand": "^4.5.5"
|
||||
"zustand": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,9 @@ export const App = () => {
|
|||
<h1>Etherpad</h1>
|
||||
</span>
|
||||
<ul onClick={()=>{
|
||||
setSidebarOpen(false)
|
||||
if (window.innerWidth < 768) {
|
||||
setSidebarOpen(false)
|
||||
}
|
||||
}}>
|
||||
<li><NavLink to="/plugins"><Cable/><Trans i18nKey="admin_plugins"/></NavLink></li>
|
||||
<li><NavLink to={"/settings"}><Wrench/><Trans i18nKey="admin_settings"/></NavLink></li>
|
||||
|
|
|
@ -4,7 +4,7 @@ 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 {ArrowUpFromDot, Download, Trash} from "lucide-react";
|
||||
import {IconButton} from "../components/IconButton.tsx";
|
||||
import {determineSorting} from "../utils/sorting.ts";
|
||||
|
||||
|
@ -12,7 +12,8 @@ import {determineSorting} from "../utils/sorting.ts";
|
|||
export const HomePage = () => {
|
||||
const pluginsSocket = useStore(state=>state.pluginsSocket)
|
||||
const [plugins,setPlugins] = useState<PluginDef[]>([])
|
||||
const [installedPlugins, setInstalledPlugins] = useState<InstalledPlugin[]>([])
|
||||
const installedPlugins = useStore(state=>state.installedPlugins)
|
||||
const setInstalledPlugins = useStore(state=>state.setInstalledPlugins)
|
||||
const [searchParams, setSearchParams] = useState<SearchParams>({
|
||||
offset: 0,
|
||||
limit: 99999,
|
||||
|
@ -49,7 +50,7 @@ export const HomePage = () => {
|
|||
}, [plugins, searchParams])
|
||||
|
||||
const sortedInstalledPlugins = useMemo(()=>{
|
||||
return installedPlugins.sort((a, b)=>{
|
||||
return useStore.getState().installedPlugins.sort((a, b)=>{
|
||||
|
||||
if(a.name < b.name){
|
||||
return -1
|
||||
|
@ -78,17 +79,16 @@ export const HomePage = () => {
|
|||
})
|
||||
|
||||
pluginsSocket.on('results:updatable', (data) => {
|
||||
data.updatable.forEach((pluginName: string) => {
|
||||
setInstalledPlugins(installedPlugins.map(plugin => {
|
||||
if (plugin.name === pluginName) {
|
||||
return {
|
||||
...plugin,
|
||||
updatable: true
|
||||
}
|
||||
}
|
||||
return plugin
|
||||
}))
|
||||
})
|
||||
const newInstalledPlugins = useStore.getState().installedPlugins.map(plugin => {
|
||||
if (data.updatable.includes(plugin.name)) {
|
||||
return {
|
||||
...plugin,
|
||||
updatable: true
|
||||
}
|
||||
}
|
||||
return plugin
|
||||
})
|
||||
setInstalledPlugins(newInstalledPlugins)
|
||||
})
|
||||
|
||||
pluginsSocket.on('finished:install', () => {
|
||||
|
@ -159,6 +159,7 @@ export const HomePage = () => {
|
|||
})
|
||||
}, 500, [searchTerm])
|
||||
|
||||
|
||||
return <div>
|
||||
<h1><Trans i18nKey="admin_plugins"/></h1>
|
||||
|
||||
|
@ -180,7 +181,7 @@ export const HomePage = () => {
|
|||
<td>
|
||||
{
|
||||
plugin.updatable ?
|
||||
<button onClick={() => installPlugin(plugin.name)}>Update</button>
|
||||
<IconButton onClick={() => installPlugin(plugin.name)} icon={<ArrowUpFromDot/>} title="Update"></IconButton>
|
||||
: <IconButton disabled={plugin.name == "ep_etherpad-lite"} icon={<Trash/>} title={<Trans i18nKey="admin_plugins.installed_uninstall.value"/>} onClick={() => uninstallPlugin(plugin.name)}/>
|
||||
}
|
||||
</td>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {create} from "zustand";
|
||||
import {Socket} from "socket.io-client";
|
||||
import {PadSearchResult} from "../utils/PadSearch.ts";
|
||||
import {InstalledPlugin} from "../pages/Plugin.ts";
|
||||
|
||||
type ToastState = {
|
||||
description?:string,
|
||||
|
@ -22,7 +23,9 @@ type StoreState = {
|
|||
toastState: ToastState,
|
||||
setToastState: (val: ToastState)=>void,
|
||||
pads: PadSearchResult|undefined,
|
||||
setPads: (pads: PadSearchResult)=>void
|
||||
setPads: (pads: PadSearchResult)=>void,
|
||||
installedPlugins: InstalledPlugin[],
|
||||
setInstalledPlugins: (plugins: InstalledPlugin[])=>void
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,5 +46,7 @@ export const useStore = create<StoreState>()((set) => ({
|
|||
success: false
|
||||
},
|
||||
pads: undefined,
|
||||
setPads: (pads)=>set({pads})
|
||||
setPads: (pads)=>set({pads}),
|
||||
installedPlugins: [],
|
||||
setInstalledPlugins: (plugins)=>set({installedPlugins: plugins})
|
||||
}));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bin",
|
||||
"version": "2.2.5",
|
||||
"version": "2.2.6",
|
||||
"description": "",
|
||||
"main": "checkAllPads.js",
|
||||
"directories": {
|
||||
|
@ -12,12 +12,12 @@
|
|||
"log4js": "^6.9.1",
|
||||
"semver": "^7.6.3",
|
||||
"tsx": "^4.19.1",
|
||||
"ueberdb2": "^5.0.2"
|
||||
"ueberdb2": "^5.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/node": "^22.7.9",
|
||||
"@types/semver": "^7.5.8",
|
||||
"typescript": "^5.6.2"
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"scripts": {
|
||||
"makeDocs": "node --import tsx make_docs.ts",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.3.4"
|
||||
"vitepress": "^1.4.1"
|
||||
},
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev",
|
||||
|
|
|
@ -50,6 +50,6 @@
|
|||
"type": "git",
|
||||
"url": "https://github.com/ether/etherpad-lite.git"
|
||||
},
|
||||
"version": "2.2.5",
|
||||
"version": "2.2.6",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
|
|
2279
pnpm-lock.yaml
2279
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -16,10 +16,18 @@
|
|||
]
|
||||
},
|
||||
"admin.page-title": "لوحة تحكم المسؤول - Etherpad",
|
||||
"admin_plugins": "مدير المكونات الإضافية",
|
||||
"admin_plugins.available": "المكونات الإضافية المتاحة",
|
||||
"admin_plugins.available_not-found": "لم يتم العثور على أي مكونات إضافية.",
|
||||
"admin_plugins.available_fetching": "جاري الجلب…",
|
||||
"admin_plugins.available_install.value": "تنصيب",
|
||||
"admin_plugins.available_search.placeholder": "ابحث عن المكونات الإضافية للتثبيت",
|
||||
"admin_plugins.description": "الوصف",
|
||||
"admin_plugins.installed": "الإضافات المثبتة",
|
||||
"admin_plugins.installed_fetching": "جارٍ إحضار المكونات الإضافية المثبتة ...",
|
||||
"admin_plugins.installed_nothing": "لم تقم بتثبيت أي مكونات إضافية حتى الآن.",
|
||||
"admin_plugins.installed_uninstall.value": "إلغاء التثبيت",
|
||||
"admin_plugins.last-update": "آخر تحديث",
|
||||
"admin_plugins.name": "الاسم",
|
||||
"admin_plugins.page-title": "مدير البرنامج المساعد - Etherpad",
|
||||
"admin_plugins.version": "الإصدار",
|
||||
|
@ -31,8 +39,10 @@
|
|||
"admin_plugins_info.plugins": "الإضافات المثبتة",
|
||||
"admin_plugins_info.page-title": "معلومات البرنامج المساعد - Etherpad",
|
||||
"admin_plugins_info.version": "إصدار Etherpad",
|
||||
"admin_plugins_info.version_latest": "أحدث إصدار متاح",
|
||||
"admin_plugins_info.version_number": "رقم الإصدار",
|
||||
"admin_settings": "إعدادات",
|
||||
"admin_settings.current": "التكوين الحالي",
|
||||
"admin_settings.current_example-devel": "مثال على قالب إعدادات التطوير",
|
||||
"admin_settings.current_example-prod": "مثال على قالب إعدادات الإنتاج",
|
||||
"admin_settings.current_restart.value": "أعد تشغيل Etherpad",
|
||||
|
@ -110,6 +120,8 @@
|
|||
"pad.modals.deleted": "محذوف.",
|
||||
"pad.modals.deleted.explanation": "تمت إزالة هذا الباد.",
|
||||
"pad.modals.rateLimited": "معدل محدود.",
|
||||
"pad.modals.rateLimited.explanation": "لقد أرسلت الكثير من الرسائل إلى هذه اللوحة مما أدى إلى قطع الاتصال بك.",
|
||||
"pad.modals.rejected.explanation": "رفض الخادم الرسالة التي أرسلها متصفحك.",
|
||||
"pad.modals.rejected.cause": "ربما تم تحديث الخادم أثناء عرض اللوحة ، أو ربما كان هناك خطأ في Etherpad. حاول إعادة تحميل الصفحة.",
|
||||
"pad.modals.disconnected": "لم تعد متصلا.",
|
||||
"pad.modals.disconnected.explanation": "تم فقدان الاتصال بالخادم",
|
||||
|
|
|
@ -82,7 +82,9 @@
|
|||
"pad.settings.colorcheck": "Autorenfarben anzeigen",
|
||||
"pad.settings.linenocheck": "Zeilennummern",
|
||||
"pad.settings.rtlcheck": "Inhalt von rechts nach links lesen?",
|
||||
"pad.settings.fontType": "Schriftart:",
|
||||
"pad.settings.delete": "Pad löschen",
|
||||
"pad.delete.confirm": "Möchtest du dieses Pad wirklich löschen?",
|
||||
"pad.settings.fontType": "Schriftart:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Sprache:",
|
||||
"pad.settings.about": "Über",
|
||||
|
|
|
@ -72,6 +72,8 @@
|
|||
"pad.settings.fontType": "Font type:",
|
||||
"pad.settings.fontType.normal": "Normal",
|
||||
"pad.settings.language": "Language:",
|
||||
"pad.settings.deletePad": "Delete Pad",
|
||||
"pad.delete.confirm": "Do you really want to delete this pad?",
|
||||
"pad.settings.about": "About",
|
||||
"pad.settings.poweredBy": "Powered by",
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"Peter17",
|
||||
"Quenenni",
|
||||
"Rastus Vernon",
|
||||
"Spf",
|
||||
"Stephane Cottin",
|
||||
"Thibaut120094",
|
||||
"Tux-tn",
|
||||
|
@ -157,7 +158,7 @@
|
|||
"timeslider.toolbar.exportlink.title": "Exporter",
|
||||
"timeslider.exportCurrent": "Exporter la version actuelle sous :",
|
||||
"timeslider.version": "Version {{version}}",
|
||||
"timeslider.saved": "Enregistré le {{day}} {{month}} {{year}}",
|
||||
"timeslider.saved": "Enregistrée le {{day}} {{month}} {{year}}",
|
||||
"timeslider.playPause": "Lecture / Pause des contenus du bloc-notes",
|
||||
"timeslider.backRevision": "Reculer d’une révision dans ce bloc-notes",
|
||||
"timeslider.forwardRevision": "Avancer d’une révision dans ce bloc-notes",
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"pad.toolbar.import_export.title": "ਵੱਖ-ਵੱਖ ਫਾਇਲ ਫਾਰਮੈਟ ਤੋਂ/ਵਿੱਚ ਇੰਪੋਰਟ/ਐਕਸਪੋਰਟ ਕਰੋ",
|
||||
"pad.toolbar.timeslider.title": "ਸਮਾਂ-ਲਕੀਰ",
|
||||
"pad.toolbar.savedRevision.title": "ਦੁਹਰਾਅ ਸਾਂਭੋ",
|
||||
"pad.toolbar.settings.title": "ਸੈਟਿੰਗ",
|
||||
"pad.toolbar.settings.title": "ਪਸੰਦਾਂ",
|
||||
"pad.toolbar.embed.title": "ਇਹ ਪੈਡ ਸਾਂਝਾ ਤੇ ਇੰਬੈੱਡ ਕਰੋ",
|
||||
"pad.toolbar.showusers.title": "ਇਸ ਫੱਟੀ ਉੱਤੇ ਵਰਤੋਂਕਾਰ ਵਿਖਾਓ",
|
||||
"pad.colorpicker.save": "ਸੰਭਾਲੋ",
|
||||
|
@ -41,7 +41,7 @@
|
|||
"pad.settings.linenocheck": "ਲਕੀਰ ਨੰਬਰ",
|
||||
"pad.settings.rtlcheck": "ਸਮੱਗਰੀ ਸੱਜੇ ਤੋਂ ਖੱਬੇ ਪੜ੍ਹਨੀ ਹੈ?",
|
||||
"pad.settings.fontType": "ਫੋਂਟ ਕਿਸਮ:",
|
||||
"pad.settings.fontType.normal": "ਸਧਾਰਨ",
|
||||
"pad.settings.fontType.normal": "ਆਮ",
|
||||
"pad.settings.language": "ਭਾਸ਼ਾ:",
|
||||
"pad.importExport.import_export": "ਇੰਪੋਰਟ/ਐਕਸਪੋਰਟ",
|
||||
"pad.importExport.import": "ਕੋਈ ਵੀ ਟੈਕਸਟ ਫਾਇਲ ਜਾਂ ਦਸਤਾਵੇਜ਼ ਅੱਪਲੋਡ ਕਰੋ",
|
||||
|
@ -80,11 +80,11 @@
|
|||
"pad.modals.disconnected.cause": "ਸਰਵਰ ਨਾਮੌਜੂਦ ਹੋ ਸਕਦਾ ਹੈ। ਜੇਕਰ ਇਹ ਹੁੰਦਾ ਰਹੇ ਤਾਂ ਮਿਹਰਬਾਨੀ ਕਰਕੇ ਸੇਵਾ ਪ੍ਰਬੰਧਕ ਨੂੰ ਖ਼ਬਰ ਕਰੋ।",
|
||||
"pad.share": "ਇਹ ਪੈਡ ਸਾਂਝਾ ਕਰੋ",
|
||||
"pad.share.readonly": "ਕੇਵਲ ਪੜ੍ਹਨ ਲਈ",
|
||||
"pad.share.link": "ਲਿੰਕ",
|
||||
"pad.share.link": "ਕੜੀ",
|
||||
"pad.share.emebdcode": "ਇੰਬੈੱਡ URL",
|
||||
"pad.chat": "ਗੱਲਬਾਤ",
|
||||
"pad.chat.title": "ਇਹ ਪੈਡ ਲਈ ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ।",
|
||||
"pad.chat.loadmessages": "ਹੋਰ ਸੁਨੇਹੇ ਲੋਡ ਕਰੋ",
|
||||
"pad.chat.loadmessages": "ਹੋਰ ਸੁਨੇਹੇ ਲੱਦੋ",
|
||||
"timeslider.pageTitle": "{{appTitle}} ਸਮਾਂ-ਲਕੀਰ",
|
||||
"timeslider.toolbar.returnbutton": "ਪੈਡ ਉੱਤੇ ਵਾਪਸ",
|
||||
"timeslider.toolbar.authors": "ਲੇਖਕ:",
|
||||
|
|
|
@ -43,7 +43,7 @@ import {RateLimiterMemory} from 'rate-limiter-flexible';
|
|||
import {ChangesetRequest, PadUserInfo, SocketClientRequest} from "../types/SocketClientRequest";
|
||||
import {APool, AText, PadAuthor, PadType} from "../types/PadType";
|
||||
import {ChangeSet} from "../types/ChangeSet";
|
||||
import {ChatMessageMessage, ClientReadyMessage, ClientSaveRevisionMessage, ClientSuggestUserName, ClientUserChangesMessage, ClientVarMessage, CustomMessage, UserNewInfoMessage} from "../../static/js/types/SocketIOMessage";
|
||||
import {ChatMessageMessage, ClientReadyMessage, ClientSaveRevisionMessage, ClientSuggestUserName, ClientUserChangesMessage, ClientVarMessage, CustomMessage, PadDeleteMessage, UserNewInfoMessage} from "../../static/js/types/SocketIOMessage";
|
||||
import {Builder} from "../../static/js/Builder";
|
||||
const webaccess = require('../hooks/express/webaccess');
|
||||
const { checkValidRev } = require('../utils/checkValidRev');
|
||||
|
@ -211,6 +211,45 @@ exports.handleDisconnect = async (socket:any) => {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
const handlePadDelete = async (socket: any, padDeleteMessage: PadDeleteMessage) => {
|
||||
const session = sessioninfos[socket.id];
|
||||
if (!session || !session.author || !session.padId) throw new Error('session not ready');
|
||||
if (await padManager.doesPadExist(padDeleteMessage.data.padId)) {
|
||||
const retrievedPad = await padManager.getPad(padDeleteMessage.data.padId)
|
||||
// Only the one doing the first revision can delete the pad, otherwise people could troll a lot
|
||||
const firstContributor = await retrievedPad.getRevisionAuthor(0)
|
||||
if (session.author === firstContributor) {
|
||||
retrievedPad.remove()
|
||||
} else {
|
||||
|
||||
type ShoutMessage = {
|
||||
message: string,
|
||||
sticky: boolean,
|
||||
}
|
||||
|
||||
const messageToShout: ShoutMessage = {
|
||||
message: 'You are not the creator of this pad, so you cannot delete it',
|
||||
sticky: false
|
||||
}
|
||||
const messageToSend = {
|
||||
type: "COLLABROOM",
|
||||
data: {
|
||||
type: "shoutMessage",
|
||||
payload: {
|
||||
message: messageToShout,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
socket.emit('shout',
|
||||
messageToSend
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles a message from a user
|
||||
* @param socket the socket.io Socket object for the client
|
||||
|
@ -350,6 +389,7 @@ exports.handleMessage = async (socket:any, message: ClientVarMessage) => {
|
|||
stats.counter('pendingEdits').inc();
|
||||
await padChannels.enqueue(thisSession.padId, {socket, message});
|
||||
break;
|
||||
case 'PAD_DELETE': await handlePadDelete(socket, message.data as unknown as PadDeleteMessage); break;
|
||||
case 'USERINFO_UPDATE': await handleUserInfoUpdate(socket, message as unknown as UserNewInfoMessage); break;
|
||||
case 'CHAT_MESSAGE': await handleChatMessage(socket, message as unknown as ChatMessageMessage); break;
|
||||
case 'GET_CHAT_MESSAGES': await handleGetChatMessages(socket, message); break;
|
||||
|
|
|
@ -6,10 +6,10 @@ import {QueryType} from "../../types/QueryType";
|
|||
|
||||
import {getAvailablePlugins, install, search, uninstall} from "../../../static/js/pluginfw/installer";
|
||||
import {PackageData} from "../../types/PackageInfo";
|
||||
|
||||
const pluginDefs = require('../../../static/js/pluginfw/plugin_defs');
|
||||
import semver from 'semver';
|
||||
import log4js from 'log4js';
|
||||
|
||||
const pluginDefs = require('../../../static/js/pluginfw/plugin_defs');
|
||||
const logger = log4js.getLogger('adminPlugins');
|
||||
|
||||
|
||||
|
@ -20,10 +20,28 @@ exports.socketio = (hookName:string, args:ArgsExpressType, cb:Function) => {
|
|||
const {session: {user: {is_admin: isAdmin} = {}} = {}} = socket.conn.request;
|
||||
if (!isAdmin) return;
|
||||
|
||||
socket.on('getInstalled', (query:string) => {
|
||||
const checkPluginForUpdates = async () => {
|
||||
const results = await getAvailablePlugins(/* maxCacheAge:*/ 60 * 10);
|
||||
return Object.keys(pluginDefs.plugins).filter((plugin) => {
|
||||
if (!results[plugin]) return false;
|
||||
|
||||
const latestVersion = results[plugin].version;
|
||||
const currentVersion = pluginDefs.plugins[plugin].package.version;
|
||||
|
||||
return semver.gt(latestVersion, currentVersion);
|
||||
})
|
||||
}
|
||||
|
||||
socket.on('getInstalled', async (query: string) => {
|
||||
// send currently installed plugins
|
||||
const installed =
|
||||
Object.keys(pluginDefs.plugins).map((plugin) => pluginDefs.plugins[plugin].package);
|
||||
Object.keys(pluginDefs.plugins).map((plugin) => pluginDefs.plugins[plugin].package);
|
||||
|
||||
const updatable = await checkPluginForUpdates();
|
||||
|
||||
installed.forEach((plugin) => {
|
||||
plugin.updatable = updatable.includes(plugin.name);
|
||||
})
|
||||
|
||||
socket.emit('results:installed', {installed});
|
||||
});
|
||||
|
@ -31,16 +49,7 @@ exports.socketio = (hookName:string, args:ArgsExpressType, cb:Function) => {
|
|||
socket.on('checkUpdates', async () => {
|
||||
// Check plugins for updates
|
||||
try {
|
||||
const results = await getAvailablePlugins(/* maxCacheAge:*/ 60 * 10);
|
||||
|
||||
const updatable = Object.keys(pluginDefs.plugins).filter((plugin) => {
|
||||
if (!results[plugin]) return false;
|
||||
|
||||
const latestVersion = results[plugin].version;
|
||||
const currentVersion = pluginDefs.plugins[plugin].package.version;
|
||||
|
||||
return semver.gt(latestVersion, currentVersion);
|
||||
});
|
||||
const updatable = checkPluginForUpdates();
|
||||
|
||||
socket.emit('results:updatable', {updatable});
|
||||
} catch (err) {
|
||||
|
|
|
@ -112,7 +112,7 @@ const convertTypescript = (content: string) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleLiveReload = async (args: any, padString: string, timeSliderString: string, indexString: any) => {
|
||||
const handleLiveReload = async (args: ArgsExpressType, padString: string, timeSliderString: string, indexString: any) => {
|
||||
const chokidar = await import('chokidar')
|
||||
const watcher = chokidar.watch(path.join(settings.root, 'src', 'static', 'js'), {});
|
||||
let routeHandlers: { [key: string]: Function } = {};
|
||||
|
|
|
@ -33,20 +33,20 @@
|
|||
"@etherpad/express-session": "^1.18.4",
|
||||
"async": "^3.2.6",
|
||||
"axios": "^1.7.7",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cross-env": "^7.0.3",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"ejs": "^3.1.10",
|
||||
"esbuild": "^0.23.1",
|
||||
"express": "4.21.0",
|
||||
"express-rate-limit": "^7.4.0",
|
||||
"esbuild": "^0.24.0",
|
||||
"express": "4.21.1",
|
||||
"express-rate-limit": "^7.4.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"find-root": "1.1.0",
|
||||
"formidable": "^3.5.1",
|
||||
"formidable": "^3.5.2",
|
||||
"http-errors": "^2.0.0",
|
||||
"jose": "^5.9.2",
|
||||
"jose": "^5.9.6",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsdom": "^25.0.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"jsonminify": "0.4.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"languages4translatewiki": "0.1.3",
|
||||
|
@ -56,23 +56,23 @@
|
|||
"lru-cache": "^11.0.1",
|
||||
"measured-core": "^2.0.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"oidc-provider": "^8.5.1",
|
||||
"oidc-provider": "^8.5.2",
|
||||
"openapi-backend": "^5.11.0",
|
||||
"proxy-addr": "^2.0.7",
|
||||
"rate-limiter-flexible": "^5.0.3",
|
||||
"rehype": "^13.0.1",
|
||||
"rehype-minify-whitespace": "^6.0.1",
|
||||
"rate-limiter-flexible": "^5.0.4",
|
||||
"rehype": "^13.0.2",
|
||||
"rehype-minify-whitespace": "^6.0.2",
|
||||
"resolve": "1.22.8",
|
||||
"rusty-store-kv": "^1.3.1",
|
||||
"security": "1.0.0",
|
||||
"semver": "^7.6.3",
|
||||
"socket.io": "^4.7.5",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"superagent": "10.1.0",
|
||||
"socket.io": "^4.8.0",
|
||||
"socket.io-client": "^4.8.0",
|
||||
"superagent": "10.1.1",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"tinycon": "0.6.8",
|
||||
"tsx": "4.19.1",
|
||||
"ueberdb2": "^5.0.2",
|
||||
"ueberdb2": "^5.0.6",
|
||||
"underscore": "1.13.7",
|
||||
"unorm": "1.6.0",
|
||||
"wtfnode": "^0.9.3"
|
||||
|
@ -82,39 +82,39 @@
|
|||
"etherpad-lite": "node/server.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.47.1",
|
||||
"@playwright/test": "^1.48.1",
|
||||
"@types/async": "^3.2.24",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/express": "4.17.21",
|
||||
"@types/formidable": "^3.4.5",
|
||||
"@types/http-errors": "^2.0.4",
|
||||
"@types/jquery": "^3.5.30",
|
||||
"@types/jquery": "^3.5.32",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/jsonwebtoken": "^9.0.7",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/mocha": "^10.0.8",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/mocha": "^10.0.9",
|
||||
"@types/node": "^22.7.9",
|
||||
"@types/oidc-provider": "^8.5.2",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/sinon": "^17.0.3",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@types/swagger-ui-express": "^4.1.6",
|
||||
"@types/underscore": "^1.11.15",
|
||||
"@types/underscore": "^1.13.0",
|
||||
"@types/whatwg-mimetype": "^3.0.2",
|
||||
"chokidar": "^4.0.0",
|
||||
"eslint": "^9.10.0",
|
||||
"chokidar": "^4.0.1",
|
||||
"eslint": "^9.13.0",
|
||||
"eslint-config-etherpad": "^4.0.4",
|
||||
"etherpad-cli-client": "^3.0.2",
|
||||
"mocha": "^10.7.3",
|
||||
"mocha-froth": "^0.2.10",
|
||||
"nodeify": "^1.0.1",
|
||||
"openapi-schema-validation": "^0.4.2",
|
||||
"set-cookie-parser": "^2.7.0",
|
||||
"set-cookie-parser": "^2.7.1",
|
||||
"sinon": "^19.0.2",
|
||||
"split-grid": "^1.0.11",
|
||||
"supertest": "^7.0.0",
|
||||
"typescript": "^5.6.2",
|
||||
"vitest": "^2.1.1"
|
||||
"typescript": "^5.6.3",
|
||||
"vitest": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.18.2",
|
||||
|
@ -141,6 +141,6 @@
|
|||
"debug:socketio": "cross-env DEBUG=socket.io* node --require tsx/cjs node/server.ts",
|
||||
"test:vitest": "vitest"
|
||||
},
|
||||
"version": "2.2.5",
|
||||
"version": "2.2.6",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
|
|
|
@ -75,11 +75,20 @@ const padeditor = (() => {
|
|||
padutils.setCheckbox($('#options-rtlcheck'), ('rtl' === html10n.getDirection()));
|
||||
});
|
||||
|
||||
|
||||
|
||||
// font family change
|
||||
$('#viewfontmenu').on('change', () => {
|
||||
pad.changeViewOption('padFontFamily', $('#viewfontmenu').val());
|
||||
});
|
||||
|
||||
// delete pad
|
||||
$('#delete-pad').on('click', () => {
|
||||
if (window.confirm(html10n.get('pad.delete.confirm'))) {
|
||||
pad.collabClient.sendMessage({type: 'PAD_DELETE', data:{padId: pad.getPadId()}});
|
||||
}
|
||||
})
|
||||
|
||||
// Language
|
||||
html10n.bind('localized', () => {
|
||||
$('#languagemenu').val(html10n.getLanguage());
|
||||
|
|
|
@ -192,6 +192,14 @@ export type ClientSaveRevisionMessage = {
|
|||
type: 'SAVE_REVISION'
|
||||
}
|
||||
|
||||
|
||||
export type PadDeleteMessage = {
|
||||
type: 'PAD_DELETE'
|
||||
data: {
|
||||
padId: string
|
||||
}
|
||||
}
|
||||
|
||||
export type GetChatMessageMessage = {
|
||||
type: 'GET_CHAT_MESSAGES',
|
||||
start: number,
|
||||
|
@ -283,7 +291,7 @@ export type ChangesetRequestMessage = {
|
|||
|
||||
export type CollabroomMessage = {
|
||||
type: 'COLLABROOM'
|
||||
data: ClientSendUserInfoUpdate | ClientUserChangesMessage | ChatMessageMessage | GetChatMessageMessage | ClientSaveRevisionMessage | ClientMessageMessage
|
||||
data: ClientSendUserInfoUpdate | ClientUserChangesMessage | ChatMessageMessage | GetChatMessageMessage | ClientSaveRevisionMessage | ClientMessageMessage | PadDeleteMessage
|
||||
}
|
||||
|
||||
export type ClientVarMessage = | ClientVarData | ClientDisconnectedMessage | ClientReadyMessage| ChangesetRequestMessage | CollabroomMessage | CustomMessage
|
||||
|
|
|
@ -81,3 +81,7 @@
|
|||
.skin-variant-container {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
#delete-pad {
|
||||
background-color: #ff7b72;
|
||||
}
|
||||
|
|
|
@ -164,10 +164,10 @@
|
|||
</p>
|
||||
<% e.end_block(); %>
|
||||
</div>
|
||||
|
||||
<button data-l10n-id="pad.settings.delete" id="delete-pad">Delete pad</button>
|
||||
<h2 data-l10n-id="pad.settings.about">About</h2>
|
||||
<span data-l10n-id="pad.settings.poweredBy">Powered by</span>
|
||||
<a href="https://etherpad.org">Etherpad</a>
|
||||
<a href="https://etherpad.org" target="_blank" referrerpolicy="no-referrer" rel="noopener">Etherpad</a>
|
||||
<% if (settings.exposeVersion) { %>(commit <%=settings.getGitCommit()%>)<% } %>
|
||||
</div></div>
|
||||
|
||||
|
|
|
@ -250,6 +250,19 @@ export const sendUserChanges = async (socket:any, data:any) => await sendMessage
|
|||
},
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* Convenience function to send a delete pad request.
|
||||
*/
|
||||
export const sendPadDelete = async (socket:any, data:any) => await sendMessage(socket, {
|
||||
type: 'PAD_DELETE',
|
||||
component: 'pad',
|
||||
data: {
|
||||
padId: data.padId
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Convenience function that waits for an ACCEPT_COMMIT message. Asserts that the new revision
|
||||
* matches the expected revision.
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"ep_etherpad-lite": "workspace:../src",
|
||||
"typescript": "^5.6.2",
|
||||
"vite": "^5.4.7"
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^5.4.10"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -385,7 +385,7 @@
|
|||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<button data-l10n-id="pad.settings.delete">Delete pad</button>
|
||||
<h2 data-l10n-id="pad.settings.about">About</h2>
|
||||
<span data-l10n-id="pad.settings.poweredBy">Powered by</span>
|
||||
<a href="https://etherpad.org">Etherpad</a>
|
||||
|
|
Loading…
Reference in a new issue