Skip to content

Commit

Permalink
Merge pull request #965 from Morg42/db-2
Browse files Browse the repository at this point in the history
database: change reassignment selection to modal dialogue
  • Loading branch information
Morg42 authored Nov 3, 2024
2 parents e5fda4b + 4213579 commit c97395e
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 6 deletions.
37 changes: 35 additions & 2 deletions database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Database(SmartPlugin):
"""

ALLOW_MULTIINSTANCE = True
PLUGIN_VERSION = '1.6.12'
PLUGIN_VERSION = '1.6.13'

# SQL queries: {item} = item table name, {log} = log table name
# time, item_id, val_str, val_num, val_bool, changed
Expand Down Expand Up @@ -104,6 +104,7 @@ def __init__(self, sh, *args, **kwargs):
self._precision = self.get_parameter_value('precision')
self.count_logentries = self.get_parameter_value('count_logentries')
self.max_delete_logentries = self.get_parameter_value('max_delete_logentries')
self.max_reassign_logentries = self.get_parameter_value('max_reassign_logentries')
self._default_maxage = float(self.get_parameter_value('default_maxage'))

self._copy_database = self.get_parameter_value('copy_database')
Expand Down Expand Up @@ -967,6 +968,38 @@ def _count_orphanlogentries(self):
return


def reassign_orphaned_id(self, orphan_id, to):
"""
Reassign values from orphaned item ID to given item ID
:param orphan_id: item id of the orphaned item
:param to: item id of the target item
:type orphan_id: int
:type to: int
"""
log_info = self.logger.warning # info
log_debug = self.logger.error # debug
try:
log_info(f'reassigning orphaned data from (old) id {orphan_id} to (new) id {to}')
cur = self._db_maint.cursor()
count = self.readLogCount(orphan_id, cur=cur)
log_debug(f'found {count} entries to reassign, reassigning {self.max_reassign_logentries} at once')

while count > 0:
log_debug(f'reassigning {min(count, self.max_reassign_logentries)} log entries')
self._execute(self._prepare("UPDATE {log} SET item_id = :newid WHERE item_id = :orphanid LIMIT :limit;"), {'newid': to, 'orphanid': orphan_id, 'limit': self.max_reassign_logentries}, cur=cur)
count -= self.max_reassign_logentries

self._execute(self._prepare("DELETE FROM {item} WHERE id = :orphanid LIMIT 1;"), {'orphanid': orphan_id}, cur=cur)
log_info(f'reassigned orphaned id {orphan_id} to new id {to}')
cur.close()
self._db_maint.commit()
log_debug('rebuilding orphan list')
self.build_orphanlist()
except Exception as e:
self.logger.error(f'error on reassigning id {orphan_id} to {to}: {e}')
return e

def _delete_orphan(self, item_path):
"""
Delete orphan item or logentries it
Expand Down Expand Up @@ -1184,7 +1217,7 @@ def _expression(self, func):
expression['finalizer'] = func[:func.index(":")]
func = func[func.index(":") + 1:]
if func == 'count' or func.startswith('count'):
parts = re.match('(count)((<>|!=|<|=|>)(\d+))?', func)
parts = re.match(r'(count)((<>|!=|<|=|>)(\d+))?', func)
func = 'count'
if parts and parts.group(3) is not None:
expression['params']['op'] = parts.group(3)
Expand Down
10 changes: 9 additions & 1 deletion database/plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugin:
keywords: database
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1021844-neues-database-plugin

version: 1.6.12 # Plugin version
version: 1.6.13 # Plugin version
sh_minversion: '1.9.3.2' # minimum shNG version to use this plugin
# sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest)
multi_instance: True # plugin supports multi instance
Expand Down Expand Up @@ -72,6 +72,14 @@ parameters:
de: "Maximal auf einmal zu löschende Anzahl an Log Einträgen mit dem database_maxage Attribut, reduziert die Belastung der Datenbank bei alten Datenbeständen"
en: "Maximum number of Logentries to delete at once with database_maxage attribute, reduces load on database with old datasets"

max_reassign_logentries:
type: int
default: 20 # 000
valid_min: 10 # 00
description:
de: "Maximal auf einmal neu zuzuweisende Anzahl an Log Einträgen, reduziert die Belastung der Datenbank bei großen Datenbeständen"
en: "Maximum number of Logentries to reassign at once, reduces load on database with large datasets"

default_maxage:
type: int
default: 0
Expand Down
23 changes: 22 additions & 1 deletion database/webif/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,28 @@ def index(self, reload=None, action=None, item_id=None, item_path=None, time_end
tabcount=2, action=action, item_id=item_id, delete_triggered=delete_triggered,
language=self.plugin.get_sh().get_defaultlanguage())

@cherrypy.expose
def reassign(self):
cl = cherrypy.request.headers['Content-Length']
if not cl:
return
try:
rawbody = cherrypy.request.body.read(int(cl))
data = json.loads(rawbody)
except Exception:
return
orphan_id = data.get("orphan_id")
new_id = data.get("new_id")
result = {"operation": "request", "result": "success"}
if orphan_id is not None and new_id is not None and orphan_id != new_id:
self.logger.info(f'reassigning orphaned id {orphan_id} to new id {new_id}')
err = self.plugin.reassign_orphaned_id(orphan_id, to=new_id)
if err:
return
return json.dumps(result)
else:
self.logger.warning(f'reassigning orphaned id {orphan_id} to new id {new_id} failed')

@cherrypy.expose
def get_data_html(self, dataSet=None, params=None):
"""
Expand Down Expand Up @@ -271,7 +293,6 @@ def db_sqldump(self):

return


@cherrypy.expose
def cleanup(self):
self.plugin.cleanup()
Expand Down
37 changes: 37 additions & 0 deletions database/webif/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* The Modal (background) */
.or-modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 999; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}

/* Modal Content/Box */
.or-modal-content {
background-color: #fefefe;
margin: 15% auto; /* 15% from the top and centered */
padding: 20px;
border: 1px solid #888;
width: 80%; /* Could be more or less, depending on screen size */
}

/* The Close Button */
.or-close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}

.or-close:hover,
.or-close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
4 changes: 3 additions & 1 deletion database/webif/templates/base_database.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
{ className: "time", targets: 2 },
{ className: "type", targets: 3 },
{ className: "id", targets: 4, render: $.fn.dataTable.render.number('.', ',', 0, '') },
{ className: "logcount", targets: 5, render: $.fn.dataTable.render.number('.', ',', 0, '') },
{ className: "reassign", targets: 5 },
{ className: "logcount", targets: 6, render: $.fn.dataTable.render.number('.', ',', 0, '') },
].concat($.fn.dataTable.defaults.columnDefs)});
{% else %}
orphantable = $('#orphantable').DataTable( {
Expand All @@ -42,6 +43,7 @@
{ className: "time", targets: 2 },
{ className: "type", targets: 3 },
{ className: "id", targets: 4, render: $.fn.dataTable.render.number('.', ',', 0, '') },
{ className: "reassign", targets: 5 },
].concat($.fn.dataTable.defaults.columnDefs)});
{% endif %}

Expand Down
68 changes: 67 additions & 1 deletion database/webif/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
{% set dataSet = 'overview' %}
{% set tab1title = _('Database Items') %}

{% block pluginstyles %}
<link rel="stylesheet" href="static/style.css">
{% endblock pluginstyles %}

{%- block pluginscripts %}
{{ super() }}
<script>
Expand Down Expand Up @@ -158,6 +162,63 @@

{% set tab3title = _('Verwaiste Items') %}
{% block bodytab3 %}

<script type="text/javascript">
function reassignOrphan(selObj) {
// get modal box data from elements
var orphanID = document.getElementById('orphan-item-id').textContent;
var orphanItem = document.getElementById('orphan-item-name').textContent;
var newID = document.getElementById('orphanSelect').value;
var newItem = document.getElementById('orphanSelect').selectedOptions[0].text;

// reset elements (just to be sure...)
document.getElementById('orphan-item-id').textContent = "";
document.getElementById('orphan-item-name').textContent = "";
document.getElementById('orphanSelect').selectedIndex = 0;

var mydata = {"orphan_id": orphanID, "new_id": newID};
$.ajax({
type: "POST",
url: "reassign",
data: JSON.stringify(mydata),
contentType: 'application/json',
dataType: 'json',
error: function() {
alert("Fehler beim Übermitteln der Daten. Bitte shng-Log prüfen!");
document.getElementById('orphanModal').style.display = 'none';
},
success: function() {
document.getElementById('orphanModal').style.display = 'none';
// reload page to reflect recalculated orphans
setTimeout(window.location.reload(), 3000);
}
})
}
</script>

<div id="orphanModal" class="or-modal">
<div class="or-modal-content">
<span class="or-close" onclick="document.getElementById('orphanModal').style.display = 'none';">&times;</span>
<div>
<strong>Neuzuweisen von Itemreihe <span id='orphan-item-name'></span> (ID <span id='orphan-item-id'></span>)</strong>
</div>
<div>
<span>Bitte wählen Sie die Itemreihe aus, der die verwaisten Daten zugewiesen werden sollen: </span>
<select id="orphanSelect" name="{{ item }}_reassign" onchange="btn = document.getElementById('orphanAssignBtn'); if (this.value == -1) { btn.disabled = true; } else { btn.disabled = false; }">
<option value=-1 selected="selected"></option>
{% for newitem in items %}
{% set newitemid = p.id(newitem, create=False) %}
{% if p.has_iattr(newitem.conf, 'database') %}
<option value={{ newitemid }}>{{ newitem.property.path }} ({{ newitemid }})</option>
{% endif %}
{% endfor %}
</select>
<button type="button" id="orphanAssignBtn" disabled class="btn btn-danger btn-sm" onclick="reassignOrphan()">Zuweisen</button>
<button type="button" class="btn btn-shng btn-sm" onclick="document.getElementById('orphanModal').style.display = 'none';">Abbrechen</button>
</div>
</div>
</div>

<div class="container-fluid m-2 table-resize">
<div id="webif-orphanbuttons" style="margin-left: 10px; margin-bottom: 10px; float:right; white-space: nowrap;" class="mb-2">
{% if p.remove_orphan or len(p.orphanlist) == 0 %}
Expand All @@ -174,13 +235,15 @@
<th>{{ _('Letzte Änderung') }}</th>
<th>{{ _('Typ') }}</th>
<th class="dt-head-right" title="{{ _('Item-ID in der Datenbank') }}">{{ _('DB-ID') }}</th>
<th>{{ _('Neuzuweisung') }}</th>
{% if p.count_logentries %}
<th class="logcount dt-head-right">{{ _('Anzahl Einträge') }}</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for item in p.orphanlist %}
{% set itemid = p.id(item, create=False) %}
<tr>
<td></td>
<td id="{{ item }}_orphan_path">{{ item }}</td>
Expand All @@ -199,7 +262,10 @@
{% endif %}
{% endif %}</td>
<td id="{{ item }}_orphan_type">{{ _(p.db_itemtype(item)) }}</td>
<td id="{{ item }}_orphan_id">{{ p.id(item, create=False) }}</td>
<td id="{{ item }}_orphan_id">{{ itemid }}</td>
<td id="{{ item }}_orphan_reassign">
<button type="button" id="orphanBtn" class="btn btn-danger btn-sm" value="{{ itemid }}-{{ item }}" onclick="document.getElementById('orphan-item-name').textContent = '{{ item }}'; document.getElementById('orphan-item-id').textContent = '{{ itemid }}'; document.getElementById('orphanModal').style.display = 'block';"><i class="fas fa-share"></i></button>
</td>
{% if p.count_logentries %}
<td id="{{ item }}_orphan_logcount">{{ p._orphan_logcount[p.id(item, create=False)] }}</td>
{% endif %}
Expand Down

0 comments on commit c97395e

Please sign in to comment.