mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 14:13:34 +01:00
fix(admin): Fixed updating plugins (#6705)
This commit is contained in:
parent
f61a3b6c5a
commit
0b26405201
4 changed files with 49 additions and 32 deletions
|
@ -95,7 +95,9 @@ export const App = () => {
|
||||||
<h1>Etherpad</h1>
|
<h1>Etherpad</h1>
|
||||||
</span>
|
</span>
|
||||||
<ul onClick={()=>{
|
<ul onClick={()=>{
|
||||||
setSidebarOpen(false)
|
if (window.innerWidth < 768) {
|
||||||
|
setSidebarOpen(false)
|
||||||
|
}
|
||||||
}}>
|
}}>
|
||||||
<li><NavLink to="/plugins"><Cable/><Trans i18nKey="admin_plugins"/></NavLink></li>
|
<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={"/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 {useDebounce} from "../utils/useDebounce.ts";
|
||||||
import {Trans, useTranslation} from "react-i18next";
|
import {Trans, useTranslation} from "react-i18next";
|
||||||
import {SearchField} from "../components/SearchField.tsx";
|
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 {IconButton} from "../components/IconButton.tsx";
|
||||||
import {determineSorting} from "../utils/sorting.ts";
|
import {determineSorting} from "../utils/sorting.ts";
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ import {determineSorting} from "../utils/sorting.ts";
|
||||||
export const HomePage = () => {
|
export const HomePage = () => {
|
||||||
const pluginsSocket = useStore(state=>state.pluginsSocket)
|
const pluginsSocket = useStore(state=>state.pluginsSocket)
|
||||||
const [plugins,setPlugins] = useState<PluginDef[]>([])
|
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>({
|
const [searchParams, setSearchParams] = useState<SearchParams>({
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: 99999,
|
limit: 99999,
|
||||||
|
@ -49,7 +50,7 @@ export const HomePage = () => {
|
||||||
}, [plugins, searchParams])
|
}, [plugins, searchParams])
|
||||||
|
|
||||||
const sortedInstalledPlugins = useMemo(()=>{
|
const sortedInstalledPlugins = useMemo(()=>{
|
||||||
return installedPlugins.sort((a, b)=>{
|
return useStore.getState().installedPlugins.sort((a, b)=>{
|
||||||
|
|
||||||
if(a.name < b.name){
|
if(a.name < b.name){
|
||||||
return -1
|
return -1
|
||||||
|
@ -78,17 +79,16 @@ export const HomePage = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
pluginsSocket.on('results:updatable', (data) => {
|
pluginsSocket.on('results:updatable', (data) => {
|
||||||
data.updatable.forEach((pluginName: string) => {
|
const newInstalledPlugins = useStore.getState().installedPlugins.map(plugin => {
|
||||||
setInstalledPlugins(installedPlugins.map(plugin => {
|
if (data.updatable.includes(plugin.name)) {
|
||||||
if (plugin.name === pluginName) {
|
return {
|
||||||
return {
|
...plugin,
|
||||||
...plugin,
|
updatable: true
|
||||||
updatable: true
|
}
|
||||||
}
|
}
|
||||||
}
|
return plugin
|
||||||
return plugin
|
})
|
||||||
}))
|
setInstalledPlugins(newInstalledPlugins)
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
pluginsSocket.on('finished:install', () => {
|
pluginsSocket.on('finished:install', () => {
|
||||||
|
@ -159,6 +159,7 @@ export const HomePage = () => {
|
||||||
})
|
})
|
||||||
}, 500, [searchTerm])
|
}, 500, [searchTerm])
|
||||||
|
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<h1><Trans i18nKey="admin_plugins"/></h1>
|
<h1><Trans i18nKey="admin_plugins"/></h1>
|
||||||
|
|
||||||
|
@ -180,7 +181,7 @@ export const HomePage = () => {
|
||||||
<td>
|
<td>
|
||||||
{
|
{
|
||||||
plugin.updatable ?
|
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)}/>
|
: <IconButton disabled={plugin.name == "ep_etherpad-lite"} icon={<Trash/>} title={<Trans i18nKey="admin_plugins.installed_uninstall.value"/>} onClick={() => uninstallPlugin(plugin.name)}/>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {create} from "zustand";
|
import {create} from "zustand";
|
||||||
import {Socket} from "socket.io-client";
|
import {Socket} from "socket.io-client";
|
||||||
import {PadSearchResult} from "../utils/PadSearch.ts";
|
import {PadSearchResult} from "../utils/PadSearch.ts";
|
||||||
|
import {InstalledPlugin} from "../pages/Plugin.ts";
|
||||||
|
|
||||||
type ToastState = {
|
type ToastState = {
|
||||||
description?:string,
|
description?:string,
|
||||||
|
@ -22,7 +23,9 @@ type StoreState = {
|
||||||
toastState: ToastState,
|
toastState: ToastState,
|
||||||
setToastState: (val: ToastState)=>void,
|
setToastState: (val: ToastState)=>void,
|
||||||
pads: PadSearchResult|undefined,
|
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
|
success: false
|
||||||
},
|
},
|
||||||
pads: undefined,
|
pads: undefined,
|
||||||
setPads: (pads)=>set({pads})
|
setPads: (pads)=>set({pads}),
|
||||||
|
installedPlugins: [],
|
||||||
|
setInstalledPlugins: (plugins)=>set({installedPlugins: plugins})
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -6,10 +6,10 @@ import {QueryType} from "../../types/QueryType";
|
||||||
|
|
||||||
import {getAvailablePlugins, install, search, uninstall} from "../../../static/js/pluginfw/installer";
|
import {getAvailablePlugins, install, search, uninstall} from "../../../static/js/pluginfw/installer";
|
||||||
import {PackageData} from "../../types/PackageInfo";
|
import {PackageData} from "../../types/PackageInfo";
|
||||||
|
|
||||||
const pluginDefs = require('../../../static/js/pluginfw/plugin_defs');
|
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import log4js from 'log4js';
|
import log4js from 'log4js';
|
||||||
|
|
||||||
|
const pluginDefs = require('../../../static/js/pluginfw/plugin_defs');
|
||||||
const logger = log4js.getLogger('adminPlugins');
|
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;
|
const {session: {user: {is_admin: isAdmin} = {}} = {}} = socket.conn.request;
|
||||||
if (!isAdmin) return;
|
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
|
// send currently installed plugins
|
||||||
const installed =
|
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});
|
socket.emit('results:installed', {installed});
|
||||||
});
|
});
|
||||||
|
@ -31,16 +49,7 @@ exports.socketio = (hookName:string, args:ArgsExpressType, cb:Function) => {
|
||||||
socket.on('checkUpdates', async () => {
|
socket.on('checkUpdates', async () => {
|
||||||
// Check plugins for updates
|
// Check plugins for updates
|
||||||
try {
|
try {
|
||||||
const results = await getAvailablePlugins(/* maxCacheAge:*/ 60 * 10);
|
const updatable = checkPluginForUpdates();
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.emit('results:updatable', {updatable});
|
socket.emit('results:updatable', {updatable});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
Loading…
Reference in a new issue