mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	feat: show top 5 trending plugins in new tab in Extend > Plugins
This commit is contained in:
		| @@ -1,4 +1,5 @@ | |||||||
| { | { | ||||||
|  | 	"trending": "Trending", | ||||||
| 	"installed": "Installed", | 	"installed": "Installed", | ||||||
| 	"active": "Active", | 	"active": "Active", | ||||||
| 	"inactive": "Inactive", | 	"inactive": "Inactive", | ||||||
|   | |||||||
| @@ -8,15 +8,25 @@ const meta = require('../../meta'); | |||||||
| const pluginsController = module.exports; | const pluginsController = module.exports; | ||||||
|  |  | ||||||
| pluginsController.get = async function (req, res) { | pluginsController.get = async function (req, res) { | ||||||
| 	const [compatible, all] = await Promise.all([ | 	const [compatible, all, trending] = await Promise.all([ | ||||||
| 		getCompatiblePlugins(), | 		getCompatiblePlugins(), | ||||||
| 		getAllPlugins(), | 		getAllPlugins(), | ||||||
|  | 		plugins.listTrending(), | ||||||
| 	]); | 	]); | ||||||
|  |  | ||||||
| 	const compatiblePkgNames = compatible.map(pkgData => pkgData.name); | 	const compatiblePkgNames = compatible.map(pkgData => pkgData.name); | ||||||
| 	const installedPlugins = compatible.filter(plugin => plugin && plugin.installed); | 	const installedPlugins = compatible.filter(plugin => plugin && plugin.installed); | ||||||
| 	const activePlugins = all.filter(plugin => plugin && plugin.installed && plugin.active); | 	const activePlugins = all.filter(plugin => plugin && plugin.installed && plugin.active); | ||||||
|  |  | ||||||
|  | 	const trendingScores = trending.reduce((memo, cur) => { | ||||||
|  | 		memo[cur.label] = cur.value; | ||||||
|  | 		return memo; | ||||||
|  | 	}, {}); | ||||||
|  | 	const trendingPlugins = all.filter(plugin => plugin && Object.keys(trendingScores).includes(plugin.id)).sort((a, b) => trendingScores[b.id] - trendingScores[a.id]).map((plugin) => { | ||||||
|  | 		plugin.downloads = trendingScores[plugin.id]; | ||||||
|  | 		return plugin; | ||||||
|  | 	}); | ||||||
|  |  | ||||||
| 	res.render('admin/extend/plugins', { | 	res.render('admin/extend/plugins', { | ||||||
| 		installed: installedPlugins, | 		installed: installedPlugins, | ||||||
| 		installedCount: installedPlugins.length, | 		installedCount: installedPlugins.length, | ||||||
| @@ -34,6 +44,7 @@ pluginsController.get = async function (req, res) { | |||||||
| 		incompatible: all.filter(function (plugin) { | 		incompatible: all.filter(function (plugin) { | ||||||
| 			return !compatiblePkgNames.includes(plugin.name); | 			return !compatiblePkgNames.includes(plugin.name); | ||||||
| 		}), | 		}), | ||||||
|  | 		trending: trendingPlugins, | ||||||
| 		submitPluginUsage: meta.config.submitPluginUsage, | 		submitPluginUsage: meta.config.submitPluginUsage, | ||||||
| 		version: nconf.get('version'), | 		version: nconf.get('version'), | ||||||
| 	}); | 	}); | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ const async = require('async'); | |||||||
| const winston = require('winston'); | const winston = require('winston'); | ||||||
| const semver = require('semver'); | const semver = require('semver'); | ||||||
| const nconf = require('nconf'); | const nconf = require('nconf'); | ||||||
| const util = require('util'); | const request = require('request-promise-native'); | ||||||
|  |  | ||||||
| const user = require('../user'); | const user = require('../user'); | ||||||
| const posts = require('../posts'); | const posts = require('../posts'); | ||||||
| @@ -141,24 +141,11 @@ Plugins.reloadRoutes = async function (params) { | |||||||
| 	winston.verbose('[plugins] All plugins reloaded and rerouted'); | 	winston.verbose('[plugins] All plugins reloaded and rerouted'); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| function request(url, callback) { |  | ||||||
| 	require('request')(url, { |  | ||||||
| 		json: true, |  | ||||||
| 	}, function (err, res, body) { |  | ||||||
| 		if (err) { |  | ||||||
| 			return callback(err); |  | ||||||
| 		} |  | ||||||
| 		if (res.statusCode === 404 || !body) { |  | ||||||
| 			return callback(null, {}); |  | ||||||
| 		} |  | ||||||
| 		callback(null, body); |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
| const requestAsync = util.promisify(request); |  | ||||||
|  |  | ||||||
| Plugins.get = async function (id) { | Plugins.get = async function (id) { | ||||||
| 	const url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins/' + id; | 	const url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins/' + id; | ||||||
| 	const body = await requestAsync(url); | 	const body = await request(url, { | ||||||
|  | 		json: true, | ||||||
|  | 	}); | ||||||
|  |  | ||||||
| 	let normalised = await Plugins.normalise([body ? body.payload : {}]); | 	let normalised = await Plugins.normalise([body ? body.payload : {}]); | ||||||
| 	normalised = normalised.filter(plugin => plugin.id === id); | 	normalised = normalised.filter(plugin => plugin.id === id); | ||||||
| @@ -172,7 +159,9 @@ Plugins.list = async function (matching) { | |||||||
| 	const version = require(path.join(nconf.get('base_dir'), 'package.json')).version; | 	const version = require(path.join(nconf.get('base_dir'), 'package.json')).version; | ||||||
| 	const url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins' + (matching !== false ? '?version=' + version : ''); | 	const url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins' + (matching !== false ? '?version=' + version : ''); | ||||||
| 	try { | 	try { | ||||||
| 		const body = await requestAsync(url); | 		const body = await request(url, { | ||||||
|  | 			json: true, | ||||||
|  | 		}); | ||||||
| 		return await Plugins.normalise(body); | 		return await Plugins.normalise(body); | ||||||
| 	} catch (err) { | 	} catch (err) { | ||||||
| 		winston.error('Error loading ' + url, err); | 		winston.error('Error loading ' + url, err); | ||||||
| @@ -180,6 +169,13 @@ Plugins.list = async function (matching) { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | Plugins.listTrending = async () => { | ||||||
|  | 	const url = `${nconf.get('registry') || 'https://packages.nodebb.org'}/api/v1/analytics/top/week`; | ||||||
|  | 	return await request(url, { | ||||||
|  | 		json: true, | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  |  | ||||||
| Plugins.normalise = async function (apiReturn) { | Plugins.normalise = async function (apiReturn) { | ||||||
| 	const themeNamePattern = /^(@.*?\/)?nodebb-theme-.*$/; | 	const themeNamePattern = /^(@.*?\/)?nodebb-theme-.*$/; | ||||||
| 	const pluginMap = {}; | 	const pluginMap = {}; | ||||||
|   | |||||||
| @@ -1,21 +1,37 @@ | |||||||
| <ul class="nav nav-pills"> | <ul class="nav nav-pills"> | ||||||
| 	<li class="active"><a href="#installed" data-toggle="tab"> | 	<li> | ||||||
| 		[[admin/extend/plugins:installed]] | 		<a href="#trending" data-toggle="tab"> | ||||||
| 		<span class="badge">{installedCount}</span> | 			[[admin/extend/plugins:trending]] | ||||||
| 	</a></li> | 			<i class="fa fa-star"></i> | ||||||
| 	<li><a href="#active" data-toggle="tab"> | 		</a> | ||||||
| 		[[admin/extend/plugins:active]] | 	</li> | ||||||
| 		<span class="badge">{activeCount}</span> | 	<li class="active"> | ||||||
| 	</a></li> | 		<a href="#installed" data-toggle="tab"> | ||||||
| 	<li><a href="#deactive" data-toggle="tab"> | 			[[admin/extend/plugins:installed]] | ||||||
| 		[[admin/extend/plugins:inactive]] | 			<span class="badge">{installedCount}</span> | ||||||
| 		<span class="badge">{inactiveCount}</span> | 		</a> | ||||||
| 	</a></li> | 	</li> | ||||||
| 	<li><a href="#upgrade" data-toggle="tab"> | 	<li> | ||||||
| 		[[admin/extend/plugins:out-of-date]] | 		<a href="#active" data-toggle="tab"> | ||||||
| 		<span class="badge">{upgradeCount}</span> | 			[[admin/extend/plugins:active]] | ||||||
| 	</a></li> | 			<span class="badge">{activeCount}</span> | ||||||
| 	<li><a href="#download" data-toggle="tab">[[admin/extend/plugins:find-plugins]]</a></li> | 		</a> | ||||||
|  | 	</li> | ||||||
|  | 	<li> | ||||||
|  | 		<a href="#deactive" data-toggle="tab"> | ||||||
|  | 			[[admin/extend/plugins:inactive]] | ||||||
|  | 			<span class="badge">{inactiveCount}</span> | ||||||
|  | 		</a> | ||||||
|  | 	</li> | ||||||
|  | 	<li> | ||||||
|  | 		<a href="#upgrade" data-toggle="tab"> | ||||||
|  | 			[[admin/extend/plugins:out-of-date]] | ||||||
|  | 			<span class="badge">{upgradeCount}</span> | ||||||
|  | 		</a> | ||||||
|  | 	</li> | ||||||
|  | 	<li> | ||||||
|  | 		<a href="#download" data-toggle="tab">[[admin/extend/plugins:find-plugins]]</a> | ||||||
|  | 	</li> | ||||||
| </ul> | </ul> | ||||||
| <br /> | <br /> | ||||||
|  |  | ||||||
| @@ -58,6 +74,13 @@ | |||||||
|  |  | ||||||
| 	<div class="col-lg-9 col-lg-pull-3"> | 	<div class="col-lg-9 col-lg-pull-3"> | ||||||
| 		<div class="tab-content"> | 		<div class="tab-content"> | ||||||
|  | 			<div class="tab-pane fade" id="trending"> | ||||||
|  | 				<ul class="trending"> | ||||||
|  | 					{{{ each trending }}} | ||||||
|  | 					<!-- IMPORT admin/partials/installed_plugin_item.tpl --> | ||||||
|  | 					{{{ end }}} | ||||||
|  | 				</ul> | ||||||
|  | 			</div> | ||||||
| 			<div class="tab-pane fade active in" id="installed"> | 			<div class="tab-pane fade active in" id="installed"> | ||||||
| 				<ul class="installed"> | 				<ul class="installed"> | ||||||
| 					<!-- BEGIN installed --> | 					<!-- BEGIN installed --> | ||||||
|   | |||||||
| @@ -1,25 +1,25 @@ | |||||||
| 					<li id="{download.id}" data-plugin-id="{download.id}" class="clearfix"> | 					<li id="{../id}" data-plugin-id="{../id}" class="clearfix"> | ||||||
| 						<div class="pull-right"> | 						<div class="pull-right"> | ||||||
| 							<button data-action="toggleActive" class="btn btn-success hidden"><i class="fa fa-power-off"></i> [[admin/extend/plugins:plugin-item.activate]]</button> | 							<button data-action="toggleActive" class="btn btn-success hidden"><i class="fa fa-power-off"></i> [[admin/extend/plugins:plugin-item.activate]]</button> | ||||||
| 							<button data-action="toggleInstall" data-installed="0" class="btn btn-success"><i class="fa fa-download"></i> [[admin/extend/plugins:plugin-item.install]]</button> | 							<button data-action="toggleInstall" data-installed="0" class="btn btn-success"><i class="fa fa-download"></i> [[admin/extend/plugins:plugin-item.install]]</button> | ||||||
| 						</div> | 						</div> | ||||||
|  |  | ||||||
| 						<h2><strong>{download.name}</strong></h2> | 						<h2><strong>{../name}</strong></h2> | ||||||
|  |  | ||||||
| 						<!-- IF download.description --> | 						<!-- IF ../description --> | ||||||
| 						<p>{download.description}</p> | 						<p>{../description}</p> | ||||||
| 						<!-- ENDIF download.description --> | 						<!-- ENDIF ../description --> | ||||||
|  |  | ||||||
| 						<small>[[admin/extend/plugins:plugin-item.latest]] <strong class="latestVersion">{download.latest}</strong></small> | 						<small>[[admin/extend/plugins:plugin-item.latest]] <strong class="latestVersion">{../latest}</strong></small> | ||||||
| 						<p> | 						<p> | ||||||
| 							<!-- IF download.isCompatible --> | 							<!-- IF ../isCompatible --> | ||||||
| 							<i class="fa fa-check text-success"></i> [[admin/extend/plugins:plugin-item.compatible, {version}]] | 							<i class="fa fa-check text-success"></i> [[admin/extend/plugins:plugin-item.compatible, {version}]] | ||||||
| 							<!-- ELSE --> | 							<!-- ELSE --> | ||||||
| 							<i class="fa fa-question text-warning"></i> [[admin/extend/plugins:plugin-item.not-compatible]] | 							<i class="fa fa-question text-warning"></i> [[admin/extend/plugins:plugin-item.not-compatible]] | ||||||
| 							<!-- ENDIF --> | 							<!-- ENDIF --> | ||||||
| 						</p> | 						</p> | ||||||
|  |  | ||||||
| 						<!-- IF download.url --> | 						<!-- IF ../url --> | ||||||
| 						<p>[[admin/extend/plugins:plugin-item.more-info]] <a target="_blank" href="{download.url}">{download.url}</a></p> | 						<p>[[admin/extend/plugins:plugin-item.more-info]] <a target="_blank" href="{../url}">{../url}</a></p> | ||||||
| 						<!-- ENDIF download.url --> | 						<!-- ENDIF ../url --> | ||||||
| 					</li> | 					</li> | ||||||
|   | |||||||
| @@ -1,56 +1,60 @@ | |||||||
| 					<!-- IF !installed.error --> | 					<!-- IF !../error --> | ||||||
| 					<li id="{installed.id}" data-plugin-index="@index" data-plugin-id="{installed.id}" data-version="{installed.version}" class="clearfix <!-- IF installed.active -->active<!-- ENDIF installed.active -->"> | 					<li id="{../id}" data-plugin-index="@index" data-plugin-id="{../id}" data-version="{../version}" class="clearfix <!-- IF ../active -->active<!-- ENDIF ../active -->"> | ||||||
| 						<div class="pull-right controls"> | 						<div class="pull-right controls"> | ||||||
| 							<!-- IF installed.isTheme --> | 							{{{ if ../installed }}} | ||||||
| 							<a href="{config.relative_path}/admin/appearance/themes" class="btn btn-info">[[admin/extend/plugins:plugin-item.themes]]</a> | 								<!-- IF ../isTheme --> | ||||||
| 							<!-- ELSE --> | 								<a href="{config.relative_path}/admin/appearance/themes" class="btn btn-info">[[admin/extend/plugins:plugin-item.themes]]</a> | ||||||
| 							<button data-action="toggleActive" class="btn <!-- IF installed.active --> btn-warning<!-- ELSE --> btn-success<!-- ENDIF installed.active -->"> | 								<!-- ELSE --> | ||||||
| 							<i class="fa fa-power-off"></i> <!-- IF installed.active -->[[admin/extend/plugins:plugin-item.deactivate]]<!-- ELSE -->[[admin/extend/plugins:plugin-item.activate]]<!-- ENDIF installed.active --></button> | 								<button data-action="toggleActive" class="btn <!-- IF ../active --> btn-warning<!-- ELSE --> btn-success<!-- ENDIF ../active -->"> | ||||||
| 							<!-- ENDIF installed.isTheme --> | 								<i class="fa fa-power-off"></i> <!-- IF ../active -->[[admin/extend/plugins:plugin-item.deactivate]]<!-- ELSE -->[[admin/extend/plugins:plugin-item.activate]]<!-- ENDIF ../active --></button> | ||||||
|  | 								<!-- ENDIF ../isTheme --> | ||||||
|  |  | ||||||
| 							<button data-action="toggleInstall" data-installed="1" class="btn btn-danger"><i class="fa fa-trash-o"></i> [[admin/extend/plugins:plugin-item.uninstall]]</button> | 								<button data-action="toggleInstall" data-installed="1" class="btn btn-danger"><i class="fa fa-trash-o"></i> [[admin/extend/plugins:plugin-item.uninstall]]</button> | ||||||
|  |  | ||||||
| 							<!-- IF installed.active --> | 								<!-- IF ../active --> | ||||||
| 							<!-- IF installed.settingsRoute --> | 								<!-- IF ../settingsRoute --> | ||||||
| 							<a href="{config.relative_path}{installed.settingsRoute}" class="btn btn-primary"><i class="fa fa-wrench"></i> [[admin/extend/plugins:plugin-item.settings]]</a> | 								<a href="{config.relative_path}{../settingsRoute}" class="btn btn-primary"><i class="fa fa-wrench"></i> [[admin/extend/plugins:plugin-item.settings]]</a> | ||||||
| 							<!-- ENDIF installed.settingsRoute --> | 								<!-- ENDIF ../settingsRoute --> | ||||||
| 							<!-- ENDIF installed.active --> | 								<!-- ENDIF ../active --> | ||||||
|  | 							{{{ else }}} | ||||||
|  | 								<button data-action="toggleInstall" data-installed="0" class="btn btn-success"><i class="fa fa-download"></i> [[admin/extend/plugins:plugin-item.install]]</button> | ||||||
|  | 							{{{ end }}} | ||||||
| 						</div> | 						</div> | ||||||
|  |  | ||||||
| 						<h2><strong>{installed.name}</strong></h2> | 						<h2><strong>{../name}</strong></h2> | ||||||
|  |  | ||||||
| 						<!-- IF installed.description --> | 						<!-- IF ../description --> | ||||||
| 						<p>{installed.description}</p> | 						<p>{../description}</p> | ||||||
| 						<!-- ENDIF installed.description --> | 						<!-- ENDIF ../description --> | ||||||
| 						<!-- IF installed.outdated --><i class="fa fa-exclamation-triangle text-danger"></i> <!-- ENDIF installed.outdated --> | 						<!-- IF ../outdated --><i class="fa fa-exclamation-triangle text-danger"></i> <!-- ENDIF ../outdated --> | ||||||
| 						<small>[[admin/extend/plugins:plugin-item.installed]] <strong class="currentVersion">{installed.version}</strong> | [[admin/extend/plugins:plugin-item.latest]] <strong class="latestVersion">{installed.latest}</strong></small> | 						<small>[[admin/extend/plugins:plugin-item.installed]] <strong class="currentVersion">{../version}</strong> | [[admin/extend/plugins:plugin-item.latest]] <strong class="latestVersion">{../latest}</strong></small> | ||||||
|  |  | ||||||
| 						<!-- IF installed.outdated --> | 						<!-- IF ../outdated --> | ||||||
| 						<button data-action="upgrade" class="btn btn-success btn-xs"><i class="fa fa-download"></i> [[admin/extend/plugins:plugin-item.upgrade]]</button> | 						<button data-action="upgrade" class="btn btn-success btn-xs"><i class="fa fa-download"></i> [[admin/extend/plugins:plugin-item.upgrade]]</button> | ||||||
| 						<p> | 						<p> | ||||||
| 							<!-- IF installed.isCompatible --> | 							<!-- IF ../isCompatible --> | ||||||
| 							<i class="fa fa-check text-success"></i> [[admin/extend/plugins:plugin-item.compatible, {version}]] | 							<i class="fa fa-check text-success"></i> [[admin/extend/plugins:plugin-item.compatible, {version}]] | ||||||
| 							<!-- ELSE --> | 							<!-- ELSE --> | ||||||
| 							<i class="fa fa-question text-warning"></i> [[admin/extend/plugins:plugin-item.not-compatible]] | 							<i class="fa fa-question text-warning"></i> [[admin/extend/plugins:plugin-item.not-compatible]] | ||||||
| 							<!-- ENDIF --> | 							<!-- ENDIF --> | ||||||
| 						</p> | 						</p> | ||||||
| 						<!-- ENDIF installed.outdated --> | 						<!-- ENDIF ../outdated --> | ||||||
|  |  | ||||||
| 						<!-- IF installed.url --> | 						<!-- IF ../url --> | ||||||
| 						<p>[[admin/extend/plugins:plugin-item.more-info]] <a target="_blank" href="{installed.url}">{installed.url}</a></p> | 						<p>[[admin/extend/plugins:plugin-item.more-info]] <a target="_blank" href="{../url}">{../url}</a></p> | ||||||
| 						<!-- ENDIF installed.url --> | 						<!-- ENDIF ../url --> | ||||||
| 					</li> | 					</li> | ||||||
| 					<!-- ENDIF !installed.error --> | 					<!-- ENDIF !../error --> | ||||||
| 					<!-- IF installed.error --> | 					<!-- IF ../error --> | ||||||
| 					<li data-plugin-id="{installed.id}" class="clearfix"> | 					<li data-plugin-id="{../id}" class="clearfix"> | ||||||
| 						<div class="pull-right"> | 						<div class="pull-right"> | ||||||
| 							<button class="btn btn-default disabled"><i class="fa fa-exclamation-triangle"></i> [[admin/extend/plugins:plugin-item.unknown]]</button> | 							<button class="btn btn-default disabled"><i class="fa fa-exclamation-triangle"></i> [[admin/extend/plugins:plugin-item.unknown]]</button> | ||||||
| 							<button data-action="toggleInstall" data-installed="1" class="btn btn-danger"><i class="fa fa-trash-o"></i> [[admin/extend/plugins:plugin-item.uninstall]]</button> | 							<button data-action="toggleInstall" data-installed="1" class="btn btn-danger"><i class="fa fa-trash-o"></i> [[admin/extend/plugins:plugin-item.uninstall]]</button> | ||||||
| 						</div> | 						</div> | ||||||
|  |  | ||||||
| 						<h2><strong>{installed.id}</strong></h2> | 						<h2><strong>{../id}</strong></h2> | ||||||
| 						<p> | 						<p> | ||||||
| 							[[admin/extend/plugins:plugin-item.unknown-explanation]] | 							[[admin/extend/plugins:plugin-item.unknown-explanation]] | ||||||
| 						</p> | 						</p> | ||||||
| 					</li> | 					</li> | ||||||
| 					<!-- ENDIF installed.error --> | 					<!-- ENDIF ../error --> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user