diff --git a/app/admin.py b/app/admin.py
index aa5f7ee7..b8214400 100644
--- a/app/admin.py
+++ b/app/admin.py
@@ -149,7 +149,9 @@ class PluginAdmin(admin.ModelAdmin):
def plugin_disable(self, request, plugin_name, *args, **kwargs):
try:
- disable_plugin(plugin_name)
+ p = disable_plugin(plugin_name)
+ if p.requires_restart():
+ messages.warning(request, _("Restart required. Please restart WebODM to fully disable %(plugin)s") % {'plugin': plugin_name})
except Exception as e:
messages.warning(request, _("Cannot disable plugin %(plugin)s: %(message)s") % {'plugin': plugin_name, 'message': str(e)})
diff --git a/app/plugins/functions.py b/app/plugins/functions.py
index d11c23ca..1ca0384d 100644
--- a/app/plugins/functions.py
+++ b/app/plugins/functions.py
@@ -328,7 +328,9 @@ def enable_plugin(plugin_name):
return p
def disable_plugin(plugin_name):
+ p = get_plugin_by_name(plugin_name, only_active=False)
Plugin.objects.get(pk=plugin_name).disable()
+ return p
def delete_plugin(plugin_name):
Plugin.objects.get(pk=plugin_name).delete()
diff --git a/app/static/app/js/components/ClipboardInput.jsx b/app/static/app/js/components/ClipboardInput.jsx
index c9235ee8..c83efa97 100644
--- a/app/static/app/js/components/ClipboardInput.jsx
+++ b/app/static/app/js/components/ClipboardInput.jsx
@@ -30,6 +30,7 @@ class ClipboardInput extends React.Component{
{ this.dom = domNode; }}
+ title={this.props.value || ""}
onBlur={() => { this.setState({showCopied: false}); }}
/>
diff --git a/coreplugins/shortlinks/api.py b/coreplugins/shortlinks/api.py
index db62fdd0..f35b6a7a 100644
--- a/coreplugins/shortlinks/api.py
+++ b/coreplugins/shortlinks/api.py
@@ -3,11 +3,16 @@ import math
from rest_framework import status
from rest_framework.response import Response
from app.plugins.views import TaskView
-from app.plugins import get_current_plugin
+from app.plugins import get_current_plugin, signals as plugin_signals
+from django.dispatch import receiver
from app.plugins import GlobalDataStore
from django.http import Http404
from django.shortcuts import redirect
+import logging
+
+logger = logging.getLogger('app.logger')
+
ds = GlobalDataStore('shortlinks')
def gen_short_string(num):
@@ -55,4 +60,12 @@ def HandleShortLink(request, view_type, short_id):
return redirect('/public/task/{}/{}/'.format(task_id, v))
else:
- raise Http404()
\ No newline at end of file
+ raise Http404()
+
+@receiver(plugin_signals.task_removed, dispatch_uid="shortlinks_on_task_removed")
+def shortlinks_cleanup(sender, task_id, **kwargs):
+ short_id = ds.get_string(task_id)
+ if short_id:
+ logger.info("Cleaning up shortlinks datastore for task {}".format(str(task_id)))
+ ds.del_key(task_id)
+ ds.del_key(short_id)
diff --git a/coreplugins/shortlinks/plugin.py b/coreplugins/shortlinks/plugin.py
index 8e9bf862..54f8a60c 100644
--- a/coreplugins/shortlinks/plugin.py
+++ b/coreplugins/shortlinks/plugin.py
@@ -10,7 +10,7 @@ class Plugin(PluginBase):
def include_js_files(self):
return ['main.js']
-
+
def root_mount_points(self):
return [
MountPoint(r'^s(?P[m3])(?P[a-z0-9]+)/?$', HandleShortLink)
diff --git a/coreplugins/shortlinks/public/SLCheckbox.jsx b/coreplugins/shortlinks/public/SLCheckbox.jsx
index 1cc78b0f..8c50e799 100644
--- a/coreplugins/shortlinks/public/SLCheckbox.jsx
+++ b/coreplugins/shortlinks/public/SLCheckbox.jsx
@@ -63,17 +63,13 @@ export default class SLCheckbox extends React.Component{
if (error) return ();
- return (