Commit 3d4f57fd authored by Leigh Stoller's avatar Leigh Stoller

Update the admin profile listings page to a search page, too many

profiles to list them in a big table.
parent 8b66840c
$(function ()
{
'use strict';
var template_list = ["list-profiles", "profile-list",
"oops-modal", "waitwait-modal"];
var templates = APT_OPTIONS.fetchTemplateList(template_list);
var listTemplate = _.template(templates["profile-list"]);
function initialize()
{
window.APT_OPTIONS.initialize(sup);
$('#main-body').html(templates["list-profiles"]);
$('#oops_div').html(templates["oops-modal"]);
$('#waitwait_div').html(templates["waitwait-modal"]);
// Start out as empty table.
$('#search-profiles-table')
.tablesorter({
theme : 'green',
// initialize zebra
widgets: ["zebra"],
});
// Search box key change handler.
var search_profiles_timeout = null;
$("#profile-search-box").on("keyup", function (event) {
var userInput = $("#profile-search-box").val();
userInput = userInput.toLowerCase();
window.clearTimeout(search_profiles_timeout);
search_profiles_timeout =
window.setTimeout(function() {
if (userInput.length < 3) {
return;
}
UpdateProfileSearch(userInput);
}, 500);
});
$("#profile-search-box").focus();
}
function UpdateProfileSearch(text)
{
console.info("UpdateProfileSearch: " + text);
var callback = function(json) {
console.info(json);
if (json.code) {
console.info(json.value);
return;
}
var html = "";
for (var i in json.value) {
var profile = json.value[i];
html = html +
"<tr>" +
"<td>" + profile.profile_link + "</td>" +
"<td>" + profile.creator_link + "</td>" +
"<td>" + profile.project_link + "</td>" +
"<td>" + profile.desc + "</td>" +
"<td class='format-date' style='white-space: nowrap;'>" +
profile.created + "</td>" +
"<td>" + profile.listed + "</td>" +
"<td>" + profile.privacy + "</td>" +
"</tr>\n";
}
$('#search-profiles-table tbody').html(html);
// Format dates with moment before table update
$('.format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
$('#search-profiles-table').trigger("update", [false]);
$('.match-count').text(json.value.length);
};
var xmlthing = sup.CallServerMethod(null, "manage_profile",
"SearchProfiles",
{"text" : text});
xmlthing.done(callback);
}
$(document).ready(initialize);
});
$(function ()
{
'use strict';
var ajaxurl = null;
function initialize()
{
window.APT_OPTIONS.initialize(sup);
ajaxurl = window.AJAXURL;
// Format dates with moment before display.
$('.format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
var table = $(".tablesorter")
.tablesorter({
theme : 'green',
//cssChildRow: "tablesorter-childRow",
// initialize zebra and filter widgets
widgets: ["zebra", "filter", "resizable"],
widgetOptions: {
// include child row content while filtering, if true
filter_childRows : true,
// include all columns in the search.
filter_anyMatch : true,
// class name applied to filter row and each input
filter_cssFilter : 'form-control',
// search from beginning
filter_startsWith : false,
// Set this option to false for case sensitive search
filter_ignoreCase : true,
// Only one search box.
filter_columnFilters : false,
// Search as typing
filter_liveSearch : true,
},
headers: { 1: { sorter: false} }
});
// Target the $('.search') input using built in functioning
// this binds to the search using "search" and "keyup"
// Allows using filter_liveSearch or delayed search &
// pressing escape to cancel the search
$.tablesorter.filter.bindSearch( table, $('#profile_search') );
$('.showtopo_modal_button').click(function (event) {
event.preventDefault();
ShowTopology($(this).data("profile"));
});
}
function ShowTopology(profile)
{
var profile;
var index;
var callback = function(json) {
if (json.code) {
alert("Failed to get rspec for topology viewer: " + json.value);
return;
}
sup.ShowModal("#quickvm_topomodal");
$("#quickvm_topomodal").one("shown.bs.modal", function () {
sup.maketopmap('#showtopo_nopicker',
json.value.rspec, false, !window.ISADMIN);
});
};
var $xmlthing = sup.CallServerMethod(ajaxurl,
"myprofiles",
"GetProfile",
{"uuid" : profile});
$xmlthing.done(callback);
}
$(document).ready(initialize);
});
......@@ -147,7 +147,7 @@ $(function ()
});
};
var $xmlthing = sup.CallServerMethod(null,
"myprofiles",
"manage_profile",
"GetProfile",
{"uuid" : profile});
$xmlthing.done(callback);
......
......@@ -300,7 +300,7 @@ $(function ()
});
};
var $xmlthing = sup.CallServerMethod(null,
"myprofiles",
"manage_profile",
"GetProfile",
{"uuid" : profile});
$xmlthing.done(callback);
......
......@@ -407,7 +407,7 @@ $(function ()
});
};
var $xmlthing = sup.CallServerMethod(null,
"myprofiles",
"manage_profile",
"GetProfile",
{"uuid" : profile});
$xmlthing.done(callback);
......
<?php
#
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
# Copyright (c) 2000-2018 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -22,39 +22,46 @@
# }}}
#
chdir("..");
include_once("webtask.php");
include("defs.php3");
chdir("apt");
include_once("profile_defs.php");
include("quickvm_sup.php");
$page_title = "List Profiles";
#
# Return info about specific profile.
# Get current user.
#
function Do_GetProfile()
{
global $this_user;
global $ajax_args;
$this_idx = $this_user->uid_idx();
if (!isset($ajax_args["uuid"])) {
SPITAJAX_ERROR(1, "Missing profile uuid");
return;
}
$profile = Profile::Lookup($ajax_args["uuid"]);
if (!$profile) {
SPITAJAX_ERROR(1, "Unknown profile uuid");
return;
}
if (!ISADMIN() &&
!ISFOREIGN_ADMIN() &&
!$profile->CanView($this_user)) {
SPITAJAX_ERROR(1, "Not enough permission");
return;
}
SPITAJAX_RESPONSE(array('rspec' => $profile->rspec(),
'name' => $profile->name()));
RedirectSecure();
$this_user = CheckLoginOrRedirect();
if (! (ISADMIN() || ISFOREIGN_ADMIN())) {
SPITUSERERROR("You do not have permission to view this page");
exit();
}
# Local Variables:
# mode:php
# End:
SPITHEADER(1);
echo "<link rel='stylesheet'
href='css/tablesorter.css'>\n";
# Place to hang the toplevel template.
echo "<div id='main-body'></div>\n";
echo "<script type='text/javascript'>\n";
$isadmin = (ISADMIN() ? 1 : 0);
$isfadmin = (ISFOREIGN_ADMIN() ? 1 : 0);
echo " window.ISADMIN = $isadmin;\n";
echo " window.ISFOREIGN_ADMIN = $isfadmin;\n";
echo "</script>\n";
echo "<script src='js/lib/jquery-2.0.3.min.js'></script>\n";
echo "<script src='js/lib/jquery.tablesorter.min.js'></script>\n";
echo "<script src='js/lib/jquery.tablesorter.widgets.min.js'></script>\n";
REQUIRE_UNDERSCORE();
REQUIRE_SUP();
REQUIRE_MOMENT();
AddTemplateList(array("list-profiles",
"profile-list", "oops-modal", "waitwait-modal"));
SPITREQUIRE("js/list-profiles.js");
SPITFOOTER();
?>
<?php
#
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
# Copyright (c) 2000-2018 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -1658,6 +1658,127 @@ function Do_GetRepoHash()
SPITAJAX_RESPONSE($profile->repohash());
}
#
# Return info about a profile.
#
function Do_GetProfile()
{
global $this_user;
global $ajax_args;
$this_idx = $this_user->uid_idx();
if (!isset($ajax_args["uuid"])) {
SPITAJAX_ERROR(1, "Missing profile uuid");
return;
}
$profile = Profile::Lookup($ajax_args["uuid"]);
if (!$profile) {
SPITAJAX_ERROR(1, "Unknown profile uuid");
return;
}
if (!ISADMIN() &&
!ISFOREIGN_ADMIN() &&
!$profile->CanView($this_user)) {
SPITAJAX_ERROR(1, "Not enough permission");
return;
}
SPITAJAX_RESPONSE(array('rspec' => $profile->rspec(),
'name' => $profile->name()));
}
#
# Admin search function.
#
function Do_SearchProfiles()
{
global $this_user;
global $ajax_args;
if (!ISADMIN()) {
SPITAJAX_ERROR(-1, "Not enough permission");
return;
}
$results = array();
if (!isset($ajax_args["text"])) {
SPITAJAX_ERROR(-1, "Missing text to search for");
return -1;
}
$text = $ajax_args["text"];
if (!preg_match("/^[\w\s]*$/", $text)) {
SPITAJAX_ERROR(-1, "Illegal text to search for");
return -1;
}
$safe_text = addslashes("%${text}%");
$query_result
= DBQueryFatal("select p.*,v.*,DATE(v.created) as created ".
" from apt_profiles as p ".
"left join apt_profile_versions as v on ".
" v.profileid=p.profileid and ".
" v.version=p.version ".
"where (v.creator like '$safe_text' or ".
" p.pid like '$safe_text' or ".
" v.rspec like ".
" '%<description%>$safe_text</description>%' or ".
" p.name like '$safe_text') ".
"order by v.creator");
while ($row = mysql_fetch_array($query_result)) {
$blob = array();
$blob["profileid"] = $row["profileid"];
$blob["uuid"] = $row["uuid"];
$blob["version"] = $row["version"];
$blob["name"] = $row["name"];
$blob["pid"] = $row["pid"];
$blob["desc"] = CleanString($row["description"]);
$blob["created"] = DateStringGMT($row["created"]);
$blob["public"] = $row["public"];
$blob["listed"] = $row["listed"] ? "Yes" : "No";
$blob["shared"] = $row["shared"];
$blob["creator"] = $row["creator"];
if ($public)
$privacy = "Public";
elseif ($shared)
$privacy = "Site";
else
$privacy = "Project";
$blob["privacy"] = $privacy;
$parsed_xml = simplexml_load_string($row["rspec"]);
if ($parsed_xml &&
$parsed_xml->rspec_tour && $parsed_xml->rspec_tour->description) {
$desc = $parsed_xml->rspec_tour->description;
$blob["desc"] = CleanString($desc);
}
#
# Convenience.
#
$uuid = $row["uuid"];
$name = $row["name"];
$pid = $row["pid"];
$pid_idx = $row["pid_idx"];
$creator = $row["creator"];
$blob["profile_link"]
= "<a href='manage_profile.php?action=edit&uuid=$uuid' ".
"target='_blank'>$name</a>";
$blob["creator_link"]
= "<a href='user-dashboard.php?user=$creator' ".
"target='_blank'>$creator</a>";
$blob["project_link"]
= "<a href='show-project.php?pid=$pid_idx' ".
"target='_blank'>$pid</a>";
$results[] = $blob;
}
SPITAJAX_RESPONSE($results);
}
# Local Variables:
# mode:php
# End:
......
<?php
#
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir("..");
include("defs.php3");
chdir("apt");
include("quickvm_sup.php");
$page_title = "My Profiles";
#
# Verify page arguments.
#
$optargs = OptionalPageArguments("target_user", PAGEARG_USER,
"all", PAGEARG_BOOLEAN);
#
# Get current user.
#
RedirectSecure();
$this_user = CheckLoginOrRedirect();
if (!isset($target_user)) {
$target_user = $this_user;
}
if (!$this_user->SameUser($target_user)) {
if (!ISADMIN()) {
SPITUSERERROR("You do not have permission to view ".
"target user's profiles");
exit();
}
}
$target_idx = $target_user->uid_idx();
SPITHEADER(1);
echo "<link rel='stylesheet'
href='css/tablesorter.css'>\n";
$whereclause = "where v.creator_idx='$target_idx'";
$joinclause = "";
$orderclause = "";
if (isset($all)) {
if (ISADMIN() || ISFOREIGN_ADMIN()) {
$whereclause = "";
}
else {
$joinclause =
"left join group_membership as g on ".
" g.uid_idx='$target_idx' and ".
" g.pid_idx=v.pid_idx and g.pid_idx=g.gid_idx";
$whereclause =
"where p.public=1 or p.shared=1 or v.creator_idx='$target_idx' or ".
" g.uid_idx is not null ";
}
}
$query_result =
DBQueryFatal("select p.*,v.*,DATE(v.created) as created ".
" from apt_profiles as p ".
"left join apt_profile_versions as v on ".
" v.profileid=p.profileid and ".
" v.version=p.version ".
"$joinclause ".
"$whereclause order by v.creator");
if (mysql_num_rows($query_result) == 0) {
$message = "<b>No profiles to show you. Maybe you want to ".
"<a href='manage_profile.php'>create one?</a></b><br><br>";
if (ISADMIN() || ISFOREIGN_ADMIN()) {
$message .= "<img src='images/redball.gif'>".
"<a href='myprofiles.php?all=1'>Show all user Profile</a>";
}
else {
$message .= "<img src='images/blueball.gif'>".
"<a href='myprofiles.php?all=1'>".
"Show all profiles you can instantiate</a>\n";
}
SPITUSERERROR($message);
exit();
}
echo "<div class='row'>
<div class='col-lg-12 col-lg-offset-0
col-md-12 col-md-offset-0
col-sm-12 col-sm-offset-0
col-xs-12 col-xs-offset-0'>\n";
echo "<input class='form-control search' type='search' data-column='all'
id='profile_search' placeholder='Search'>\n";
echo " <table class='tablesorter'>
<thead>
<tr>
<th>Name</th>
<th>&nbsp</th>\n";
if (isset($all) && ISADMIN()) {
echo " <th>Creator</th>";
}
echo " <th>Project</th>
<th>Description</th>
<th>Created</th>
<th>Listed</th>
<th>Privacy</th>
</tr>
</thead>
<tbody>\n";
while ($row = mysql_fetch_array($query_result)) {
$idx = $row["profileid"];
$uuid = $row["uuid"];
$version = $row["version"];
$name = $row["name"];
$pid = $row["pid"];
$desc = $row["description"];
$created = DateStringGMT($row["created"]);
$public = $row["public"];
$listed = ($row["listed"] ? "Yes" : "No");
$shared = $row["shared"];
$creator = $row["creator"];
$rspec = $row["rspec"];
if ($public)
$privacy = "Public";
elseif ($shared)
$privacy = "Site";
else
$privacy = "Project";
$parsed_xml = simplexml_load_string($rspec);
if ($parsed_xml &&
$parsed_xml->rspec_tour && $parsed_xml->rspec_tour->description) {
$desc = $parsed_xml->rspec_tour->description;
}
echo " <tr>";
if ($creator == $this_user->uid() || ISADMIN()) {
echo " <td style='text-align:center'>
<a href='manage_profile.php?action=edit&uuid=$uuid'>$name</a>
</td>\n";
}
else {
echo " <td style='text-align:center'>
<a href='show-profile.php?uuid=$uuid'>$name</a>
</td>\n";
}
echo "<td style='text-align:center'>
<button class='btn btn-primary btn-xs showtopo_modal_button'
data-profile=$uuid>Topo</button>
</td>\n";
if (isset($all) && ISADMIN()) {
echo "<td>$creator</td>";
}
echo " <td style='white-space:nowrap'>$pid</td>
<td>$desc</td>
<td class='format-date'>$created</td>
<td>$listed</td>
<td>$privacy</td>
</tr>\n";
}
echo " </tbody>
</table>\n";
if (!isset($all)) {
if (ISADMIN() || ISFOREIGN_ADMIN()) {
echo "<img src='images/redball.gif'>
<a href='myprofiles.php?all=1'>Show all user profiles</a>\n";
}
else {
echo "<img src='images/blueball.gif'>
<a href='myprofiles.php?all=1'>Show all profiles you can instantiate</a>\n";
}
}
echo" </div>
</div>\n";
echo "<!-- This is the topology view modal -->
<div id='quickvm_topomodal' class='modal fade'>
<div class='modal-dialog' id='showtopo_dialog'>
<div class='modal-content'>
<div class='modal-header'>
<button type='button' class='close' data-dismiss='modal'
aria-hidden='true'>
&times;</button>
<h3>Topology Viewer</h3>
</div>
<div class='modal-body'>
<!-- This topo diagram goes inside this div -->
<div class='panel panel-default'
id='showtopo_container'>
<div class='panel-body'>
<div id='showtopo_nopicker' class='jacks'></div>
</div>
</div>
</div>
</div>
</div>
</div>\n";
echo "<script type='text/javascript'>\n";
echo " window.AJAXURL = 'server-ajax.php';\n";
$isadmin = (isset($this_user) && ISADMIN() ? 1 : 0);
echo " window.ISADMIN = $isadmin;\n";
echo "</script>\n";
echo "<script src='js/lib/jquery-2.0.3.min.js'></script>\n";
echo "<script src='js/lib/jquery.tablesorter.min.js'></script>\n";
echo "<script src='js/lib/jquery.tablesorter.widgets.min.js'></script>\n";
REQUIRE_SUP();
REQUIRE_MOMENT();
SPITREQUIRE("js/myprofiles.js");
SPITFOOTER();
?>
<div>
<center><h4>Search for profiles</h4></center>
<div class="table-responsive">
<input class='form-control search' type='search'
id='profile-search-box' placeholder='Search'>
<div class="text-center">
<small>
There are <span class="match-count">0</span> matching profiles.
</small>
</div>
<table class='tablesorter'
id='search-profiles-table'>
<thead>
<tr>
<th>Name</th>
<th>Creator</th>
<th>Project</th>
<th>Description</th>
<th>Created</th>
<th>Listed</th>
<th>Privacy</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div>
<div id='oops_div'></div>
<div id='waitwait_div'></div>
</div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment