Merge pull request #5945 from BOINC/dpa_sandbox3

web: make sandbox file list sortable by name, size, or date
This commit is contained in:
Vitalii Koshura 2024-12-10 23:27:29 +01:00 committed by GitHub
commit 5eb9fa9829
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 111 additions and 35 deletions

View File

@ -22,18 +22,19 @@
// - each user (job submitter) has a 'sandbox' where they can store files
// on the BOINC server, via a web interface.
// These files are mutable; you can modify a file w/ a given name.
// - files are stored in a dir project/sandbox/<userid>
// - files are stored in project/sandbox/<userid>/
// - When a file is uploaded, its size and MD5 are computed and stored
// in an 'info file' in a parallel dir, project/sandbox/<userid>/.md5
// in an 'info file' in a parallel dir, project/sandbox/<userid>/.md5/
//
// Sandbox files can be used for web-based job submissions systems
// like BUDA and autodock on BOINC Central.
// Typically they are used as job input files or app files,
// in which case they are downloadable.
// in which case they are downloadable by BOINC clients.
// When a file is used in this way,
// it must be copied to the download hierarchy,
// and assigned a physical name that includes its MD5.
// The name depends on the role of the file.
// The name can depend on the role of the file;
// e.g. it can include a batch ID or BUDA app name
require_once("../inc/util.inc");
require_once("../inc/dir_hier.inc");
@ -118,8 +119,9 @@ function sandbox_file_select(
return $x;
}
// copy file and info file from sandbox to $dir
// Copy file and info file from sandbox to $dir
// (which must have a subdir .md5/)
// Used for BUDA app files.
//
function copy_sandbox_file($user, $fname, $dir) {
$sbdir = sandbox_dir($user);
@ -127,4 +129,46 @@ function copy_sandbox_file($user, $fname, $dir) {
copy("$sbdir/.md5/$fname", "$dir/.md5/$fname");
}
//////////// tables with sortable columns ////////////////
// maybe this should go in util.inc
$g_field = null;
function field_compare($a, $b) {
global $g_field;
if ($a->$g_field == $b->$g_field) return 0;
return $a->$g_field > $b->$g_field;
}
function column_sort(&$items, $field, $rev) {
global $g_field;
$g_field = $field;
usort($items, 'field_compare');
if ($rev) {
$items = array_reverse($items);
}
}
// column header for a given field.
// If it's the sort field, show up or down arrow to change order
// Otherwise name is a link to make it the sort field
//
function column_sort_header($field, $title, $url, $sort_field, $sort_rev) {
if ($field == $sort_field) {
return sprintf(
'%s <a href="%s&sort_field=%s&sort_rev=%d">%s</a>',
$title,
$url, $sort_field,
$sort_rev?0:1,
$sort_rev?'&uarr;':'&darr;'
);
} else {
return sprintf(
'<a href="%s&sort_field=%s">%s</a>',
$url, $field, $title
);
}
}
?>

View File

@ -913,8 +913,8 @@ function current_url() {
return $url;
}
// style for a button
// the colors for bootstrap' btn-success are almost illegible;
// return style for a button
// the colors for bootstrap's btn-success are almost illegible;
// the green is too light. Use a darker green.
//
function button_style($color='green', $font_size=null) {
@ -951,6 +951,10 @@ function button_text($url, $text, $desc=null, $class=null, $extra='') {
);
}
function button_text_small($url, $text, $desc=null) {
return button_text($url, $text, $desc, "btn btn-xs", button_style());
}
function show_button($url, $text, $desc=null, $class=null, $extra=null) {
echo button_text($url, $text, $desc, $class, $extra);
}
@ -958,7 +962,7 @@ function show_button($url, $text, $desc=null, $class=null, $extra=null) {
// for places with a bunch of buttons, like forum posts
//
function show_button_small($url, $text, $desc=null) {
echo button_text($url, $text, $desc, "btn btn-xs", button_style());
echo button_text_small($url, $text, $desc);
}
// used for showing icons

View File

@ -318,7 +318,7 @@ function view_file() {
$app = get_str('app');
if (!is_valid_filename($app)) die('bad arg');
$variant = get_str('variant');
if (!is_valid_filename($arg)) die('bad arg');
if (!is_valid_filename($variant)) die('bad arg');
$fname = get_str('fname');
if (!is_valid_filename($fname)) die('bad arg');
echo "<pre>\n";

View File

@ -92,36 +92,67 @@ function list_files($user) {
if ($notice) {
echo "<p>$notice<hr>";
}
echo "
<p>
Your 'File sandbox' is where you store files to this BOINC server.
";
$files = array();
echo "<p>Click a column title to sort on that attribute.<p>\n";
$fnames = array();
foreach (scandir($dir) as $f) {
if ($f[0] == '.') continue;
$files[] = $f;
$fnames[] = $f;
}
if (count($files) == 0) {
if (count($fnames) == 0) {
echo "Your sandbox is currently empty.";
} else {
sort($files);
$files = [];
foreach ($fnames as $fname) {
[$md5, $size] = sandbox_parse_info_file($user, $fname);
$f = new StdClass;
$f->name = $fname;
$f->size = $size;
$f->md5 = $md5;
$f->date = filemtime("$dir/$fname");
$files[] = $f;
}
$sort_field = get_str('sort_field', true);
if (!$sort_field) $sort_field = 'name';
$sort_rev = get_str('sort_rev', true);
column_sort($files, $sort_field, $sort_rev);
start_table();
table_header("Name<br><small>(click to view text files)</small>", "Modified", "Size (bytes)", "MD5", "Delete","Download");
table_header(
column_sort_header(
'name',
'Name',
'sandbox.php?',
$sort_field, $sort_rev
).'<br><small>(click to view text files)</small>',
column_sort_header(
'date',
'Modified',
'sandbox.php?',
$sort_field, $sort_rev
),
column_sort_header(
'size',
"Size (bytes)",
'sandbox.php?',
$sort_field, $sort_rev
),
"MD5",
"Delete",
"Download"
);
foreach ($files as $f) {
[$md5, $size] = sandbox_parse_info_file($user, $f);
$path = "$dir/$f";
$ct = time_str(filemtime($path));
$ct = time_str($f->date);
table_row(
"<a href=sandbox.php?action=view_file&name=$f>$f</a>",
"<a href=sandbox.php?action=view_file&name=$f->name>$f->name</a>",
$ct,
$size,
$md5,
button_text(
"sandbox.php?action=delete_file&name=$f",
$f->size,
$f->md5,
button_text_small(
"sandbox.php?action=delete_file&name=$f->name",
"Delete"
),
button_text(
"sandbox.php?action=download_file&name=$f",
button_text_small(
"sandbox.php?action=download_file&name=$f->name",
"Download"
)
);

View File

@ -590,10 +590,10 @@ function handle_query_job($user) {
<li><a href=submit.php?action=query_batch&batch_id=$wu->batch>Batch details</a>
";
echo "<h2>Instances</h2>\n";
echo "<h2>Job instances</h2>\n";
start_table('table-striped');
table_header(
"ID<br><small>click for result page</small>",
"ID<br><small>click for details and stderr</small>",
"State",
"Output files"
);
@ -651,9 +651,7 @@ function handle_query_job($user) {
$x = "<in>".$wu->xml_doc."</in>";
$x = simplexml_load_string($x);
start_table('table-striped');
table_header("Name<br><small>(click to view)</small>",
"Size (bytes)", "MD5"
);
table_header("Name<br><small>(click to view)</small>", "Size (bytes)");
foreach ($x->workunit->file_ref as $fr) {
$pname = (string)$fr->file_name;
$lname = (string)$fr->open_name;
@ -661,8 +659,7 @@ function handle_query_job($user) {
if ((string)$fi->name == $pname) {
table_row(
"<a href=$fi->url>$lname</a>",
$fi->nbytes,
$fi->md5_cksum
$fi->nbytes
);
break;
}