Commit 73a369a7 authored by Stavros Sachtouris's avatar Stavros Sachtouris Committed by Giorgos Korfiatis
Browse files

Help GUI user to resolve folder/container problems

Implement a dialogue window which is pop up when the directory or
container have been removed. The proposed solution is to create
the missing piece and reset the syncing process. If the user
accepts, the proposed solution is enforced. Otherwise the system
stays in a non working mode, where the user can fix the problem by
handling the settings.
parent 57f02a43
<!DOCTYPE html>
<!--
Copyright (C) 2015 GRNET S.A.
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" />
<title>Agkyra</title>
<link rel="stylesheet" href="static/stylesheets/main.css" />
<script src="static/js/jquery.js"></script>
<script src="settings.js"></script>
<script type="text/javascript">var d = get_dialogue();</script>
</head>
<body>
<div class="wrapper"><form>
<h4 id="text">Do you agree to a fuzzy question which will be used against you in the future?</h4>
<div class="clearfix small-12 columns">
<a id="OK" class="button right" onclick="set_dialogue(d.msg, d.terms, true); window.close();">OK</a>
<a id="CANCEL" class="button right" onclick="window.close()">Cancel</a>
</div>
</form></div>
<script type="text/javascript">
document.getElementById('text').innerHTML = d.msg;
document.getElementById('OK').innerHTML = d.terms.OK;
document.getElementById('CANCEL').innerHTML = d.terms.CANCEL;
</script>
</body>
</html>
......@@ -31,7 +31,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var windows = {
"settings": null,
"about": null,
"index": gui.Window.get()
"index": gui.Window.get(),
"dialogue": null
}
function closeWindows() {
for (win in windows) if (windows[win]) windows[win].close();
......@@ -221,6 +222,7 @@ window.setInterval(function() {
var new_progress = COMMON.NOTIFICATION[globals.status.code];
var new_pause = '';
var tray_icon_off = false;
var dialogue_msg = null;
switch(globals.status.code) {
case STATUS['UNINITIALIZED']:
case STATUS['INITIALIZING']:
......@@ -252,11 +254,27 @@ window.setInterval(function() {
new_progress += ', '+ COMMON.MENU.REMAINING.replace(
'%s', remaining(globals.status));
break;
case STATUS['SETTINGS MISSING']:
case STATUS['AUTH URL ERROR']:
case STATUS['TOKEN ERROR']:
case STATUS['DIRECTORY ERROR']:
dialogue_msg = COMMON.DIALOGUE[globals.status.code].replace(
'%s', globals.settings.directory);
case STATUS['CONTAINER ERROR']:
if (!dialogue_msg)
dialogue_msg = COMMON.DIALOGUE[globals.status.code].replace(
'%s', globals.settings.container);
set_dialogue(dialogue_msg, COMMON.DIALOGUE, false);
if (windows.dialogue === null) {
windows['dialogue'] = gui.Window.open(
'dialogue.html', {
toolbar: false, focus: true,
width: 550, height: 220});
windows['dialogue'].on('closed', function() {
var d = get_dialogue();
if (d.response) post_force(socket);
});
}
case STATUS['AUTH URL ERROR']:
case STATUS['TOKEN ERROR']:
case STATUS['SETTINGS MISSING']:
deactivate_menu();
new_pause = COMMON.MENU.INACTIVE;
settings_menu.enabled = true;
......@@ -282,6 +300,7 @@ window.setInterval(function() {
tray.icon = tray_icon.off;
else if (!(tray_icon_off || tray.icon === tray_icon.on))
tray.icon = tray_icon.on;
get_status(socket);
}, 1500);
......
......@@ -33,15 +33,9 @@ var ntf_timeout = {
'error': 4000
}
var notify_menu = new gui.MenuItem({
label: 'Notifications',
icon: 'static/images/play_pause.png',
iconIsTemplate: false,
});
function notify_user(msg, level, ntf_title) {
var n = new Notification(ntf_title[level], {
lang: 'utf-8', body: msg, icon: ntf_icon[level]
});
setTimeout(n.close.bind(n), ntf_timeout[level]);
}
\ No newline at end of file
}
......@@ -79,6 +79,11 @@ function post_start(socket) {
send_json(socket, {'method': 'post', 'path': 'start'});
} // expected response: {"OK": 200}
function post_force(socket) {
log_debug('SEND post force');
send_json(socket, {'method': 'post', 'path': 'force'});
}
function get_settings(socket) {
send_json(socket, {'method': 'get', 'path': 'settings'});
} // expected response: {settings JSON}
......
......@@ -282,7 +282,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<input type="text" id="cloud-url" placeholder="Authentication URL"
onchange="
var identity_url = $(this).val().replace(/\/+$/, '');
settings['url'] = identity_url; refresh_endpoints(identity_url);
settings['url'] = identity_url;
refresh_endpoints(identity_url);
check_cloud_url();">
<small>Invalid entry</small>
</div>
......
......@@ -29,10 +29,18 @@ function get_setting(key) {
return global.settings[key];
}
function get_dialogue() {
return global.dialogue;
}
function set_setting(key, val) {
global.settings[key] = val;
}
function set_dialogue(msg, terms, response) {
global.dialogue = {msg: msg, terms: terms, response: response};
}
function refresh_endpoints(identity_url) {
$.post(identity_url + '/tokens', function(data) {
var endpoints = data.access.serviceCatalog
......
......@@ -225,6 +225,10 @@ class WebSocketProtocol(WebSocket):
GUI: {"method": "post", "path": "start"}
HELPER: {"OK": 200, "action": "post start"} or error
-- FORCE START --
GUI: {"method": "post", "path": "force"}
HELPER: {"OK": 200, "action": "post force"} or error
-- GET SETTINGS --
GUI: {"method": "get", "path": "settings"}
HELPER:
......@@ -459,13 +463,13 @@ class WebSocketProtocol(WebSocket):
# d.update(unsynced=0, synced=0, failed=0)
while msg:
if isinstance(msg, messaging.SyncMessage):
LOG.error('UNSYNCED +1 %s' % getattr(msg, 'objname', ''))
LOG.debug('UNSYNCED +1 %s' % getattr(msg, 'objname', ''))
self.set_status(unsynced=self.get_status('unsynced') + 1)
elif isinstance(msg, messaging.AckSyncMessage):
LOG.error('SYNCED +1 %s' % getattr(msg, 'objname', ''))
LOG.debug('SYNCED +1 %s' % getattr(msg, 'objname', ''))
self.set_status(synced=self.get_status('synced') + 1)
elif isinstance(msg, messaging.SyncErrorMessage):
LOG.error('FAILED +1 %s' % getattr(msg, 'objname', ''))
LOG.debug('FAILED +1 %s' % getattr(msg, 'objname', ''))
self.set_status(failed=self.get_status('failed') + 1)
elif isinstance(msg, messaging.LocalfsSyncDisabled):
self.set_status(code=STATUS['DIRECTORY ERROR'])
......@@ -527,7 +531,7 @@ class WebSocketProtocol(WebSocket):
local_ok = False
break
elif isinstance(msg, messaging.PithosSyncDisabled):
self.set_status(code=STATUS['CONTAINER ERRIR'])
self.set_status(code=STATUS['CONTAINER ERROR'])
remote_ok = False
break
elif isinstance(msg, messaging.LocalfsSyncEnabled):
......@@ -580,17 +584,26 @@ class WebSocketProtocol(WebSocket):
syncer_.wait_sync_threads()
def pause_sync(self):
"""Pause syncing (assuming it is up and running)"""
if self.syncer:
self.syncer.stop_decide()
self.set_status(code=STATUS['PAUSING'])
# syncer_ = self.syncer
# if syncer_ and not syncer_.paused:
# Thread(target=self._pause_syncer).start()
# self.set_status(code=STATUS['PAUSING'])
def start_sync(self):
"""Start syncing"""
self.syncer.start_decide()
def force_sync(self):
"""Force syncing, assuming there is a directory or container problem"""
self.set_status(code=STATUS['INITIALIZING'])
self.syncer_settings.purge_db_archives_and_enable()
self.init_sync()
if self.syncer:
self.syncer.start_decide()
self.set_status(code=STATUS['SYNCING'])
else:
self.set_status(code=STATUS['CRITICAL ERROR'])
def send_json(self, msg):
LOG.debug('send: %s' % msg)
self.send(json.dumps(msg))
......@@ -609,7 +622,8 @@ class WebSocketProtocol(WebSocket):
return
{
'start': self.start_sync,
'pause': self.pause_sync
'pause': self.pause_sync,
'force': self.force_sync
}[action]()
self.send_json({'OK': 200, 'action': 'post %s' % action})
elif r['ui_id'] == self.ui_id:
......
......@@ -13,6 +13,12 @@
"CONTAINER ERROR": 204,
"CRITICAL ERROR": 1000
},
"DIALOGUE": {
"203": "Ο τοπικός φάκελος \"%s\" δεν υπάρχει. Επιθυμείτε τη δημιουργία νέου και την επανεκίνηση του συγχρονισμού;",
"204": "Ο απομακρυσμένος περιέκτης (container) \"%s\" δεν υπάρχει. Επιθυμείτε τη δημιουργία νέου και την επανεκίνηση του συγχρονισμού;",
"OK": "Εντάξει",
"CANCEL": "Άκυρο"
},
"NOTIFICATION": {
"0": "Ανενεργό",
"1": "Εκκίνηση ...",
......
......@@ -27,6 +27,12 @@
"204": "Remote container error",
"1000": "Critical error"
},
"DIALOGUE": {
"203": "Local directory \"%s\" does not exist. Would you like Agkyra to create a new one and restart the syncing process?",
"204": "Remote container \"%s\" does not exist. Would you like Agkyra to create a new one and restart the syncing process?",
"OK": "OK",
"CANCEL": "Cancel"
},
"MENU": {
"TITLE": "Agkyra Syncing Client",
"START": "Start syncing",
......
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