diff --git a/js/server_plugins.js b/js/server_plugins.js
new file mode 100644
index 0000000000..dde5990fa7
--- /dev/null
+++ b/js/server_plugins.js
@@ -0,0 +1,17 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Functions used in server plugins pages
+ */
+AJAX.registerOnload('server_plugins.js', function () {
+ // Make columns sortable, but only for tables with more than 1 data row
+ var $tables = $('#plugins_plugins table:has(tbody tr + tr)');
+ $tables.tablesorter({
+ sortList: [[0, 0]],
+ headers: {
+ 1: {sorter: false}
+ },
+ widgets: ['zebra']
+ });
+ $tables.find('thead th')
+ .append('
');
+});
diff --git a/libraries/Menu.class.php b/libraries/Menu.class.php
index 4ffd037fcc..8d4504c7ce 100644
--- a/libraries/Menu.class.php
+++ b/libraries/Menu.class.php
@@ -606,6 +606,10 @@ class PMA_Menu
$tabs['engine']['link'] = 'server_engines.php';
$tabs['engine']['text'] = __('Engines');
+ $tabs['plugins']['icon'] = 'b_routines.png';
+ $tabs['plugins']['link'] = 'server_plugins.php';
+ $tabs['plugins']['text'] = __('Plugins');
+
return $tabs;
}
diff --git a/libraries/server_plugins.lib.php b/libraries/server_plugins.lib.php
new file mode 100644
index 0000000000..8f628c151e
--- /dev/null
+++ b/libraries/server_plugins.lib.php
@@ -0,0 +1,124 @@
+query($sql);
+ $plugins = array();
+ while ($row = $GLOBALS['dbi']->fetchAssoc($res)) {
+ $plugins[$row['plugin_type']][] = $row;
+ }
+ $GLOBALS['dbi']->freeResult($res);
+ ksort($plugins);
+ return $plugins;
+}
+
+/**
+ * Returns the html for plugin Tab.
+ *
+ * @param Array $plugins list
+ *
+ * @return string
+ */
+function PMA_getPluginTab($plugins)
+{
+ $html = '
';
+ $html .= '
';
+
+ foreach ($plugins as $plugin_type => $plugin_list) {
+ $key = 'plugins-'
+ . preg_replace('/[^a-z]/', '', /*overload*/mb_strtolower($plugin_type));
+ $html .= '
'
+ . htmlspecialchars($plugin_type) . '' . "\n";
+ }
+
+ $html .= '
';
+ $html .= '
';
+
+ foreach ($plugins as $plugin_type => $plugin_list) {
+ $key = 'plugins-'
+ . preg_replace('/[^a-z]/', '', /*overload*/mb_strtolower($plugin_type));
+ sort($plugin_list);
+
+ $html .= '
';
+ $html .= '';
+ $html .= '';
+ $html .= '';
+ $html .= '| ' . __('Plugin') . ' | ';
+ $html .= '' . __('Description') . ' | ';
+ $html .= '' . __('Version') . ' | ';
+ $html .= '' . __('Author') . ' | ';
+ $html .= '' . __('License') . ' | ';
+ $html .= '
';
+ $html .= '';
+ $html .= '';
+
+ $html .= PMA_getPluginList($plugin_list);
+
+ $html .= '';
+ $html .= '
';
+ }
+ $html .= '
';
+ return $html;
+}
+
+/**
+ * Returns the html for plugin List.
+ *
+ * @param Array $plugin_list list
+ *
+ * @return string
+ */
+function PMA_getPluginList($plugin_list)
+{
+ $html = "";
+ $odd_row = false;
+ foreach ($plugin_list as $plugin) {
+ $odd_row = !$odd_row;
+ $html .= '';
+ $html .= '| ';
+ $html .= htmlspecialchars($plugin['plugin_name']);
+ if (! $plugin['is_active']) {
+ $html .= ' ' . __('disabled') . '';
+ }
+ $html .= ' | ';
+ $html .= '' . htmlspecialchars($plugin['plugin_description']) . ' | ';
+ $html .= '' . htmlspecialchars($plugin['plugin_type_version']) . ' | ';
+ $html .= '' . htmlspecialchars($plugin['plugin_author']) . ' | ';
+ $html .= '' . htmlspecialchars($plugin['plugin_license']) . ' | ';
+ $html .= '
';
+ }
+ return $html;
+}
\ No newline at end of file
diff --git a/server_plugins.php b/server_plugins.php
new file mode 100644
index 0000000000..4bb3fef99d
--- /dev/null
+++ b/server_plugins.php
@@ -0,0 +1,36 @@
+getHeader();
+$scripts = $header->getScripts();
+$scripts->addFile('jquery/jquery.tablesorter.js');
+$scripts->addFile('server_plugins.js');
+
+/**
+ * Does the common work
+ */
+require 'libraries/server_common.inc.php';
+require 'libraries/server_plugins.lib.php';
+
+$plugins = PMA_getServerPlugins();
+
+/**
+ * Displays the page
+ */
+$response->addHTML(PMA_getPluginTab($plugins));
+
+exit;
diff --git a/test/libraries/PMA_server_plugins_test.php b/test/libraries/PMA_server_plugins_test.php
new file mode 100644
index 0000000000..b94f5de60a
--- /dev/null
+++ b/test/libraries/PMA_server_plugins_test.php
@@ -0,0 +1,138 @@
+getMockBuilder('PMA_DatabaseInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $GLOBALS['dbi'] = $dbi;
+
+ //Call the test function
+ /**
+ * Prepare plugin list
+ */
+
+ $plugins = array();
+
+ $row = array();
+ $row["plugin_name"] = "plugin_name1";
+ $row["plugin_type"] = "plugin_type1";
+ $row["plugin_type_version"] = "plugin_version1";
+ $row["plugin_author"] = "plugin_author1";
+ $row["plugin_license"] = "plugin_license1";
+ $row["plugin_description"] = "plugin_description1";
+ $row["is_active"] = true;
+ $plugins[$row['plugin_type']][] = $row;
+
+ $html = PMA_getPluginTab($plugins);
+
+ //validate 1:Items
+ $this->assertContains(
+ 'Plugin | ',
+ $html
+ );
+ $this->assertContains(
+ 'Description | ',
+ $html
+ );
+ $this->assertContains(
+ 'Version | ',
+ $html
+ );
+ $this->assertContains(
+ 'Author | ',
+ $html
+ );
+ $this->assertContains(
+ 'License | ',
+ $html
+ );
+
+ //validate 2: one Item HTML
+ $this->assertContains(
+ 'plugin_name1 | ',
+ $html
+ );
+ $this->assertContains(
+ 'plugin_description1 | ',
+ $html
+ );
+ $this->assertContains(
+ 'plugin_type_version1 | ',
+ $html
+ );
+ $this->assertContains(
+ 'plugin_author1 | ',
+ $html
+ );
+ $this->assertContains(
+ 'plugin_license1 | ',
+ $html
+ );
+ }
+}