| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 | <!DOCTYPE html><html><head>    <title>File Restore</title>	<meta name="mobile-web-app-capable" content="yes">	<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>	<meta charset="UTF-8">    <link rel="stylesheet" href="../../script/semantic/semantic.min.css">    <script src="../../script/jquery.min.js"></script>	<script src="../../script/semantic/semantic.min.js"></script>    <script type="text/javascript" src="../../script/ao_module.js"></script>    <style>        .hidden{            display:none;        }        .disabled{            opacity: 0.5;            pointer-events: none;        }        .colorblock{            width: 20px;            height: 20px;            display: inline-block;            vertical-align: bottom;            margin-right: 12px;        }        .blue.colorblock{            background-color: #52bdf2;        }        .grey.colorblock{            background-color: #b9b9b9;        }        .yellow.colorblock{            background-color: #e5e75c;        }        .ui.table tr td{           border-top: 0px solid transparent !important;         }                .overlap.bar{            position: absolute !important;             top:0px;             left: 0px;        }        .nointeract{            pointer-events: none;            user-select: none;         }        #restorableList{            max-height: 300px;            overflow-y: scroll;            padding-right: 4px;        }        #snapshotList{            max-height: 300px;            overflow-y: scroll;            padding-right: 4px;        }                .timeleft{            width: 30px;            height: 30px;            display: inline-block;            user-select: none;             vertical-align: baseline;            margin-bottom: -10px;            margin-right: 4px;        }        .closebtn{            position: absolute;            right: 4px;            top: 4px;        }    </style></head><body>    <br>    <div class="ui container">        <h3 class="ui header">            Backup & Restore            <div class="sub header">Show restore points for the selected virtual disk</div>        </h3>        <div class="ui divider"></div>       <div id="error" class="ui red inverted segment hidden">            <h4 class="ui header">                <i class="remove icon"></i>                <div class="content">                    List Restore Failed                    <div class="sub reason header" style="color: white;">Unknown Vroot paramter given</div>                </div>            </h4>       </div>       <div id="restoreCancel" class="ui grey inverted segment hidden">            <h4 class="ui header">                <i class="remove icon"></i>                <div class="content">                    Snapshot Restore Cancelled                    <div class="sub reason header" style="color: white;">Operation cancelled by user</div>                </div>            </h4>        </div>         <div id="succ" class="ui green segment" style="display:none;">        <h4 class="ui header">            <i class="green checkmark icon"></i>            <div class="content">                File Restored                <div class="sub reason header openfolder"><a style="cursor: pointer" onclick="handleOpenRestoreLocation()"><i class="ui folder open icon"></i> Open Location</a></div>            </div>        </h4>       </div>       <div id="fileinfo" class="ui segment" style="display:none;">        <h4 class="ui header">            <div class="content">                <span class="filename">No File Selected</span>                <div class="sub header relpath">N/A</div>            </div>        </h4>        <div class="ui divider"></div>        <h5>Restorable File Properties</h5>        <span class="backupDisk">N/A</span><br>        <span class="restorePoint">N/A</span><br>        <span class="deleteTime">N/A</span><br>        <span class="deleteRemainingTime">N/A</span><br>        <button id="snapshotSummaryBtn" class="ui mini button" style="display:none;" onclick="openSnapshotInfo();">View Snapshot Summary</button>        <button class="circular ui icon basic small button closebtn" onclick='$("#fileinfo").slideUp("fast");'>            <i class="icon remove"></i>        </button>       </div>       <div id="snapshotList" class="ui middle aligned divided list">            <div class="item">                <img class="ui mini image nointeract" src="../../img/system/drive-backup.svg">                <div class="content">                No Restorable Snapshot(s) for this virtual disk.                </div>            </div>        </div>        <div id="restorableList" class="ui middle aligned divided list">            <div class="item">                <img class="ui mini image nointeract" src="../../img/system/file-notfound.svg">                <div class="content">                No Restorable File(s) for this virtual disk.                </div>            </div>        </div>        <div class="ui checkbox">            <input type="checkbox" name="showhidden" autocomplete="false" onchange="toggleHiddenFiles(this.checked);">            <label>Show hidden / cache files</label>        </div>        <div class="ui divider" style="margin-top: 8px; margin-bottom: 8px;"></div>        <br>            <div class="ui tiny green button" onclick="restoreAll();">Restore All</div>           <button class="ui right floated button" onclick="ao_module_close();">Close</button>        <br>    </div>    <script>        var vrootID = "";        var viewingFileInfo = {};        $(".ui.checkbox").checkbox();        //Extract vroot id from the window hash        if (window.location.hash.length > 1){            vrootID = JSON.parse(decodeURIComponent(window.location.hash.substr(1)));            if (vrootID.length >= 1){                listRestorableFiles(vrootID[0]);            }else{                $("#error").removeClass("hidden");            }                    }else{            $("#error").removeClass("hidden");        }        function openSnapshotInfo(){            var snapshotInfo = {                SnapshotDisk: viewingFileInfo.BackupDiskUID,                SnapshotName: viewingFileInfo.Filename            };            var hashPassthrough = encodeURIComponent(JSON.stringify(snapshotInfo));            ao_module_newfw({                url: "SystemAO/disk/disk_snapshot.html#" + hashPassthrough,                width: 900,                height: 520,                appicon: "img/system/backup.svg",                title: "Snapshot Summary",            });        }        function showFileInfo(object){            var filedata = $(object).attr("filedata");            filedata = JSON.parse(decodeURIComponent(filedata));            console.log(filedata);            //Show information on page            if (filedata.IsSnapshot){                $("#fileinfo").find(".filename").text("Snapshot " + filedata.Filename);            }else{                $("#fileinfo").find(".filename").text(filedata.Filename + ` (${ao_module_utils.formatBytes(filedata.Filesize, 2)})`);            }                        viewingFileInfo=filedata;                        //Hide the filename in relpath            var shortenRelpath = filedata.RelpathOnDisk.split("/");            shortenRelpath.pop();            shortenRelpath = shortenRelpath.join("/") + "/";            $("#fileinfo").find(".relpath").text(shortenRelpath);            $("#fileinfo").find(".backupDisk").html('<i class="ui blue disk icon"></i> Restorable file from ' + filedata.BackupDiskUID + ":/");            $("#fileinfo").find(".deleteTime").html('<i class="ui trash icon"></i> File deleted since ' + timeConverter(filedata.DeleteTime));            $("#fileinfo").find(".restorePoint").html('<i class="ui refresh icon"></i> Restore to ' + (filedata.RestorePoint));            $("#fileinfo").find(".deleteRemainingTime").html('<i class="ui red remove icon"></i> Auto delete in '+ secondsToHms(filedata.RemainingTime));            if (filedata.IsSnapshot){                $("#fileinfo").find(".deleteRemainingTime").hide();                $("#fileinfo").find(".deleteTime").hide();                $("#snapshotSummaryBtn").show();            }else{                $("#fileinfo").find(".deleteRemainingTime").show();                $("#fileinfo").find(".deleteTime").show();                $("#snapshotSummaryBtn").hide();            }            $("#fileinfo").slideDown('fast');        }        function secondsToHms(d) {            d = Number(d);            var h = Math.floor(d / 3600);            var m = Math.floor(d % 3600 / 60);            var s = Math.floor(d % 3600 % 60);            var hDisplay = h > 0 ? h.toString().padStart(2, "0") + (h == 1 ? " hour, " : " hours, ") : "";            var mDisplay = m > 0 ? m.toString().padStart(2, "0") + (m == 1 ? " minute, " : " minutes") : "";                        if (h > 24){                var days = Math.floor(h/24);                days = days + (days == 1 ? " day, " : " days, ")                var hours = h % 24 + (h == 1 ? " hour, " : " hours, ");                return days + hours + mDisplay;             } else{                return hDisplay + mDisplay;             }        }        function timeConverter(UNIX_timestamp){            var a = new Date(UNIX_timestamp * 1000);            var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];            var year = a.getFullYear();            var month = months[a.getMonth()];            var date = a.getDate();            var hour = a.getHours().toString().padStart(2, "0");            var min = a.getMinutes().toString().padStart(2, "0");            var sec = a.getSeconds().toString().padStart(2, "0");            var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ;            return time;        }        function toggleHiddenFiles(status=undefined){            if (status == undefined){                $(".hiddenfile").slideToggle("fast");            }else if (status == true){                $(".hiddenfile").slideDown("fast");            }else if (status == false){                $(".hiddenfile").slideUp("fast");            }                    }        //Restore this file        var restoreFileInfo = undefined;        function restoreThisFile(fileObject){            var filedata = $(fileObject).attr("filedata");            filedata = JSON.parse(decodeURIComponent(filedata));            console.log(filedata);            if (filedata.IsSnapshot == true && !confirm("Confirm snapshot restore? All newly created files will be kept.")){                $("#restoreCancel").stop().finish().slideDown('fast').delay(3000).slideUp('fast');                return;            }            $.ajax({                url: "../../system/backup/restoreFile",                method: "POST",                data: {"bdid": filedata.BackupDiskUID, "relpath": filedata.RelpathOnDisk},                success: function(data){                    if (data.error !== undefined){                        alert("Restore failed: " + data.error);                    }else{                        console.log(data);                        if (filedata.IsSnapshot){                            restoreFileInfo = filedata;                        }else{                            restoreFileInfo = data;                        }                                               if (restoreFileInfo.RestoredVirtualPath == ""){                            $("#openfolder").hide();                        }else{                            $("#openfolder").show();                        }                        $("#succ").finish().stop().slideDown('fast').delay(10000).slideUp('fast');                        listRestorableFiles(vrootID[0]);                    }                                   }            })        }        function handleOpenRestoreLocation(){            if (restoreFileInfo.RestorePoint !== undefined){                //Snapshot                ao_module_openPath(restoreFileInfo.RestorePoint + ":/");                return            }else if (restoreFileInfo.RestoredVirtualPath != undefined && restoreFileInfo.RestoredVirtualPath != ""){                var filepath = restoreFileInfo.RestoredVirtualPath;                var tmp = filepath.split("/");                var filename = tmp.pop();                var dirname = tmp.join("/");                ao_module_openPath(dirname, filename);            }        }        function listRestorableFiles(rootID){            $.ajax({                url: "/system/backup/listRestorable",                data: {vroot: rootID},                success: function(data){                    if (data.error !== undefined){                        $("#error").find(".reason").text(data.error);                        $("#error").removeClass("hidden");                    }else{                        //Filter out the restorable snapshot and files                        let restorableFiles = [];                        let restorableSnapshots = [];                        data.RestorableFiles.forEach(file => {                            if (file.IsSnapshot){                                restorableSnapshots.push(file);                            }else{                                restorableFiles.push(file);                                                            }                        });                        //Sort the result by latest first (file only)                        restorableFiles.sort(function(a, b) {                            return b.DeleteTime - a.DeleteTime;                        });                        restorableSnapshots.sort(function(a, b) {                            return b.Filename > a.Filename;                        });                        //Display the reuslt for restorableSnapshot                        $("#snapshotList").html("");                        restorableSnapshots.forEach(snapshot => {                            let snapshotData = encodeURIComponent(JSON.stringify(snapshot));                            $("#snapshotList").append(`<div class="item restorableFile snapshot" filedata="${snapshotData}">                                <div class="right floated content">                                    <div class="ui tiny button" onclick="showFileInfo(this.parentNode.parentNode)">Info</div>                                    <div class="ui tiny green button" onclick="restoreThisFile($(this).parent().parent());">Restore</div>                                </div>                                                                <div class="content">                                    <p style="word-break: break-all; font-size: 97%"><img class="ui mini spaced image nointeract" src="../../img/system/drive-backup.svg">                                        Snapshot ${snapshot.Filename}                                    </p>                                </div>                            </div>`);                        })                        //Display the result for restorableFile                        $("#restorableList").html("");                        restorableFiles.forEach(fileObject => {                            let thisFileData = encodeURIComponent(JSON.stringify(fileObject));                            var timerIcon = "100.svg";                            if (fileObject.RemainingTime < 75600){                                timerIcon = "87_5.svg"                            }else if (fileObject.RemainingTime < 64800){                                timerIcon = "75.svg"                            }else if (fileObject.RemainingTime < 54000){                                timerIcon = "62_5.svg"                            }else if (fileObject.RemainingTime < 43200){                                timerIcon = "50.svg"                            }else if (fileObject.RemainingTime < 32400){                                timerIcon = "37_5.svg"                            }else if (fileObject.RemainingTime < 21600){                                timerIcon = "25.svg"                            }else if (fileObject.RemainingTime < 10800){                                timerIcon = "12_5.svg"                            }else if (fileObject.RemainingTime < 7200){                                timerIcon = "0.svg"                            }                            var deleteTimeLeftHumanReadable = secondsToHms(fileObject.RemainingTime);                            var fileIcon = "../../img/system/file-restore.svg";                            var isHidden = "";                            if (fileObject.IsHidden == true){                                fileIcon = "../../img/system/file-restore-hidden.svg";                                isHidden = "hiddenfile";                            }                            $("#restorableList").append(`<div class="item restorableFile file ${isHidden}" filedata="${thisFileData}">                                <div class="right floated content">                                    <div class="timeleft" title="Will be deleted in ${deleteTimeLeftHumanReadable}">                                        <img class="ui fluid image" src="../../img/icons/backup/${timerIcon}"/>                                    </div>                                    <div class="ui tiny button" onclick="showFileInfo(this.parentNode.parentNode)">Info</div>                                    <div class="ui tiny green button" onclick="restoreThisFile($(this).parent().parent());">Restore</div>                                </div>                                                                <div class="content">                                    <p style="word-break: break-all;"><img class="ui mini spaced image nointeract" src="${fileIcon}">                                        ${fileObject.Filename}                                    </p>                                </div>                            </div>`);                        });                        if (restorableFiles.length == 0){                            $("#restorableList").html(`<div class="item">                            <img class="ui mini image nointeract" src="../../img/system/file-notfound.svg">                            <div class="content">                                No Restorable File(s) for this virtual disk.                            </div>                            </div>`);                        }                    }                                        $(".hiddenfile").hide();                }                            })        }        function restoreAll(){            if (confirm("Confirm restore all files from backup?")){                $(".restorableFile").each(function(){                    //Restore this file if it is not a snapshot                    if ($(this).hasClass("snapshot") == false){                        restoreThisFile($(this));                    }                });            }        }    </script></body></html>
 |