|
429 | 429 | dust.render('snapshot-info', resp.beans[0], function(err, out) { |
430 | 430 | $('#tab-snapshot').html(out); |
431 | 431 | $('#ui-tabs a[href="#tab-snapshot"]').tab('show'); |
| 432 | + |
| 433 | + // Build a map to store snapshottable directory -> snapshots |
| 434 | + var snapshots = 'Snapshots' in resp.beans[0] ? resp.beans[0].Snapshots : []; |
| 435 | + var snapshotsMap = snapshots.reduce(function(result, snapshot) { |
| 436 | + var rootPath = snapshot.snapshotDirectory.substr(0, snapshot.snapshotDirectory.indexOf(".snapshot") -1 ); |
| 437 | + if (rootPath in result) { |
| 438 | + var arr = result[rootPath]; |
| 439 | + arr.push(snapshot); |
| 440 | + result[rootPath] = arr; |
| 441 | + } else { |
| 442 | + result[rootPath] = [snapshot]; |
| 443 | + } |
| 444 | + return result; |
| 445 | + }, {}); |
| 446 | + |
| 447 | + var table = $('#table-snapshots').DataTable( { |
| 448 | + 'lengthMenu': [ [25, 50, 100, -1], [25, 50, 100, "All"] ], |
| 449 | + 'columns': [ |
| 450 | + { 'orderable': false, 'searchable': false, 'data': null, 'defaultContent': "" }, |
| 451 | + { 'data': 'path', 'orderDataType': 'ng-value', 'searchable': true , 'type': 'string', 'defaultContent': "" }, |
| 452 | + { 'data': 'snapshotNumber', 'orderDataType': 'ng-value', 'searchable': false , 'type': 'num', 'defaultContent': 0 }, |
| 453 | + { 'data': 'snapshotQuota', 'orderDataType': 'ng-value', 'searchable': false , 'type': 'num', 'defaultContent': 0 }, |
| 454 | + { 'data': 'modificationTime', 'orderDataType': 'ng-value', 'searchable': false , 'type': 'string', 'defaultContent': "" }, |
| 455 | + { 'data': 'permission', 'orderable': false, 'searchable': false , 'type': 'string', 'defaultContent': "" }, |
| 456 | + { 'data': 'owner', 'orderDataType': 'ng-value', 'searchable': true , 'type': 'string', 'defaultContent': "" }, |
| 457 | + { 'data': 'group', 'orderDataType': 'ng-value', 'searchable': true , 'type': 'string', 'defaultContent': "" } |
| 458 | + ], |
| 459 | + 'order': [[ 1, 'asc' ]] |
| 460 | + }); |
| 461 | + // Add event listener for opening and closing details |
| 462 | + $('#table-snapshots tbody').on('click', 'td.details-control', function () { |
| 463 | + var tr = $(this).closest('tr'); |
| 464 | + var row = table.row( tr ); |
| 465 | + |
| 466 | + if ( row.child.isShown() ) { |
| 467 | + // This row is already open - close it |
| 468 | + row.child.hide(); |
| 469 | + tr.removeClass('shown'); |
| 470 | + } |
| 471 | + else { |
| 472 | + // Open this row |
| 473 | + row.child( formatExpandedRow(row.data(), snapshotsMap) ).show(); |
| 474 | + var tableId = getSubTableId(row.data()); |
| 475 | + if (!$.fn.dataTable.isDataTable('#'+tableId)) { |
| 476 | + $('#' + tableId).DataTable({ |
| 477 | + 'lengthMenu': [[25, 50, 100, -1], [25, 50, 100, "All"]], |
| 478 | + 'columns': [ |
| 479 | + { |
| 480 | + 'orderDataType': 'ng-value', |
| 481 | + 'searchable': true, |
| 482 | + 'type': 'num', |
| 483 | + 'defaultContent': 0 |
| 484 | + }, |
| 485 | + { |
| 486 | + 'orderDataType': 'ng-value', |
| 487 | + 'searchable': true, |
| 488 | + 'type': 'string', |
| 489 | + 'defaultContent': "" |
| 490 | + }, |
| 491 | + { |
| 492 | + 'orderDataType': 'ng-value', |
| 493 | + 'searchable': true, |
| 494 | + 'type': 'string', |
| 495 | + 'defaultContent': "" |
| 496 | + }, |
| 497 | + { |
| 498 | + 'orderDataType': 'ng-value', |
| 499 | + 'searchable': true, |
| 500 | + 'type': 'string', |
| 501 | + 'defaultContent': "" |
| 502 | + } |
| 503 | + ], |
| 504 | + 'order': [[0, 'asc']] |
| 505 | + }); |
| 506 | + } |
| 507 | + tr.addClass('shown'); |
| 508 | + } |
| 509 | + }); |
432 | 510 | }); |
433 | 511 | })).fail(ajax_error_handler); |
434 | 512 | } |
435 | 513 |
|
| 514 | + function getSubTableId(row) { |
| 515 | + var path = row.path; |
| 516 | + // replace all "/" with "-" |
| 517 | + path = path.replace(/\//g, '-'); |
| 518 | + return "table-snapshots"+path; |
| 519 | + } |
| 520 | + |
| 521 | + function formatExpandedRow (row, snapshotsMap) { |
| 522 | + // `row` is the original data object for the row |
| 523 | + var tableId = getSubTableId(row); |
| 524 | + var path = row.path; |
| 525 | + var snapshots = snapshotsMap[path]; |
| 526 | + if (!snapshots || snapshots.length === 0) { |
| 527 | + return 'No snapshots found for this path'; |
| 528 | + } |
| 529 | + var tbody = snapshots.reduce(function(result, snapshot) { |
| 530 | + var html = '<tr>'+ |
| 531 | + '<td ng-value="'+snapshot.snapshotID+'">'+ snapshot.snapshotID +'</td>'+ |
| 532 | + '<td ng-value="'+snapshot.snapshotDirectory+'">'+ snapshot.snapshotDirectory +'</td>'+ |
| 533 | + '<td ng-value="'+snapshot.modificationTime+'">'+ moment(Number(snapshot.modificationTime)).format('ddd MMM DD HH:mm:ss ZZ YYYY') +'</td>'+ |
| 534 | + '<td ng-value="'+snapshot.status+'">'+ snapshot.status +'</td>'+ |
| 535 | + '</tr>'; |
| 536 | + return result + html; |
| 537 | + }, ""); |
| 538 | + return '<table class="table sub-table" id='+ tableId +'>'+ |
| 539 | + '<thead>'+ |
| 540 | + '<tr>'+ |
| 541 | + '<th>Snapshot ID</th>'+ |
| 542 | + '<th>Snapshot Directory</th>'+ |
| 543 | + '<th>Modification Time</th>' + |
| 544 | + '<th>Status</th>' + |
| 545 | + '</tr>'+ |
| 546 | + '</thead>'+ |
| 547 | + '<tbody>'+ |
| 548 | + tbody + |
| 549 | + '</tbody>'+ |
| 550 | + '</table>'; |
| 551 | + } |
| 552 | + |
436 | 553 | function load_page() { |
437 | 554 | var hash = window.location.hash; |
438 | 555 | switch(hash) { |
|
0 commit comments