mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 04:22:07 +02:00
MDL-82283 admin: js filtering of the plugins on plugins overview page
This commit is contained in:
parent
1938c438ea
commit
f8e7bbe776
11
admin/amd/build/plugins_overview.min.js
vendored
Normal file
11
admin/amd/build/plugins_overview.min.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
define("core_admin/plugins_overview",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){const filters=document.querySelectorAll(SELECTORS_PLUGIN_FILTERS),pluginRows=document.querySelectorAll(SELECTORS_PLUGIN_ROWS),pluginTypeRows=document.querySelectorAll(SELECTORS_PLUGIN_TYPE_ROWS),filterPlugins=target=>{const filterBy=target.getAttribute("data-filterby"),headerVisibility={};for(const row of pluginRows){const type=[...row.classList].find((s=>s.startsWith("type-"))),visible="all"===filterBy||row.classList.contains(filterBy);row.style.display=visible?null:"none",visible&&type&&(headerVisibility[type]=!0)}for(const row of pluginTypeRows){const type=[...row.classList].find((s=>s.startsWith("type-")));if(type){const visible="all"===filterBy||headerVisibility[type];row.style.display=visible?null:"none"}}filters.forEach((el=>el.classList.remove("active"))),target.classList.add("active")};if(filters.forEach((target=>target.addEventListener("click",(e=>{e.preventDefault(),window.history.replaceState({},null,e.target.href),filterPlugins(target)})))),window.location.hash.length>1){const anchor=window.location.hash.substring(1),target=[...filters].find((t=>t.getAttribute("data-filterby")===anchor));target&&filterPlugins(target)}};
|
||||
/**
|
||||
* Allows to filter the plugin list on plugins overview page
|
||||
*
|
||||
* @module core_admin/plugins_overview
|
||||
* @copyright 2024 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const SELECTORS_PLUGIN_FILTERS="#plugins-overview-panel [data-filterby]",SELECTORS_PLUGIN_ROWS="table#plugins-control-panel tbody tr:not(.plugintypeheader)",SELECTORS_PLUGIN_TYPE_ROWS="table#plugins-control-panel tbody tr.plugintypeheader"}));
|
||||
|
||||
//# sourceMappingURL=plugins_overview.min.js.map
|
1
admin/amd/build/plugins_overview.min.js.map
Normal file
1
admin/amd/build/plugins_overview.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"plugins_overview.min.js","sources":["../src/plugins_overview.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allows to filter the plugin list on plugins overview page\n *\n * @module core_admin/plugins_overview\n * @copyright 2024 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst SELECTORS = {\n PLUGIN_FILTERS: '#plugins-overview-panel [data-filterby]',\n PLUGIN_ROWS: 'table#plugins-control-panel tbody tr:not(.plugintypeheader)',\n PLUGIN_TYPE_ROWS: 'table#plugins-control-panel tbody tr.plugintypeheader',\n};\n\n/**\n * Initialise filters for the \"Plugins overview\" page\n */\nexport function init() {\n const filters = document.querySelectorAll(SELECTORS.PLUGIN_FILTERS);\n const pluginRows = document.querySelectorAll(SELECTORS.PLUGIN_ROWS);\n const pluginTypeRows = document.querySelectorAll(SELECTORS.PLUGIN_TYPE_ROWS);\n\n const filterPlugins = (target) => {\n const filterBy = target.getAttribute('data-filterby');\n const headerVisibility = {};\n\n // Hide all plugin rows in the plugin table that do not match the filter and show all others.\n for (const row of pluginRows) {\n const type = [...row.classList].find(s => s.startsWith('type-'));\n const visible = filterBy === 'all' ? true : row.classList.contains(filterBy);\n row.style.display = visible ? null : 'none';\n if (visible && type) {\n headerVisibility[type] = true;\n }\n }\n\n // Hide all the plugin type headers that do not have any visible plugins and show all others.\n for (const row of pluginTypeRows) {\n const type = [...row.classList].find(s => s.startsWith('type-'));\n if (type) {\n const visible = filterBy === 'all' || headerVisibility[type];\n row.style.display = visible ? null : 'none';\n }\n }\n\n // Toggle 'active' class for the selected filter.\n filters.forEach(el => el.classList.remove('active'));\n target.classList.add('active');\n };\n\n // Add event listeners for the links changing plugins filters.\n filters\n .forEach(target => target.addEventListener('click', (e) => {\n e.preventDefault();\n window.history.replaceState({}, null, e.target.href);\n filterPlugins(target);\n }));\n\n // Pre-filter plugins based on the current url anchor.\n if (window.location.hash.length > 1) {\n const anchor = window.location.hash.substring(1);\n const target = [...filters].find(t => t.getAttribute('data-filterby') === anchor);\n if (target) {\n filterPlugins(target);\n }\n }\n}\n"],"names":["filters","document","querySelectorAll","SELECTORS","pluginRows","pluginTypeRows","filterPlugins","target","filterBy","getAttribute","headerVisibility","row","type","classList","find","s","startsWith","visible","contains","style","display","forEach","el","remove","add","addEventListener","e","preventDefault","window","history","replaceState","href","location","hash","length","anchor","substring","t"],"mappings":"4JAiCUA,QAAUC,SAASC,iBAAiBC,0BACpCC,WAAaH,SAASC,iBAAiBC,uBACvCE,eAAiBJ,SAASC,iBAAiBC,4BAE3CG,cAAiBC,eACbC,SAAWD,OAAOE,aAAa,iBAC/BC,iBAAmB,OAGpB,MAAMC,OAAOP,WAAY,OACpBQ,KAAO,IAAID,IAAIE,WAAWC,MAAKC,GAAKA,EAAEC,WAAW,WACjDC,QAAuB,QAAbT,UAA4BG,IAAIE,UAAUK,SAASV,UACnEG,IAAIQ,MAAMC,QAAUH,QAAU,KAAO,OACjCA,SAAWL,OACXF,iBAAiBE,OAAQ,OAK5B,MAAMD,OAAON,eAAgB,OACxBO,KAAO,IAAID,IAAIE,WAAWC,MAAKC,GAAKA,EAAEC,WAAW,cACnDJ,KAAM,OACAK,QAAuB,QAAbT,UAAsBE,iBAAiBE,MACvDD,IAAIQ,MAAMC,QAAUH,QAAU,KAAO,QAK7CjB,QAAQqB,SAAQC,IAAMA,GAAGT,UAAUU,OAAO,YAC1ChB,OAAOM,UAAUW,IAAI,cAIzBxB,QACCqB,SAAQd,QAAUA,OAAOkB,iBAAiB,SAAUC,IACjDA,EAAEC,iBACFC,OAAOC,QAAQC,aAAa,GAAI,KAAMJ,EAAEnB,OAAOwB,MAC/CzB,cAAcC,aAIdqB,OAAOI,SAASC,KAAKC,OAAS,EAAG,OAC3BC,OAASP,OAAOI,SAASC,KAAKG,UAAU,GACxC7B,OAAS,IAAIP,SAASc,MAAKuB,GAAKA,EAAE5B,aAAa,mBAAqB0B,SACtE5B,QACAD,cAAcC;;;;;;;;MAvDpBJ,yBACc,0CADdA,sBAEW,8DAFXA,2BAGgB"}
|
82
admin/amd/src/plugins_overview.js
Normal file
82
admin/amd/src/plugins_overview.js
Normal file
@ -0,0 +1,82 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Allows to filter the plugin list on plugins overview page
|
||||
*
|
||||
* @module core_admin/plugins_overview
|
||||
* @copyright 2024 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
const SELECTORS = {
|
||||
PLUGIN_FILTERS: '#plugins-overview-panel [data-filterby]',
|
||||
PLUGIN_ROWS: 'table#plugins-control-panel tbody tr:not(.plugintypeheader)',
|
||||
PLUGIN_TYPE_ROWS: 'table#plugins-control-panel tbody tr.plugintypeheader',
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise filters for the "Plugins overview" page
|
||||
*/
|
||||
export function init() {
|
||||
const filters = document.querySelectorAll(SELECTORS.PLUGIN_FILTERS);
|
||||
const pluginRows = document.querySelectorAll(SELECTORS.PLUGIN_ROWS);
|
||||
const pluginTypeRows = document.querySelectorAll(SELECTORS.PLUGIN_TYPE_ROWS);
|
||||
|
||||
const filterPlugins = (target) => {
|
||||
const filterBy = target.getAttribute('data-filterby');
|
||||
const headerVisibility = {};
|
||||
|
||||
// Hide all plugin rows in the plugin table that do not match the filter and show all others.
|
||||
for (const row of pluginRows) {
|
||||
const type = [...row.classList].find(s => s.startsWith('type-'));
|
||||
const visible = filterBy === 'all' ? true : row.classList.contains(filterBy);
|
||||
row.style.display = visible ? null : 'none';
|
||||
if (visible && type) {
|
||||
headerVisibility[type] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide all the plugin type headers that do not have any visible plugins and show all others.
|
||||
for (const row of pluginTypeRows) {
|
||||
const type = [...row.classList].find(s => s.startsWith('type-'));
|
||||
if (type) {
|
||||
const visible = filterBy === 'all' || headerVisibility[type];
|
||||
row.style.display = visible ? null : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle 'active' class for the selected filter.
|
||||
filters.forEach(el => el.classList.remove('active'));
|
||||
target.classList.add('active');
|
||||
};
|
||||
|
||||
// Add event listeners for the links changing plugins filters.
|
||||
filters
|
||||
.forEach(target => target.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
window.history.replaceState({}, null, e.target.href);
|
||||
filterPlugins(target);
|
||||
}));
|
||||
|
||||
// Pre-filter plugins based on the current url anchor.
|
||||
if (window.location.hash.length > 1) {
|
||||
const anchor = window.location.hash.substring(1);
|
||||
const target = [...filters].find(t => t.getAttribute('data-filterby') === anchor);
|
||||
if (target) {
|
||||
filterPlugins(target);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,8 +29,6 @@ require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
$fetchupdates = optional_param('fetchupdates', false, PARAM_BOOL); // Check for available plugins updates.
|
||||
$updatesonly = optional_param('updatesonly', false, PARAM_BOOL); // Show updateable plugins only.
|
||||
$contribonly = optional_param('contribonly', false, PARAM_BOOL); // Show additional plugins only.
|
||||
$uninstall = optional_param('uninstall', '', PARAM_COMPONENT); // Uninstall the plugin.
|
||||
$delete = optional_param('delete', '', PARAM_COMPONENT); // Delete the plugin folder after it is uninstalled.
|
||||
$confirmed = optional_param('confirm', false, PARAM_BOOL); // Confirm the uninstall/delete action.
|
||||
@ -47,8 +45,7 @@ require_admin();
|
||||
$syscontext = context_system::instance();
|
||||
|
||||
// URL params we want to maintain on redirects.
|
||||
$pageparams = array('updatesonly' => $updatesonly, 'contribonly' => $contribonly);
|
||||
$pageurl = new moodle_url('/admin/plugins.php', $pageparams);
|
||||
$pageurl = new moodle_url('/admin/plugins.php');
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
@ -57,7 +54,7 @@ $PAGE->set_primary_active_tab('siteadminnode');
|
||||
if ($uninstall) {
|
||||
|
||||
if (!$confirmed) {
|
||||
admin_externalpage_setup('pluginsoverview', '', $pageparams);
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
} else {
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context($syscontext);
|
||||
@ -201,7 +198,7 @@ if ($installupdate and $installupdateversion) {
|
||||
}
|
||||
}
|
||||
|
||||
admin_externalpage_setup('pluginsoverview', '', $pageparams);
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
@ -214,4 +211,4 @@ if ($fetchupdates) {
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
echo $output->plugin_management_page($pluginman, $checker, $pageparams);
|
||||
echo $output->plugin_management_page($pluginman, $checker);
|
||||
|
@ -1673,8 +1673,9 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
public function plugins_overview_panel(core_plugin_manager $pluginman, array $options = array()) {
|
||||
|
||||
$plugininfo = $pluginman->get_plugins();
|
||||
$this->page->requires->js_call_amd('core_admin/plugins_overview', 'init');
|
||||
|
||||
$numtotal = $numextension = $numupdatable = $numinstallable = 0;
|
||||
$numtotal = $numextension = $numupdatable = $numinstallable = $nummissing = $numnew = 0;
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
@ -1688,8 +1689,12 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
}
|
||||
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$nummissing++;
|
||||
continue;
|
||||
}
|
||||
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_NEW) {
|
||||
$numnew++;
|
||||
}
|
||||
$numtotal++;
|
||||
if (!$plugin->is_standard()) {
|
||||
$numextension++;
|
||||
@ -1698,36 +1703,50 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$infoall = html_writer::link(
|
||||
new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 0)),
|
||||
$this->page->url,
|
||||
get_string('overviewall', 'core_plugin'),
|
||||
array('title' => get_string('filterall', 'core_plugin'))
|
||||
['title' => get_string('filterall', 'core_plugin'), 'data-filterby' => 'all', 'class' => 'active']
|
||||
).' '.html_writer::span($numtotal, 'badge number number-all');
|
||||
|
||||
$infoext = html_writer::link(
|
||||
new moodle_url($this->page->url, array('contribonly' => 1, 'updatesonly' => 0)),
|
||||
new moodle_url($this->page->url, [], 'additional'),
|
||||
get_string('overviewext', 'core_plugin'),
|
||||
array('title' => get_string('filtercontribonly', 'core_plugin'))
|
||||
['title' => get_string('filtercontribonly', 'core_plugin'), 'data-filterby' => 'additional']
|
||||
).' '.html_writer::span($numextension, 'badge number number-additional');
|
||||
|
||||
if ($numupdatable) {
|
||||
$infoupdatable = html_writer::link(
|
||||
new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 1)),
|
||||
new moodle_url($this->page->url, [], 'updatable'),
|
||||
get_string('overviewupdatable', 'core_plugin'),
|
||||
array('title' => get_string('filterupdatesonly', 'core_plugin'))
|
||||
['title' => get_string('filterupdatesonly', 'core_plugin'), 'data-filterby' => 'updatable']
|
||||
).' '.html_writer::span($numupdatable, 'badge bg-info text-white number number-updatable');
|
||||
} else {
|
||||
// No updates, or the notifications disabled.
|
||||
$infoupdatable = '';
|
||||
}
|
||||
|
||||
$out = html_writer::start_div('', array('id' => 'plugins-overview-panel'));
|
||||
|
||||
if (!empty($options['updatesonly'])) {
|
||||
$out .= $this->output->heading(get_string('overviewupdatable', 'core_plugin'), 3);
|
||||
} else if (!empty($options['contribonly'])) {
|
||||
$out .= $this->output->heading(get_string('overviewext', 'core_plugin'), 3);
|
||||
if ($numnew) {
|
||||
$infonew = html_writer::link(
|
||||
new moodle_url($this->page->url, [], 'newplugin'),
|
||||
get_string('status_new', 'plugin'),
|
||||
['title' => get_string('filternewpluginsonly', 'core_plugin'), 'data-filterby' => 'newplugin']
|
||||
).' '.html_writer::span($numnew, 'badge bg-success text-white number number-newplugin');
|
||||
} else {
|
||||
$infonew = '';
|
||||
}
|
||||
|
||||
if ($nummissing) {
|
||||
$infomissing = html_writer::link(
|
||||
new moodle_url($this->page->url, [], 'missing'),
|
||||
get_string('status_missing', 'plugin'),
|
||||
['title' => get_string('filtermissingonly', 'core_plugin'), 'data-filterby' => 'missing']
|
||||
).' '.html_writer::span($nummissing, 'badge bg-danger text-white number number-missing');
|
||||
} else {
|
||||
$infomissing = '';
|
||||
}
|
||||
|
||||
$out = html_writer::start_div('', ['id' => 'plugins-overview-panel']);
|
||||
|
||||
if ($numinstallable) {
|
||||
$out .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('installupdatex' => 1)),
|
||||
@ -1738,8 +1757,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$out .= html_writer::div($infoall, 'info info-all').
|
||||
html_writer::div($infoext, 'info info-ext').
|
||||
html_writer::div($infoupdatable, 'info info-updatable');
|
||||
html_writer::div($infoext, 'info info-additional').
|
||||
html_writer::div($infoupdatable, 'info info-updatable').
|
||||
html_writer::div($infonew, 'info info-newplugin').
|
||||
html_writer::div($infomissing, 'info info-missing');
|
||||
|
||||
$out .= html_writer::end_div(); // End of #plugins-overview-panel block.
|
||||
|
||||
@ -1759,38 +1780,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$plugininfo = $pluginman->get_plugins();
|
||||
|
||||
// Filter the list of plugins according the options.
|
||||
if (!empty($options['updatesonly'])) {
|
||||
$updateable = array();
|
||||
foreach ($plugininfo as $plugintype => $pluginnames) {
|
||||
foreach ($pluginnames as $pluginname => $pluginfo) {
|
||||
$pluginavailableupdates = $pluginfo->available_updates();
|
||||
if (!empty($pluginavailableupdates)) {
|
||||
foreach ($pluginavailableupdates as $pluginavailableupdate) {
|
||||
$updateable[$plugintype][$pluginname] = $pluginfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$plugininfo = $updateable;
|
||||
}
|
||||
|
||||
if (!empty($options['contribonly'])) {
|
||||
$contribs = array();
|
||||
foreach ($plugininfo as $plugintype => $pluginnames) {
|
||||
foreach ($pluginnames as $pluginname => $pluginfo) {
|
||||
if (!$pluginfo->is_standard()) {
|
||||
$contribs[$plugintype][$pluginname] = $pluginfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
$plugininfo = $contribs;
|
||||
}
|
||||
|
||||
if (empty($plugininfo)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$table = new html_table();
|
||||
$table->id = 'plugins-control-panel';
|
||||
$table->head = array(
|
||||
@ -1888,13 +1877,15 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$row->attributes['class'] .= ' standard';
|
||||
$source = '';
|
||||
} else {
|
||||
$row->attributes['class'] .= ' extension';
|
||||
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge bg-info text-white');
|
||||
$row->attributes['class'] .= ' additional';
|
||||
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge mr-1 bg-info text-white');
|
||||
}
|
||||
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$row->attributes['class'] .= ' missing';
|
||||
$msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge bg-danger text-white');
|
||||
} else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
|
||||
$row->attributes['class'] .= ' newplugin';
|
||||
$msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge bg-success text-white');
|
||||
} else {
|
||||
$msg = '';
|
||||
@ -1910,6 +1901,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$updateinfo = '';
|
||||
if (is_array($plugin->available_updates())) {
|
||||
$row->attributes['class'] .= ' updatable';
|
||||
foreach ($plugin->available_updates() as $availableupdate) {
|
||||
$updateinfo .= $this->plugin_available_update_info($pluginman, $availableupdate);
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ $string['err_response_format_version'] = 'Unexpected version of the response for
|
||||
$string['err_response_http_code'] = 'Unable to fetch available updates data - unexpected HTTP response code.';
|
||||
$string['filterall'] = 'Show all';
|
||||
$string['filtercontribonly'] = 'Show additional plugins only';
|
||||
$string['filtermissingonly'] = 'Show missing from disk only';
|
||||
$string['filternewpluginsonly'] = 'Show only plugins to be installed';
|
||||
$string['filterupdatesonly'] = 'Show updateable only';
|
||||
$string['incompatibleversion'] = 'Incompatible Moodle version: {$a}';
|
||||
$string['isenabled'] = 'Enabled?';
|
||||
|
@ -438,6 +438,13 @@
|
||||
.info {
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
|
||||
[data-filterby].active {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.updateavailableinstallall {
|
||||
margin-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26876,6 +26876,12 @@ img.icon {
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
}
|
||||
#page-admin-plugins #plugins-overview-panel .info [data-filterby].active {
|
||||
font-weight: bold;
|
||||
}
|
||||
#page-admin-plugins #plugins-overview-panel .updateavailableinstallall {
|
||||
margin-right: 1em;
|
||||
}
|
||||
#page-admin-plugins .checkforupdates {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
@ -26876,6 +26876,12 @@ img.icon {
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
}
|
||||
#page-admin-plugins #plugins-overview-panel .info [data-filterby].active {
|
||||
font-weight: bold;
|
||||
}
|
||||
#page-admin-plugins #plugins-overview-panel .updateavailableinstallall {
|
||||
margin-right: 1em;
|
||||
}
|
||||
#page-admin-plugins .checkforupdates {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user