<!DOCTYPE HTML> <!-- RaspMatic update addon Copyright (C) 2018 Jan Schneider <oss@janschneider.net> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. --> <html> <head> <meta charset="UTF-8"> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="js/jquery-3.3.1.min.js"></script> <script src="js/i18next-13.0.0.min.js"></script> <script src="js/jquery-i18next-1.2.1.min.js"></script> <script src="js/semantic-2.4.2.min.js"></script> <link rel="stylesheet" href="css/semantic-2.4.2.min.css" /> <style> </style> <title data-i18n="title">RaspberryMatic Update Addon</title> <script> var language = navigator.language || navigator.userLanguage; var message_timer_id = null; var running_installation = ""; var current_firmware = '?'; var latest_firmware = '?'; var wlanScanTimer; var moving_userfs_to_device = false; var sid = null; function get_url_vars() { var vars = {}; var params = window.location.search.substring(1).split('&'); for(var i=0; i<params.length; i++) { param = params[i].split('='); if (param.length > 1) { vars[param[0]] = param[1]; } } return vars; } function get_url_var(name) { return get_url_vars()[name]; } function display_message(type, text, millis) { clear_message(); $('#message').contents().last()[0].textContent = text; $('#message').attr('class', 'ui ' + type + ' message visible'); message_timer_id = setTimeout(clear_message, millis); } function clear_message() { if (message_timer_id != null) { clearTimeout(message_timer_id); } message_timer_id = null; $('#message').contents().last()[0].textContent = ''; $('#message').attr('class', 'ui message hidden'); } function default_error_callback(xhr, ajaxOptions, thrownError) { console.error(xhr); err = thrownError; try { obj = JSON.parse(xhr.responseText); if (obj.error != null) { err = obj.error; } } catch(e) { } display_message('error', i18next.t('error_occurred', {'error': err}), 10000); } function rest(method, path, data, success_callback, error_callback) { if (!error_callback) { error_callback = default_error_callback } if (data != null) { data = JSON.stringify(data); } $.ajax({ url: "rest.cgi?sid=" + sid + "&path=" + path, type: method, data: data, context: document.body, success: success_callback, error: error_callback }); } function show_reboot_dialog() { $('#modal-reboot').modal({ onDeny: function(){ return true; }, onApprove: function() { rest('POST', '/system_reboot', null, function(data) { display_message('success', i18next.t('system_is_rebooting'), 120000); }); return true; } }) .modal('show'); } function show_shutdown_dialog() { $('#modal-shutdown').modal({ onDeny: function(){ return true; }, onApprove: function() { rest('POST', '/system_shutdown', null, function(data) { display_message('success', i18next.t('system_is_shutting_down'), 120000); }); return true; } }) .modal('show'); } function disable_buttons() { $('#install-latest-firmware-button').addClass('disabled'); $('#install-firmware-url-button').addClass('disabled'); $('[data-install-firmware-version]').addClass('disabled'); $('[data-delete-firmware-version]').addClass('disabled'); $('[data-update-addon-id]').addClass('disabled'); $('[data-uninstall-addon-id]').addClass('disabled'); $('#install-addon-url-button').addClass('disabled'); $('#install-addon-file-button').addClass('disabled'); } function reset_buttons() { $('#install-latest-firmware-button').removeClass('loading'); $('#install-latest-firmware-button').removeClass('disabled'); $('#install-firmware-url-button').removeClass('loading'); $('#install-firmware-url-button').removeClass('disabled'); $('[data-install-firmware-version]').removeClass('loading'); $('[data-install-firmware-version]').removeClass('disabled'); $('[data-delete-firmware-version]').removeClass('disabled'); $('[data-update-addon-id]').removeClass('loading'); $('[data-update-addon-id]').removeClass('disabled'); $('[data-uninstall-addon-id]').removeClass('disabled'); $('[data-uninstall-addon-id]').removeClass('loading'); $('#install-addon-url-button').removeClass('disabled'); $('#install-addon-url-button').removeClass('loading'); $('#install-addon-file-button').removeClass('disabled'); $('#install-addon-file-button').removeClass('loading'); } function set_running_installation(installation_info, error) { //console.info("set_running_installation: |" + installation_info + "|" + running_installation + "|" + error); var firmware_regex = /firmware\s+(.*)/i; if (running_installation && (!installation_info)) { // Running installation finished var match = firmware_regex.exec(running_installation); if (error) { $('#install-progress').progress("set error"); display_message('error', i18next.t('installation_failed', {'what': running_installation, 'error': error}), 4*3600000); } else { $('#install-progress').progress("set success"); display_message('success', i18next.t('installation_success', {'what': running_installation}), 4*3600000); } $('#modal-log').modal('refresh'); $('#log-content').scrollTop($('#log-content').prop("scrollHeight")); reset_buttons(); } running_installation = installation_info; if (running_installation) { var match = firmware_regex.exec(running_installation); if (match != null) { var version = match[1]; display_message('info', i18next.t('installing_firmware', {'version': version}), 3600000); disable_buttons(); $('[data-install-firmware-version="' + version + '"]').addClass('loading'); $('[data-install-firmware-version="' + version + '"]').removeClass('disabled'); } } } function update_install_log() { rest("GET", "/get_running_installation", null, function(installation_info) { if (running_installation) { if ($('#install-progress').progress("get percent") >= 95) { $('#install-progress').progress("decrement", 20); } $('#install-progress').progress('increment'); if (installation_info != running_installation) { if (installation_info == "") { // Wait a while to handle potential errors setTimeout(function() { set_running_installation(installation_info); }, 3000); } else { set_running_installation(installation_info); } } } }); rest("GET", "/read_install_log", null, function(data) { $('#log-content').html(data.replace(/\n/g, '<br />')); //$('#modal-log').modal('refresh'); $('#log-content').scrollTop($('#log-content').prop("scrollHeight")); if (running_installation) { setTimeout(update_install_log, 1000); } }); } function delete_firmware_image(version) { rest("POST", "/delete_firmware_image", {"version":version}, function(data) { display_message('success', i18next.t('delete_firmware_img_success', {'version': version}), 5000); get_firmware_info(); } ); } function install_firmware(download_url, version) { $('#log-content').html(''); $('#install-progress').progress("reset"); $('#modal-log').modal('show'); if (!running_installation) { var reboot = $('#reboot-after-install').is(':checked'); var keep_download = ! $('#delete-download-after-install').is(':checked'); var dryrun = $('#dryrun').is(':checked'); if (version) { set_running_installation("Firmware " + version); } else { set_running_installation("Firmware unknown"); } if (!download_url) download_url = ""; if (!version) version = ""; rest("POST", "/start_install_firmware", {"download_url": download_url, "version":version, "language": language, "reboot":reboot, "dryrun":dryrun, "keep_download": keep_download}, function(data) { // We are not expecting a response }, function(xhr, ajaxOptions, thrownError) { console.error("Firmware installation error: " + thrownError + ": " + xhr.responseText); //$('#modal-log').modal('hide'); set_running_installation("", thrownError + ": " + xhr.responseText); } ); } setTimeout(update_install_log, 1000); } function install_latest_firmware() { if (latest_firmware && latest_firmware != '?') { install_firmware(null, latest_firmware); } } function get_firmware_info() { $('#dimmer-firmware-info').addClass('active'); rest("GET", "/get_firmware_info", null, function(data) { $('#firmware-info tbody').empty(); var latest_firmware_supported = false; data.forEach(function(fw) { if (fw.latest) { latest_firmware = fw.version; latest_firmware_supported = fw.supported; } if (fw.installed) current_firmware = fw.version; var color = 'yellow'; if (fw.latest) color = 'green'; if (fw.installed) color = 'gray'; var disabled = ((fw.image || fw.url) && fw.supported ? '' : 'disabled'); var binstall = $('<div class="ui '+ color +' basic '+ disabled +' button">').attr('data-install-firmware-version', fw.version).append($('<i class="sign in icon">'), i18next.t('install')); binstall.click(function() { install_firmware(null, this.getAttribute('data-install-firmware-version')); }); var bcls = ''; if (!fw.image) bcls = 'disabled'; if (fw.version == running_installation) bcls = 'loading'; var bdelete = $('<div class="ui orange basic '+ bcls +' button">').attr('data-delete-firmware-version', fw.version).append($('<i class="delete icon">'), i18next.t('delete_download')); bdelete.click(function() { delete_firmware_image(this.getAttribute('data-delete-firmware-version')); }); var available = (fw.url ? 'checked=""' : '') var supported = (fw.supported ? 'checked=""' : '') var downloaded = (fw.image ? 'checked=""' : '') var cls = ''; if (fw.installed) cls = ' class="warning"'; if (fw.latest) cls = ' class="positive"'; $("#firmware-info tbody").append($('<tr' + cls + '>').append( $('<td>').append($('<a>', {text: fw.version, title: i18next.t('open_release_info'), href: fw.info_url, target: "_blank"})), $('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" '+available+'>'),$('<label></label>'))), $('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" '+supported+'>'),$('<label></label>'))), $('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" '+downloaded+'>'),$('<label></label>'))), $('<td class="center aligned">').append(bdelete, binstall) )); }); var color = "#d01919"; if (current_firmware == latest_firmware) { color = "#21BA45"; } $("#firmware-summary").empty(); $("#firmware-summary").append( $('<div class="ui item">').html(i18next.t('current_installed_version') + ': <span style="color:'+ color +'">' + current_firmware + '</span>'), $('<div class="ui item">').html(i18next.t('latest_available_version') + ': ' + latest_firmware) ); if (latest_firmware_supported && current_firmware != latest_firmware) { $("#firmware-summary").append( $('<div id="install-latest-firmware-button" class="ui green basic button" style="margin-top:20px; margin-bottom:20px;">').click(install_latest_firmware).append($('<i class="sign in icon">'), i18next.t('install_latest_firmware')) ); } rest("GET", "/get_running_installation", null, function(installation_info) { set_running_installation(installation_info); }); $('#dimmer-firmware-info').removeClass('active'); }); } function get_system_info() { rest("GET", "/get_system_info", null, function(data) { $("#system-info").empty(); $("#system-info").append( $('<div class="item">').html(i18next.t('system_type', {'system_type': data.system_type})), $('<div class="item">').html(i18next.t('uptime', {'uptime': data.uptime})) ); }); } function format_size(size) { if (size < 0) { return ''; } if (size > 1024 * 1024 * 1024) { return (parseInt(size)/1024/1024/1024).toFixed(1) + ' GB' } else if (size > 1024 * 1024) { return (parseInt(size)/1024/1024).toFixed(1) + ' MB' } else { return (parseInt(size)/1024).toFixed(1) + ' KB' } } function get_partitions() { $('#dimmer-volume-info').addClass('active'); rest("GET", "/get_partitions", null, function(data) { var disks = {}; data.forEach(function(partition) { if (partition.partition == 0) { disks[partition.disk_device] = partition; disks[partition.disk_device].userfs_on_disk = false; disks[partition.disk_device].bootfs_on_disk = false; disks[partition.disk_device].partitions = {}; } }); data.forEach(function(partition) { disks[partition.disk_device].partitions[partition.partition] = partition; if (partition.mountpoint == '/usr/local') { disks[partition.disk_device].userfs_on_disk = true; } else if (partition.mountpoint == '/boot') { disks[partition.disk_device].bootfs_on_disk = true; } }); $('#volume-info tbody').empty(); for (var disk_device in disks) { parts = Object.keys(disks[disk_device].partitions); parts.sort(); for (var part in parts) { var partition = disks[disk_device].partitions[part]; var is_sys_partition = (partition.filesystem_label == 'userfs' || partition.filesystem_label == 'bootfs' || partition.filesystem_label == 'rootfs' || partition.filesystem_label == 'rootfs1' || partition.filesystem_label == 'rootfs2') var menu_items = []; var skip_dev = false; if (disks[disk_device].userfs_on_disk) { skip_dev = true; } else if (disks[disk_device].bootfs_on_disk && (partition.partition == 0)) { skip_dev = true; } else if (is_sys_partition && (partition.partition > 0)) { skip_dev = true; } if (! skip_dev) { var device = partition.disk_device; var label = i18next.t('use_disk_for_userfs'); if (partition.partition > 0) { device = partition.partition_device; var label = i18next.t('use_partition_for_userfs'); } menu_items.push($('<a class="item">').append(label).attr('data-device', device).click(function() { var target_device = this.getAttribute('data-device'); $('#modal-move-userfs').modal({ onDeny: function() { return true; }, onApprove: function() { display_message('warning', i18next.t('moving_userfs'), 300000); if (!moving_userfs_to_device) { rest('POST', '/move_userfs_to_device', {"target_device":target_device}, function(data) { moving_userfs_to_device = false; display_message('success', i18next.t('userfs_moved'), 120000); rest('POST', '/system_reboot'); }, function(xhr, ajaxOptions, thrownError) { moving_userfs_to_device = false; default_error_callback(xhr, ajaxOptions, thrownError); } ); } moving_userfs_to_device = true; } }) .modal('show'); })); if (partition.partition == 0) { menu_items.push($('<a class="item">').append(i18next.t('delete_partition_table')).attr('data-device', device).click(function() { var device = this.getAttribute('data-device'); $('#modal-delete-partition-table').modal({ onDeny: function() { return true; }, onApprove: function() { rest('POST', '/delete_partition_table', {"device":device}, function(data) { display_message('success', i18next.t('partiton_table_deleted'), 120000); get_partitions(); }, function(xhr, ajaxOptions, thrownError) { default_error_callback(xhr, ajaxOptions, thrownError); get_partitions(); } ); } }) .modal('show'); })); } } var menu = null; if (menu_items.length > 0) { menu = $('<div class="ui compact menu" style="min-height:28px; max-height:28px;">').append( $('<div class="ui floating dropdown top right item">').append( i18next.t('action'), $('<i class="dropdown icon">'), $('<div class="menu">').append(menu_items) ) ) } if (partition.partition == 0) { var st = "border:none; border-top: 2px solid #aaafaf"; $("#volume-info tbody").append($('<tr style="background: #f8ffff;">').append( $('<td style="'+st+'" class="top aligned" rowspan="' + parts.length + '">') .append($('<label>' + partition.model + '</label><br /><strong>' + partition.disk_device + '</strong>')), $('<td style="'+st+'" class="center aligned" colspan="4">'), $('<td class="right aligned" style="'+st+'">').append($('<label>' + format_size(partition.size) + '</label>')), $('<td style="'+st+'" colspan="2">'), $('<td style="'+st+'" class="center aligned">').append(menu) )); } else { var usage = ''; if (partition.filesystem_usage && partition.filesystem_usage >= 0) { usage = (parseFloat(partition.filesystem_usage) * 100).toFixed(0) + '%' } var st = (is_sys_partition) ? 'style="font-weight:bolder"' : ''; var used = (partition.filesystem_used == -1) ? '' : format_size(partition.filesystem_used); var free = (partition.filesystem_used == -1) ? '' : format_size(partition.size-partition.filesystem_used); $("#volume-info tbody").append($('<tr>').append( $('<td style="border-left: 1px solid rgba(34,36,38,.1)">').append($('<label>' + partition.partition + '</label>')), $('<td>').append($('<label>' + partition.filesystem_type + '</label>')), $('<td>').append($('<label '+st+'>' + partition.filesystem_label + '</label>')), $('<td>').append($('<label '+st+'>' + partition.mountpoint + '</label>')), $('<td class="right aligned">').append($('<label>' + format_size(partition.size) + '</label>')), $('<td class="right aligned">').append($('<label>' + used + '</label>')), $('<td class="right aligned">').append($('<label>' + free + '</label>')), $('<td class="center aligned">').append(menu) )); } } $('.dropdown').dropdown({}); } $('#dimmer-volume-info').removeClass('active'); }); } function install_addon(addon_id, download_url, file_input) { if (!running_installation) { display_message('info', i18next.t('installing_addon', {'addon_id': addon_id}), 180000); if (addon_id) { $('[data-update-addon-id="' + addon_id + '"]').addClass('loading'); } if (download_url) { $('#install-addon-url-button').addClass('loading'); } if (file_input) { $('#install-addon-file-button').addClass('loading'); } disable_buttons(); var success_callback = function(data) { //console.info(data); reset_buttons(); display_message('success', data, 5000); if (addon_id) { if (addon_id == 'rmupdate') { location.reload(); } else { $('#tr-' + addon_id).removeClass('warning'); $('#tr-' + addon_id).addClass('positive'); $('#button-update-' + addon_id).removeClass('green'); $('#button-update-' + addon_id).addClass('gray'); $('#button-update-' + addon_id).contents().last()[0].textContent = i18next.t('reinstall'); $('#label-version-' + addon_id).text($('#label-available-version-' + addon_id).text()); } } else { $('#install-addon-url-input').val(''); $('#install-addon-file-input').val(''); get_addon_info(); } } var error_callback = function(xhr, ajaxOptions, thrownError) { console.error("Addon installation error: " + thrownError + ": " + xhr.responseText); reset_buttons(); $('#install-addon-url-input').val(''); $('#install-addon-file-input').val(''); default_error_callback(xhr, ajaxOptions, thrownError); } if (file_input) { $.ajax({ url: 'rest.cgi?sid=' + sid + '&path=/install_addon_archive', data: file_input.files[0], type: 'POST', processData: false, contentType: 'application/octet-stream', success: success_callback, error: error_callback }); } else { rest("POST", "/install_addon", {"addon_id":addon_id, "download_url":download_url}, success_callback, error_callback ); } } } function uninstall_addon(addon_id) { if (!running_installation) { display_message('info', i18next.t('uninstalling_addon', {'addon_id': addon_id}), 180000); disable_buttons(); $('[data-uninstall-addon-id="' + addon_id + '"]').addClass('loading'); rest("POST", "/uninstall_addon", {"addon_id":addon_id}, function(data) { //console.info(data); display_message('success', data, 5000); reset_buttons(); $('#tr-' + addon_id).remove(); }, function(xhr, ajaxOptions, thrownError) { console.error("Addon installation error: " + thrownError + ": " + xhr.responseText); reset_buttons(); default_error_callback(xhr, ajaxOptions, thrownError); } ); } } function get_addon_info() { $('#dimmer-addon-info').addClass('active'); rest("GET", "/get_addon_info", null, function(data) { $('#addon-info tbody').empty(); data.forEach(function(addon) { var color = 'gray'; if (addon.available_version && (addon.version != addon.available_version)) color = 'green'; var disabled = ((addon.available_version && addon.download_url) ? '' : 'disabled'); var bupdate = $('<div class="ui '+ color +' basic '+ disabled +' button" id="button-update-' + addon.id + '">') .append($('<i class="sign in icon">'), (addon.version == addon.available_version) ? i18next.t('reinstall') : i18next.t('update')); if (!disabled) { bupdate.attr('data-update-addon-id', addon.id).attr('data-update-addon-available-version', addon.available_version) } bupdate.click(function() { install_addon(this.getAttribute('data-update-addon-id')); }); disabled = ((addon.config_url) ? '' : 'disabled'); var bconfig = $('<div class="ui blue basic '+ disabled +' button">') .attr('data-addon-config-url', addon.config_url) .append($('<i class="setting icon">'), i18next.t('open_config')); bconfig.click(function() { var win = window.open(this.getAttribute('data-addon-config-url') + window.location.search, '_blank'); win.focus(); }); var buninstall = $('<div class="ui orange basic button">') .attr('data-uninstall-addon-id', addon.id) .append($('<i class="remove icon">'), i18next.t('uninstall')); buninstall.click(function() { var addon_id = this.getAttribute('data-uninstall-addon-id'); $('#modal-uninstall-addon').modal({ onDeny: function(){ return true; }, onApprove: function() { uninstall_addon(addon_id); return true; } }) .modal('show'); }); var cls = (((!addon.available_version) || (addon.version == addon.available_version)) ? "positive" : "warning"); var available_version = ((addon.available_version) ? addon.available_version : "?"); $("#addon-info tbody").append($('<tr class="' + cls + '" id="tr-' + addon.id + '">').append( $('<td>').append($('<label>' + addon.name + '</label>')), $('<td>').append($('<label id="label-version-' + addon.id + '">' + addon.version + '</label>')), $('<td>').append($('<label id="label-available-version-' + addon.id + '">' + available_version + '</label>')), $('<td class="center aligned">').append(bupdate, bconfig, buninstall) )); }); $('#dimmer-addon-info').removeClass('active'); if (running_installation) { // deactivate buttons set_running_installation(running_installation); } }); } function wlan_scan(force) { if (!force && !$('#wlan-scan-checkbox').prop("checked")) { return; } rest("GET", "/wlan_scan", null, function(data) { $('#wlan-list tbody').empty(); data.forEach(function(wlan) { var cls = (wlan.connected == "1") ? "disabled" : ""; var bconnect = $('<div class="ui green basic button ' + cls + '">') .attr('data-ssid', wlan.ssid) .append($('<i class="sign in icon">'), i18next.t('connect')); bconnect.click(function() { $('#form-connect-wlan').form('clear'); $('#form-connect-wlan').attr('data-ssid', this.getAttribute('data-ssid')); $('#modal-connect-wlan').modal('show'); }); cls = (wlan.connected == "1") ? "" : "disabled"; var bdisconnect = $('<div class="ui orange basic button ' + cls + '">') .attr('data-ssid', wlan.ssid) .append($('<i class="delete icon">'), i18next.t('disconnect')); bdisconnect.click(function() { $('.button[data-ssid]').addClass('loading'); rest("POST", "/wlan_disconnect"); }); var connected_checked = ((wlan.connected == "1") ? 'checked=""' : '') cls = (wlan.connected == "1") ? "positive" : ""; $("#wlan-list tbody").append($('<tr class="' + cls + '">').append( $('<td>').append($('<label>' + wlan.ssid + '</label>')), $('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" ' + connected_checked + '>'),$('<label></label>'))), $('<td>').append($('<label>' + wlan.signal + '</label>')), $('<td class="center aligned">').append(bconnect, bdisconnect) )); }); wlanScanTimer = setTimeout(function(){ wlan_scan(); }, 5000); }, function(xhr, ajaxOptions, thrownError) { wlanScanTimer = setTimeout(function(){ wlan_scan(); }, 5000); }); } function init() { $('#content').dimmer('hide'); var form_config = { on: 'blur', fields: { password: { identifier: 'password' } }, onSuccess: function(event, fields) { if (wlanScanTimer) { clearTimeout(wlanScanTimer); } wlanScanTimer = setTimeout(function(){ wlan_scan(); }, 10000); $(event.currentTarget).closest("div.modal").modal('hide'); var ssid = $('#form-connect-wlan').attr('data-ssid'); var password = $(event.currentTarget).form('get value', 'password'); $('.button[data-ssid]').addClass('loading'); rest("POST", "/wlan_connect", {"ssid": ssid, "password": password}); event.preventDefault(); } }; $('#form-connect-wlan').form(form_config); rest("GET", "/version", null, function(version) { document.title = document.title + " " + version; }); rest("GET", "/is_system_upgradeable", null, function(upgradeable) { if (!upgradeable) { display_message('error', i18next.t('system_not_upgradeable'), 10000); } }); get_system_info(); get_partitions(); get_firmware_info(); get_addon_info(); wlan_scan(true); } $(document).ready(function() { i18next.init({ lng: language, fallbackLng: 'en', resources: { en: { translation: { title: 'System update', system_info: 'System information', system_type: 'System type: {{system_type}}', uptime: 'Uptime: {{uptime}}', reboot_system: 'Reboot system', shutdown_system: 'Shutdown system', reboot: 'Reboot', shutdown: 'Shutdown', sure_to_reboot_system: 'Are you sure you want to reboot the system now?', sure_to_shutdown_system: 'Are you sure you want to shutdown the system now?', system_is_rebooting: 'System is going down for reboot now.', system_is_shutting_down: 'System is going down for shutdown now.', volumes: 'Volumes', device: 'Device', partition_number: 'Partition', filesystem_type: 'Filesystem', filesystem_label: 'Label', mountpoint: 'Mountpoint', size: 'Size', used: 'Used', free: 'Free', use_disk_for_userfs: 'Format and use whole disk for userfs.', use_partition_for_userfs: 'Use partition for userfs.', move_userfs: 'Move userfs to another device', sure_to_move_userfs: 'Are you sure you want to move userfs?', move: 'Move', moving_userfs: 'Moving userfs, please wait, this will take a while...', userfs_moved: 'Userfs moved, system will reboot now.', delete_partition_table: 'Delete partition table.', sure_to_delete_partition_table: 'Are you sure you want to delete the partition table?', delete: 'Delete', partiton_table_deleted: 'Partiton table deleted.', firmwares: 'Firmwares', current_installed_version: 'Current installed version', latest_available_version: 'Latest available version', loading: 'Loading', version: 'Version', available: 'Available', supported: 'Supported', downloaded: 'Downloaded', action: 'Action', delete_download: 'Delete download', install: 'Install', installation_log: 'Installation log', open_release_info: 'Open release info', perform_trial_run: 'Perform a trial run with no changes made', delete_download_after_install: 'Delete download after installation', reboot_after_install: 'Reboot system after installation', addons: 'Addons', addon_name: 'Addon name', installed_version: 'Installed version', available_version: 'Available version', reinstall: 'Reinstall', update: 'Update', open_config: 'Open config', error_occurred: 'An error occurred: {{error}}', installation_failed: 'Failed to install {{what}}: {{error}}', installation_success: '{{what}} successfully installed.', delete_firmware_img_success: 'Firmware image {{version}} successfully deleted.', installing_firmware: 'Installing firmware {{version}}.', install_latest_firmware: 'Install latest firmware', system_not_upgradeable: 'System not upgradeable or filesystem to small!', uninstall: 'Uninstall', cancel: 'Canel', uninstall_addon: 'Uninstall addon', sure_to_uninstall_addon: 'Are you sure you want to uninstall this addon?', installing_addon: 'Installing addon {{addon_id}}.', uninstalling_addon: 'Uninstalling addon {{addon_id}}.', install_addon_from_url: 'Install addon from url', install_addon_from_file: 'Install addon from file', choose_addon_file: 'Choose and install addon-file', wlan: "WLAN", wlan_scanning: "Scan for networks", wlan_ssid: "SSID", wlan_signal: "Signal", wlan_connected: "Connected", connect_to_wlan: "Connect with wifi", password: "Password", connect: "Connect", disconnect: "Disconnect", login: "Login", username: "Username", } }, de: { translation: { title: 'System-Aktualisierung', system_info: 'System-Informationen', system_type: 'System-Typ: {{system_type}}', uptime: 'Betriebszeit: {{uptime}}', reboot_system: 'System neu starten', shutdown_system: 'System herunterfahren', reboot: 'Neu starten', shutdown: 'Herunterfahren', sure_to_reboot_system: 'Soll das System jetzt neu gestartet werden?', sure_to_shutdown_system: 'Soll das System jetzt heruntergefahren werden?', system_is_rebooting: 'Das System wird neu gestartet.', system_is_shutting_down: 'Das System wird heruntergefahren.', volumes: 'Datenträger', device: 'Gerät', partition_number: 'Partition', filesystem_type: 'Dateisystem', filesystem_label: 'Label', mountpoint: 'Einhängepunkt', size: 'Größe', used: 'Belegt', free: 'Frei', use_disk_for_userfs: 'Gesamten Datenträger neu formatieren<br />und für userfs verwenden.', use_partition_for_userfs: 'Die Partition als userfs verwenden.', move_userfs: 'Userfs auf anderen Datenträger verschieben', sure_to_move_userfs: 'Soll das userfs wirklich verschoben werden?', move: 'Verschieben', moving_userfs: 'Verschiebe userfs, bitte warten, dies kann einige Zeit dauern...', userfs_moved: 'Userfs wurde verschoben, das System wird neu gestartet.', delete_partition_table: 'Partitionstabelle löschen.', sure_to_delete_partition_table: 'Soll die Partitionstabelle wirklich gelöscht werden?', delete: 'Löschen', partiton_table_deleted: 'Partitionstabelle gelöscht.', firmwares: 'Firmwares', current_installed_version: 'Momentan installierte Version', latest_available_version: 'Aktuellste verfügbare Version', loading: 'Lade', version: 'Version', available: 'Verfügbar', supported: 'Unterstützt', downloaded: 'Heruntergeladen', action: 'Aktion', delete_download: 'Download löschen', install: 'Installieren', installation_log: 'Installations-Protokoll', open_release_info: 'Release-Informationen öffnen', perform_trial_run: 'Testlauf durchführen ohne Änderungen durchzuführen', delete_download_after_install: 'Download nach Installation löschen', reboot_after_install: 'System nach Installation neu starten', addons: 'Zusatzsoftware', addon_name: 'Name des Addons', installed_version: 'Installierte Version', available_version: 'Verfügbare Version', reinstall: 'Neu installieren', update: 'Aktualisieren', open_config: 'Konfiguration öffnen', error_occurred: 'Ein Fehler ist aufgetreten: {{error}}', installation_failed: 'Fehler beim Installieren von {{what}}: {{error}}', installation_success: '{{what}} erfolgreich installiert.', delete_firmware_img_success: 'Firmware-Image {{version}} erfolgreich gelöscht.', installing_firmware: 'Installiere Firmware {{version}}.', install_latest_firmware: 'Aktuellste Firmware installieren', system_not_upgradeable: 'System nicht aktualisierbar oder Dateisystem zu klein!', uninstall: 'Deinstallieren', cancel: 'Abbrechen', uninstall_addon: 'Addon deinstallieren', sure_to_uninstall_addon: 'Sind sie sicher, dass sie dieses Addon deinstallieren wollen?', installing_addon: 'Installiere Addon {{addon_id}}.', uninstalling_addon: 'Deinstalliere Addon {{addon_id}}.', install_addon_from_url: 'Addon von URL installieren', install_addon_from_file: 'Addon aus Datei installieren', choose_addon_file: 'Addon-Datei auswählen und installieren', wlan: "WLAN", wlan_scanning: "Nach Netzwerken suchen", wlan_ssid: "SSID", wlan_signal: "Signal", wlan_connected: "Verbunden", connect_to_wlan: "Mit WLAN verbinden", password: "Passwort", connect: "Verbinden", disconnect: "Trennen", login: "Anmelden", username: "Benuzername", } } } }, function(err, t) { jqueryI18next.init(i18next, $); $('title').localize(); $('h1').localize(); $('h2').localize(); $('div').localize(); $('th').localize(); $('label').localize(); $('#install-addon-url-button').contents().last()[0].textContent = i18next.t('install'); $('#install-firmware-url-button').contents().last()[0].textContent = i18next.t('install'); $('#install-addon-file-button').contents().last()[0].textContent = i18next.t('choose_addon_file'); }); $('#content').dimmer('show'); sid = get_url_var('sid'); rest("GET", "/get_session", null, function(data) { init(); }, function(xhr, ajaxOptions, thrownError) { if (xhr.status == 401) { var form_config = { on: 'blur', fields: { username: { identifier: 'username' }, password: { identifier: 'password' } }, onSuccess: function(event, fields) { event.preventDefault(); var username = $(event.currentTarget).form('get value', 'username'); var password = $(event.currentTarget).form('get value', 'password'); rest("POST", "/login", {"username": username, "password": password}, function(data) { window.location.href = window.location.href.replace(/\?.*/, '') + '?sid=@' + data + '@'; }, function(xhr, ajaxOptions, thrownError) { default_error_callback(xhr, ajaxOptions, thrownError); } ); } }; $('#form-login').form(form_config); $('#modal-login').modal('show'); } else { default_error_callback(xhr, ajaxOptions, thrownError); } } ); }); </script> </head> <body> <div style="position: fixed; left: 50%; top: 2vh; z-index: 2000"> <div style="position: relative; left: -50%;"> <div class="ui container"> <div id="message" class="ui message hidden" style="margin-left: 100px; margin-right: 100px; min-height: 50px; min-width: 340px"> <i class="close icon" onclick="clear_message();"></i> </div> </div> </div> </div> <div id="content" style="padding: 0; margin: 0; width: 100%"> <div style="padding-top: 5vw; padding-bottom: 5vw" class="ui container"> <h1 class="ui center aligned dividing header" data-i18n="title"></h1> <h2 class="ui header"> <i class="info icon"></i> <div data-i18n="system_info" class="content"> </div> </h2> <div class="ui list" id="system-info"> </div> <div class="ui orange basic button" data-i18n="reboot_system" onclick="show_reboot_dialog();"></div> <div class="ui red basic button" data-i18n="shutdown_system" onclick="show_shutdown_dialog();"></div> <h2 class="ui header"> <i class="hdd outline icon"></i> <div data-i18n="volumes" class="content"> </div> </h2> <div class="dimmable"> <div id="dimmer-volume-info" class="ui active inverted dimmer"> <div class="ui loader" data-i18n="loading"></div> </div> <table id="volume-info" class="ui celled stackable table"> <thead> <tr> <th data-i18n="device"></th> <th data-i18n="partition_number"></th> <th data-i18n="filesystem_type"></th> <th data-i18n="filesystem_label"></th> <th data-i18n="mountpoint"></th> <th class="right aligned" data-i18n="size"></th> <th class="right aligned" data-i18n="used"></th> <th class="right aligned" data-i18n="free"></th> <th class="center aligned" data-i18n="action"></th> </tr> </thead> <tbody> </tbody> </table> </div> <h2 class="ui header"> <i class="settings icon"></i> <div data-i18n="firmwares" class="content"> </div> </h2> <div class="ui list" id="firmware-summary"> </div> <div class="dimmable"> <div id="dimmer-firmware-info" class="ui active inverted dimmer"> <div class="ui loader" data-i18n="loading"></div> </div> <div style="width: 100%" class="ui action input"> <input id="install-firmware-url-input" type="text" placeholder="http://.../RaspberryMatic.zip"/> <button id="install-firmware-url-button" class="ui green right labeled icon button" onclick="install_firmware($('#install-firmware-url-input').val());"> <i class="sign in icon"></i> install </button> </div> <table id="firmware-info" class="ui celled stackable table"> <thead> <tr> <th data-i18n="version"></th> <th class="center aligned" data-i18n="available"></th> <th class="center aligned" data-i18n="supported"></th> <th class="center aligned" data-i18n="downloaded"></th> <th class="center aligned" data-i18n="action"></th> </tr> </thead> <tbody> </tbody> </table> <div class="ui checkbox"> <input id="dryrun" type="checkbox"> <label data-i18n="perform_trial_run"></label> </div> <br /> <div class="ui checkbox"> <input id="delete-download-after-install" type="checkbox" checked="checked"> <label data-i18n="delete_download_after_install"></label> </div> <br /> <div class="ui checkbox"> <input id="reboot-after-install" type="checkbox" checked="checked"> <label data-i18n="reboot_after_install"></label> </div> </div> <h2 class="ui header"> <i class="plug icon"></i> <div data-i18n="addons" class="content"> </div> </h2> <div class="dimmable"> <div id="dimmer-addon-info" class="ui active inverted dimmer"> <div class="ui loader" data-i18n="loading"></div> </div> <table id="addon-info" class="ui celled stackable table"> <thead> <tr> <th data-i18n="addon_name"></th> <th data-i18n="installed_version"></th> <th data-i18n="available_version"></th> <th class="center aligned" data-i18n="action"></th> </tr> </thead> <tbody> </tbody> </table> </div> <h2 class="ui header"> <i class="cloud download icon"></i> <div data-i18n="install_addon_from_url" class="content"> </div> </h2> <div style="width: 100%" class="ui action input"> <input id="install-addon-url-input" type="text" placeholder="http://.../addon.tar.gz"/> <button id="install-addon-url-button" class="ui green right labeled icon button" onclick="install_addon(null, $('#install-addon-url-input').val());"> <i class="sign in icon"></i> install </button> </div> <h2 class="ui header"> <i class="upload icon"></i> <div data-i18n="install_addon_from_file" class="content"> </div> </h2> <div style="width: 100%" class="ui action input"> <input class="inputfile" id="install-addon-file-input" type="file" onchange="install_addon(null, null, this);" style="display: none;"/> <label id="install-addon-file-button" for="install-addon-file-input" class="ui green button"> <i class="ui file archive outline icon"></i> choose_addon_file </label> </div> <h2 class="ui header"> <i class="wifi icon"></i> <div data-i18n="wlan" class="content"> </div> </h2> <div> <div class="ui toggle checkbox"> <input type="checkbox" id="wlan-scan-checkbox" onclick="wlan_scan();"> <label data-i18n="wlan_scanning"></label> </div> <table id="wlan-list" class="ui celled stackable table"> <thead> <tr> <th data-i18n="wlan_ssid"></th> <th data-i18n="wlan_connected"></th> <th data-i18n="wlan_signal"></th> <th class="center aligned" data-i18n="action"></th> </tr> </thead> <tbody> </tbody> </table> </div> </div> </div> <div style="height:60vh;" id="modal-log" class="ui modal"> <i class="close icon"></i> <div class="header" data-i18n="installation_log"> </div> <div class="ui bottom attached progress" data-value="0" data-total="25" id="install-progress"> <div class="bar"></div> </div> <div class="content"> <pre style="height:40vh; overflow-x:hidden; overflow-y:auto; white-space: pre-wrap;" id="log-content"> </pre> </div> </div> <div id="modal-uninstall-addon" class="ui small basic modal transition scrolling"> <div data-i18n="uninstall_addon" class="header"></div> <div class="content"> <p data-i18n="sure_to_uninstall_addon"></p> </div> <div class="actions"> <div data-i18n="cancel" class="ui gray basic cancel inverted button"> </div> <div data-i18n="uninstall" class="ui red approve inverted button"> </div> </div> </div> <div id="modal-reboot" class="ui small basic modal transition scrolling"> <div data-i18n="reboot_system" class="header"></div> <div class="content"> <p data-i18n="sure_to_reboot_system"></p> </div> <div class="actions"> <div data-i18n="cancel" class="ui gray basic cancel inverted button"> </div> <div data-i18n="reboot" class="ui red approve inverted button"> </div> </div> </div> <div id="modal-shutdown" class="ui small basic modal transition scrolling"> <div data-i18n="shutdown_system" class="header"></div> <div class="content"> <p data-i18n="sure_to_shutdown_system"></p> </div> <div class="actions"> <div data-i18n="cancel" class="ui gray basic cancel inverted button"> </div> <div data-i18n="shutdown" class="ui red approve inverted button"> </div> </div> </div> <div id="modal-move-userfs" class="ui small basic modal transition scrolling"> <div data-i18n="move_userfs" class="header"></div> <div class="content"> <p data-i18n="sure_to_move_userfs"></p> </div> <div class="actions"> <div data-i18n="cancel" class="ui gray basic cancel inverted button"> </div> <div data-i18n="move" class="ui red approve inverted button"> </div> </div> </div> <div id="modal-delete-partition-table" class="ui small basic modal transition scrolling"> <div data-i18n="delete_partition_table" class="header"></div> <div class="content"> <p data-i18n="sure_to_delete_partition_table"></p> </div> <div class="actions"> <div data-i18n="cancel" class="ui gray basic cancel inverted button"> </div> <div data-i18n="delete" class="ui red approve inverted button"> </div> </div> </div> <div id="modal-connect-wlan" class="ui modal"> <i class="close icon"></i> <div class="header" data-i18n="connect_to_wlan"> </div> <div class="content"> <form id="form-connect-wlan" class="ui form"> <div class="field"> <label data-i18n="password"></label> <input type="password" name="password"> </div> <div class="ui error message"></div> <div class="ui button" onclick="$('#modal-connect-wlan').modal('hide');" data-i18n="cancel"></div> <div id="submit-connect-wlan" class="ui primary submit button" data-i18n="connect"></div> </form> </div> </div> <div id="modal-login" class="ui modal"> <i class="close icon"></i> <div class="header" data-i18n="login"> </div> <div class="content"> <form id="form-login" class="ui form"> <div class="field"> <label data-i18n="username"></label> <input type="text" name="username" value="Admin"> </div> <div class="field"> <label data-i18n="password"></label> <input type="password" name="password"> </div> <div class="ui error message"></div> <!-- <div class="ui button" onclick="$('#modal-login').modal('hide');" data-i18n="cancel"></div> --> <div id="submit-login" class="ui primary submit button" data-i18n="login"></div> </form> </div> </div> </body> </html>