Improve new logging stuff further
This commit is contained in:
parent
e7316ea282
commit
32f08120c2
@ -1,6 +1,7 @@
|
|||||||
#include "newlogsmodel.h"
|
#include "newlogsmodel.h"
|
||||||
|
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
#include "logmanager.h"
|
||||||
|
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
//NYMEA_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
|
//NYMEA_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
|
||||||
@ -58,7 +59,8 @@ void NewLogsModel::componentComplete()
|
|||||||
bool NewLogsModel::canFetchMore(const QModelIndex &parent) const
|
bool NewLogsModel::canFetchMore(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
return m_canFetchMore && m_sources.count() == 1;
|
// Cannot fetchMore when there are multiple sources as paging doesn't really work in that case
|
||||||
|
return m_canFetchMore && (m_sources.count() == 1 || m_list.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewLogsModel::fetchMore(const QModelIndex &parent)
|
void NewLogsModel::fetchMore(const QModelIndex &parent)
|
||||||
@ -83,13 +85,19 @@ Engine *NewLogsModel::engine() const
|
|||||||
|
|
||||||
void NewLogsModel::setEngine(Engine *engine)
|
void NewLogsModel::setEngine(Engine *engine)
|
||||||
{
|
{
|
||||||
if (m_engine != engine) {
|
if (m_engine == engine) {
|
||||||
m_engine = engine;
|
return;
|
||||||
emit engineChanged();
|
}
|
||||||
|
|
||||||
// if (m_completed && m_canFetchMore) {
|
if (m_engine) {
|
||||||
// fetchMore();
|
disconnect(m_engine->logManager(), &LogManager::logEntryReceived, this, &NewLogsModel::newLogEntryReceived);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
m_engine = engine;
|
||||||
|
emit engineChanged();
|
||||||
|
|
||||||
|
if (m_engine) {
|
||||||
|
connect(m_engine->logManager(), &LogManager::logEntryReceived, this, &NewLogsModel::newLogEntryReceived);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +211,32 @@ bool NewLogsModel::busy() const
|
|||||||
return m_busy;
|
return m_busy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NewLogsModel::live() const
|
||||||
|
{
|
||||||
|
return m_live;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewLogsModel::setLive(bool live)
|
||||||
|
{
|
||||||
|
if (m_live != live) {
|
||||||
|
m_live = live;
|
||||||
|
emit liveChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int NewLogsModel::fetchBlockSize() const
|
||||||
|
{
|
||||||
|
return m_blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewLogsModel::setFetchBlockSize(int fetchBlockSize)
|
||||||
|
{
|
||||||
|
if (m_blockSize != fetchBlockSize) {
|
||||||
|
m_blockSize = fetchBlockSize;
|
||||||
|
emit fetchBlockSizeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NewLogEntry *NewLogsModel::get(int index) const
|
NewLogEntry *NewLogsModel::get(int index) const
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_list.count()) {
|
if (index < 0 || index >= m_list.count()) {
|
||||||
@ -266,6 +300,8 @@ void NewLogsModel::clear()
|
|||||||
beginResetModel();
|
beginResetModel();
|
||||||
qDeleteAll(m_list);
|
qDeleteAll(m_list);
|
||||||
m_list.clear();
|
m_list.clear();
|
||||||
|
m_currentNewest = QDateTime();
|
||||||
|
m_lastOffset = 0;
|
||||||
endResetModel();
|
endResetModel();
|
||||||
emit countChanged();
|
emit countChanged();
|
||||||
emit entriesRemoved(0, count);
|
emit entriesRemoved(0, count);
|
||||||
@ -292,17 +328,13 @@ void NewLogsModel::fetchLogs()
|
|||||||
} else {
|
} else {
|
||||||
params.insert("limit", m_blockSize);
|
params.insert("limit", m_blockSize);
|
||||||
if (m_list.count() > 0) {
|
if (m_list.count() > 0) {
|
||||||
params.insert("offset", m_lastOffset);
|
if (m_currentNewest.isNull()) {
|
||||||
if (m_lastOffset == 0) {
|
m_currentNewest = QDateTime::currentDateTime();
|
||||||
if (m_endTime.isNull()) {
|
|
||||||
m_currentNewest = QDateTime::currentDateTime();
|
|
||||||
} else {
|
|
||||||
m_currentNewest = m_endTime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
params.insert("offset", m_lastOffset);
|
||||||
params.insert("endTime", m_currentNewest.toMSecsSinceEpoch());
|
params.insert("endTime", m_currentNewest.toMSecsSinceEpoch());
|
||||||
m_lastOffset += m_blockSize;
|
|
||||||
}
|
}
|
||||||
|
m_lastOffset += m_blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -367,8 +399,31 @@ void NewLogsModel::logsReply(int commandId, const QVariantMap &data)
|
|||||||
});
|
});
|
||||||
m_list.append(entries);
|
m_list.append(entries);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
emit entriesAdded(m_list.count(), entries);
|
emit entriesAdded(m_list.count() - entries.count(), entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit countChanged();
|
emit countChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewLogsModel::newLogEntryReceived(const QVariantMap &map)
|
||||||
|
{
|
||||||
|
QString source = map.value("source").toString();
|
||||||
|
QDateTime timestamp = QDateTime::fromMSecsSinceEpoch(map.value("timestamp").toULongLong());
|
||||||
|
QVariantMap values = map.value("values").toMap();
|
||||||
|
|
||||||
|
if (m_sources.contains(source) && m_sampleRate == SampleRateAny) {
|
||||||
|
NewLogEntry *entry = new NewLogEntry(source, timestamp, values, this);
|
||||||
|
if (m_sortOrder == Qt::AscendingOrder) {
|
||||||
|
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
|
||||||
|
m_list.append(entry);
|
||||||
|
endInsertRows();
|
||||||
|
emit entriesAdded(m_list.count() - 1, {entry});
|
||||||
|
} else {
|
||||||
|
beginInsertRows(QModelIndex(), 0, 0);
|
||||||
|
m_list.prepend(entry);
|
||||||
|
endInsertRows();
|
||||||
|
emit entriesAdded(0, {entry});
|
||||||
|
}
|
||||||
|
emit countChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -21,9 +21,11 @@ class NewLogsModel : public QAbstractListModel, public QQmlParserStatus
|
|||||||
Q_PROPERTY(SampleRate sampleRate READ sampleRate WRITE setSampleRate NOTIFY sampleRateChanged)
|
Q_PROPERTY(SampleRate sampleRate READ sampleRate WRITE setSampleRate NOTIFY sampleRateChanged)
|
||||||
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
|
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(int fetchBlockSize READ fetchBlockSize WRITE setFetchBlockSize NOTIFY fetchBlockSizeChanged)
|
||||||
|
Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged)
|
||||||
|
|
||||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||||
// Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Role {
|
enum Role {
|
||||||
@ -85,6 +87,12 @@ public:
|
|||||||
|
|
||||||
bool busy() const;
|
bool busy() const;
|
||||||
|
|
||||||
|
bool live() const;
|
||||||
|
void setLive(bool live);
|
||||||
|
|
||||||
|
int fetchBlockSize() const;
|
||||||
|
void setFetchBlockSize(int fetchBlockSize);
|
||||||
|
|
||||||
Q_INVOKABLE NewLogEntry *get(int index) const;
|
Q_INVOKABLE NewLogEntry *get(int index) const;
|
||||||
Q_INVOKABLE NewLogEntry *find(const QDateTime ×tamp) const;
|
Q_INVOKABLE NewLogEntry *find(const QDateTime ×tamp) const;
|
||||||
|
|
||||||
@ -107,11 +115,15 @@ signals:
|
|||||||
void sampleRateChanged();
|
void sampleRateChanged();
|
||||||
void sortOrderChanged();
|
void sortOrderChanged();
|
||||||
|
|
||||||
|
void liveChanged();
|
||||||
|
void fetchBlockSizeChanged();
|
||||||
|
|
||||||
void entriesAdded(int index, const QList<NewLogEntry*> &entries);
|
void entriesAdded(int index, const QList<NewLogEntry*> &entries);
|
||||||
void entriesRemoved(int index, int count);
|
void entriesRemoved(int index, int count);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void logsReply(int commandId, const QVariantMap &data);
|
void logsReply(int commandId, const QVariantMap &data);
|
||||||
|
void newLogEntryReceived(const QVariantMap &map);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Engine *m_engine = nullptr;
|
Engine *m_engine = nullptr;
|
||||||
@ -122,6 +134,8 @@ private:
|
|||||||
|
|
||||||
bool m_busy = false;
|
bool m_busy = false;
|
||||||
|
|
||||||
|
bool m_live = true;
|
||||||
|
|
||||||
// For time based sampling
|
// For time based sampling
|
||||||
QDateTime m_startTime;
|
QDateTime m_startTime;
|
||||||
QDateTime m_endTime;
|
QDateTime m_endTime;
|
||||||
@ -130,7 +144,7 @@ private:
|
|||||||
// For continuous scrolling lists
|
// For continuous scrolling lists
|
||||||
bool m_completed = false;
|
bool m_completed = false;
|
||||||
bool m_canFetchMore = true;
|
bool m_canFetchMore = true;
|
||||||
int m_blockSize = 5;
|
int m_blockSize = 50;
|
||||||
int m_lastOffset = 0;
|
int m_lastOffset = 0;
|
||||||
QDateTime m_currentNewest;
|
QDateTime m_currentNewest;
|
||||||
|
|
||||||
|
|||||||
@ -973,12 +973,14 @@ Thing* ThingManager::unpackThing(ThingManager *thingManager, const QVariantMap &
|
|||||||
loggedEventTypeIds.append(uuid.toUuid());
|
loggedEventTypeIds.append(uuid.toUuid());
|
||||||
}
|
}
|
||||||
thing->setLoggedEventTypeIds(loggedEventTypeIds);
|
thing->setLoggedEventTypeIds(loggedEventTypeIds);
|
||||||
|
QList<QUuid> loggedActionTypeIds;
|
||||||
|
foreach (const QVariant &uuid, thingMap.value("loggedActionTypeIds").toList()) {
|
||||||
|
loggedActionTypeIds.append(uuid.toUuid());
|
||||||
|
}
|
||||||
|
thing->setLoggedActionTypeIds(loggedActionTypeIds);
|
||||||
return thing;
|
return thing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QVariantMap ThingManager::packParam(Param *param)
|
QVariantMap ThingManager::packParam(Param *param)
|
||||||
{
|
{
|
||||||
QVariantMap ret;
|
QVariantMap ret;
|
||||||
|
|||||||
@ -244,6 +244,19 @@ void Thing::setLoggedEventTypeIds(const QList<QUuid> &loggedEventTypeIds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QUuid> Thing::loggedActionTypeIds() const
|
||||||
|
{
|
||||||
|
return m_loggedActionTypeIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thing::setLoggedActionTypeIds(const QList<QUuid> &loggedActionTypeIds)
|
||||||
|
{
|
||||||
|
if (m_loggedActionTypeIds != loggedActionTypeIds) {
|
||||||
|
m_loggedActionTypeIds = loggedActionTypeIds;
|
||||||
|
emit loggedActionTypeIdsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int Thing::executeAction(const QString &actionName, const QVariantList ¶ms)
|
int Thing::executeAction(const QString &actionName, const QVariantList ¶ms)
|
||||||
{
|
{
|
||||||
ActionType *actionType = m_thingClass->actionTypes()->findByName(actionName);
|
ActionType *actionType = m_thingClass->actionTypes()->findByName(actionName);
|
||||||
|
|||||||
@ -57,6 +57,7 @@ class Thing : public QObject
|
|||||||
Q_PROPERTY(ThingClass *thingClass READ thingClass CONSTANT)
|
Q_PROPERTY(ThingClass *thingClass READ thingClass CONSTANT)
|
||||||
Q_PROPERTY(QList<QUuid> loggedStateTypeIds READ loggedStateTypeIds NOTIFY loggedStateTypeIdsChanged)
|
Q_PROPERTY(QList<QUuid> loggedStateTypeIds READ loggedStateTypeIds NOTIFY loggedStateTypeIdsChanged)
|
||||||
Q_PROPERTY(QList<QUuid> loggedEventTypeIds READ loggedEventTypeIds NOTIFY loggedEventTypeIdsChanged)
|
Q_PROPERTY(QList<QUuid> loggedEventTypeIds READ loggedEventTypeIds NOTIFY loggedEventTypeIdsChanged)
|
||||||
|
Q_PROPERTY(QList<QUuid> loggedActionTypeIds READ loggedActionTypeIds NOTIFY loggedActionTypeIdsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ThingSetupStatus {
|
enum ThingSetupStatus {
|
||||||
@ -130,6 +131,9 @@ public:
|
|||||||
QList<QUuid> loggedEventTypeIds() const;
|
QList<QUuid> loggedEventTypeIds() const;
|
||||||
void setLoggedEventTypeIds(const QList<QUuid> &loggedEventTypeIds);
|
void setLoggedEventTypeIds(const QList<QUuid> &loggedEventTypeIds);
|
||||||
|
|
||||||
|
QList<QUuid> loggedActionTypeIds() const;
|
||||||
|
void setLoggedActionTypeIds(const QList<QUuid> &loggedActionTypeIds);
|
||||||
|
|
||||||
ThingClass *thingClass() const;
|
ThingClass *thingClass() const;
|
||||||
|
|
||||||
Q_INVOKABLE bool hasState(const QUuid &stateTypeId) const;
|
Q_INVOKABLE bool hasState(const QUuid &stateTypeId) const;
|
||||||
@ -150,6 +154,7 @@ signals:
|
|||||||
void statesChanged();
|
void statesChanged();
|
||||||
void loggedStateTypeIdsChanged();
|
void loggedStateTypeIdsChanged();
|
||||||
void loggedEventTypeIdsChanged();
|
void loggedEventTypeIdsChanged();
|
||||||
|
void loggedActionTypeIdsChanged();
|
||||||
void eventTriggered(const QUuid &eventTypeId, const QVariantList ¶ms);
|
void eventTriggered(const QUuid &eventTypeId, const QVariantList ¶ms);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -168,6 +173,7 @@ protected:
|
|||||||
ThingClass *m_thingClass = nullptr;
|
ThingClass *m_thingClass = nullptr;
|
||||||
QList<QUuid> m_loggedStateTypeIds;
|
QList<QUuid> m_loggedStateTypeIds;
|
||||||
QList<QUuid> m_loggedEventTypeIds;
|
QList<QUuid> m_loggedEventTypeIds;
|
||||||
|
QList<QUuid> m_loggedActionTypeIds;
|
||||||
|
|
||||||
QList<int> m_pendingActions;
|
QList<int> m_pendingActions;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -312,5 +312,7 @@
|
|||||||
<file>ui/customviews/StateChart.qml</file>
|
<file>ui/customviews/StateChart.qml</file>
|
||||||
<file>ui/devicepages/ThingLogPage.qml</file>
|
<file>ui/devicepages/ThingLogPage.qml</file>
|
||||||
<file>ui/devicepages/NotificationsThingPage.qml</file>
|
<file>ui/devicepages/NotificationsThingPage.qml</file>
|
||||||
|
<file>ui/devicepages/ActionLogPage.qml</file>
|
||||||
|
<file>ui/devicepages/EventLogPage.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
163
nymea-app/ui/devicepages/ActionLogPage.qml
Normal file
163
nymea-app/ui/devicepages/ActionLogPage.qml
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*
|
||||||
|
* Copyright 2013 - 2023, nymea GmbH
|
||||||
|
* Contact: contact@nymea.io
|
||||||
|
*
|
||||||
|
* This file is part of nymea.
|
||||||
|
* This project including source code and documentation is protected by
|
||||||
|
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||||
|
* reproduction, publication, editing and translation, are reserved. The use of
|
||||||
|
* this project is subject to the terms of a license agreement to be concluded
|
||||||
|
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||||
|
* under https://nymea.io/license
|
||||||
|
*
|
||||||
|
* GNU General Public License Usage
|
||||||
|
* Alternatively, this project may be redistributed and/or modified under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, GNU version 3. This project 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 project. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* For any further details and any questions please contact us under
|
||||||
|
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||||
|
* https://nymea.io/license/faq
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import Nymea 1.0
|
||||||
|
import "../components"
|
||||||
|
import "../customviews"
|
||||||
|
|
||||||
|
Page {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property Thing thing: null
|
||||||
|
property ActionType actionType: null
|
||||||
|
|
||||||
|
readonly property bool isLogged: thing.loggedActionTypeIds.indexOf(actionType.id) >= 0
|
||||||
|
|
||||||
|
header: NymeaHeader {
|
||||||
|
text: qsTr("History for %1").arg(root.actionType.displayName)
|
||||||
|
onBackPressed: pageStack.pop()
|
||||||
|
|
||||||
|
HeaderButton {
|
||||||
|
imageSource: "delete"
|
||||||
|
visible: root.isLogged
|
||||||
|
onClicked: {
|
||||||
|
var popup = deleteLogsComponent.createObject(root)
|
||||||
|
popup.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: deleteLogsComponent
|
||||||
|
NymeaDialog {
|
||||||
|
title: qsTr("Remove logs?")
|
||||||
|
text: qsTr("Do you want to remove the log for this action and disable logging?")
|
||||||
|
standardButtons: Dialog.No | Dialog.Yes
|
||||||
|
onAccepted: engine.thingManager.setActionLogging(root.thing.id, root.actionType.id, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NewLogsModel {
|
||||||
|
id: logsModel
|
||||||
|
engine: _engine
|
||||||
|
source: "action-" + root.thing.id + "-" + root.actionType.name
|
||||||
|
sortOrder: Qt.DescendingOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listView
|
||||||
|
visible: root.isLogged
|
||||||
|
model: logsModel
|
||||||
|
clip: true
|
||||||
|
anchors.fill: parent
|
||||||
|
ScrollBar.vertical: ScrollBar {}
|
||||||
|
|
||||||
|
delegate: NymeaItemDelegate {
|
||||||
|
id: delegate
|
||||||
|
width: listView.width
|
||||||
|
height: contentColumn.implicitHeight + Style.margins
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
topPadding: 0
|
||||||
|
bottomPadding: 0
|
||||||
|
property NewLogEntry entry: logsModel.get(index)
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
id: contentColumn
|
||||||
|
anchors { left: parent.left; right: parent.right; margins: app.margins / 2 }
|
||||||
|
ColorIcon {
|
||||||
|
Layout.preferredWidth: Style.iconSize
|
||||||
|
Layout.preferredHeight: width
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
color: delegate.entry.values.status === "ThingErrorNoError"
|
||||||
|
? Style.iconColor
|
||||||
|
: Style.red
|
||||||
|
name: delegate.entry.values.triggeredBy === "TriggeredByUser"
|
||||||
|
? "account"
|
||||||
|
: "magic"
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: (delegate.entry.values.triggeredBy === "TriggeredByUser" ? qsTr("User action") : qsTr("Automation"))
|
||||||
|
+ " - "
|
||||||
|
+ (delegate.entry.values.status === "ThingErrorNoError" ? qsTr("success") : qsTr("Failure: %1").arg(delegate.entry.values.status))
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: Qt.formatDateTime(model.timestamp,"dd.MM.yy - hh:mm:ss")
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: Style.smallFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: {
|
||||||
|
var ret = []
|
||||||
|
var values = JSON.parse(entry.values.params)
|
||||||
|
for (var i = 0; i < root.actionType.paramTypes.count; i++) {
|
||||||
|
var paramType = root.actionType.paramTypes.get(i)
|
||||||
|
ret.push(paramType.displayName + ": " + Types.toUiValue(values[paramType.name], paramType.unit) + " " + Types.toUiUnit(paramType.unit))
|
||||||
|
}
|
||||||
|
return ret.join("<br>")
|
||||||
|
}
|
||||||
|
textFormat: Text.RichText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: Style.smallFont
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyViewPlaceholder {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - app.margins * 2
|
||||||
|
title: qsTr("Logging not enabled")
|
||||||
|
text: qsTr("This state is not being logged.")
|
||||||
|
imageSource: "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle)
|
||||||
|
buttonText: qsTr("Enable logging")
|
||||||
|
visible: !root.isLogged
|
||||||
|
onButtonClicked: {
|
||||||
|
print("enabming logging")
|
||||||
|
engine.thingManager.setStateLogging(root.thing.id, root.stateType.id, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -68,9 +68,12 @@ ThingPageBase {
|
|||||||
id: logsModel
|
id: logsModel
|
||||||
engine: _engine
|
engine: _engine
|
||||||
sources: ["event-" + root.thing.id + "-pressed", "event-" + root.thing.id + "-longPressed"]
|
sources: ["event-" + root.thing.id + "-pressed", "event-" + root.thing.id + "-longPressed"]
|
||||||
// live: true
|
live: true
|
||||||
|
fetchBlockSize: 200 // As paging doesn't work with multiple sources
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: print("**************** created", logsModel.sources)
|
||||||
|
|
||||||
delegate: NymeaItemDelegate {
|
delegate: NymeaItemDelegate {
|
||||||
id: entryDelegate
|
id: entryDelegate
|
||||||
width: logView.width
|
width: logView.width
|
||||||
|
|||||||
149
nymea-app/ui/devicepages/EventLogPage.qml
Normal file
149
nymea-app/ui/devicepages/EventLogPage.qml
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*
|
||||||
|
* Copyright 2013 - 2023, nymea GmbH
|
||||||
|
* Contact: contact@nymea.io
|
||||||
|
*
|
||||||
|
* This file is part of nymea.
|
||||||
|
* This project including source code and documentation is protected by
|
||||||
|
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||||
|
* reproduction, publication, editing and translation, are reserved. The use of
|
||||||
|
* this project is subject to the terms of a license agreement to be concluded
|
||||||
|
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||||
|
* under https://nymea.io/license
|
||||||
|
*
|
||||||
|
* GNU General Public License Usage
|
||||||
|
* Alternatively, this project may be redistributed and/or modified under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, GNU version 3. This project 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 project. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* For any further details and any questions please contact us under
|
||||||
|
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||||
|
* https://nymea.io/license/faq
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import Nymea 1.0
|
||||||
|
import "../components"
|
||||||
|
import "../customviews"
|
||||||
|
|
||||||
|
Page {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property Thing thing: null
|
||||||
|
property EventType eventType: null
|
||||||
|
|
||||||
|
readonly property bool isLogged: thing.loggedEventTypeIds.indexOf(eventType.id) >= 0
|
||||||
|
|
||||||
|
header: NymeaHeader {
|
||||||
|
text: qsTr("History for %1").arg(root.eventType.displayName)
|
||||||
|
onBackPressed: pageStack.pop()
|
||||||
|
|
||||||
|
HeaderButton {
|
||||||
|
imageSource: "delete"
|
||||||
|
visible: root.isLogged
|
||||||
|
onClicked: {
|
||||||
|
var popup = deleteLogsComponent.createObject(root)
|
||||||
|
popup.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: deleteLogsComponent
|
||||||
|
NymeaDialog {
|
||||||
|
title: qsTr("Remove logs?")
|
||||||
|
text: qsTr("Do you want to remove the log for this event and disable logging?")
|
||||||
|
standardButtons: Dialog.No | Dialog.Yes
|
||||||
|
onAccepted: engine.thingManager.setEventLogging(root.thing.id, root.eventType.id, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NewLogsModel {
|
||||||
|
id: logsModel
|
||||||
|
engine: _engine
|
||||||
|
source: "event-" + root.thing.id + "-" + root.eventType.name
|
||||||
|
sortOrder: Qt.DescendingOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listView
|
||||||
|
visible: root.isLogged
|
||||||
|
model: logsModel
|
||||||
|
clip: true
|
||||||
|
anchors.fill: parent
|
||||||
|
ScrollBar.vertical: ScrollBar {}
|
||||||
|
|
||||||
|
delegate: NymeaItemDelegate {
|
||||||
|
id: delegate
|
||||||
|
width: listView.width
|
||||||
|
height: contentColumn.implicitHeight + Style.margins
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
topPadding: 0
|
||||||
|
bottomPadding: 0
|
||||||
|
property NewLogEntry entry: logsModel.get(index)
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
id: contentColumn
|
||||||
|
anchors { left: parent.left; right: parent.right; margins: app.margins / 2 }
|
||||||
|
ColorIcon {
|
||||||
|
Layout.preferredWidth: Style.iconSize
|
||||||
|
Layout.preferredHeight: width
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
name: "event"
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: Qt.formatDateTime(model.timestamp,"dd.MM.yy - hh:mm:ss")
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: {
|
||||||
|
var ret = []
|
||||||
|
var values = JSON.parse(entry.values.params)
|
||||||
|
for (var i = 0; i < root.eventType.paramTypes.count; i++) {
|
||||||
|
var paramType = root.eventType.paramTypes.get(i)
|
||||||
|
ret.push(paramType.displayName + ": " + Types.toUiValue(values[paramType.name], paramType.unit) + " " + Types.toUiUnit(paramType.unit))
|
||||||
|
}
|
||||||
|
return ret.join("<br>")
|
||||||
|
}
|
||||||
|
textFormat: Text.RichText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: Style.smallFont
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyViewPlaceholder {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - app.margins * 2
|
||||||
|
title: qsTr("Logging not enabled")
|
||||||
|
text: qsTr("This state is not being logged.")
|
||||||
|
imageSource: "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle)
|
||||||
|
buttonText: qsTr("Enable logging")
|
||||||
|
visible: !root.isLogged
|
||||||
|
onButtonClicked: {
|
||||||
|
print("enabming logging")
|
||||||
|
engine.thingManager.setStateLogging(root.thing.id, root.stateType.id, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -145,7 +145,13 @@ ThingPageBase {
|
|||||||
swipe.close();
|
swipe.close();
|
||||||
print("opening logs for", delegate.stateType)
|
print("opening logs for", delegate.stateType)
|
||||||
if (engine.jsonRpcClient.ensureServerVersion("8.0")) {
|
if (engine.jsonRpcClient.ensureServerVersion("8.0")) {
|
||||||
pageStack.push(Qt.resolvedUrl("StateLogPage.qml"), {thing: root.thing, stateType: delegate.stateType})
|
if (delegate.stateType) {
|
||||||
|
pageStack.push(Qt.resolvedUrl("StateLogPage.qml"), {thing: root.thing, stateType: delegate.stateType})
|
||||||
|
} else if (delegate.eventType) {
|
||||||
|
pageStack.push(Qt.resolvedUrl("EventLogPage.qml"), {thing: root.thing, eventType: delegate.eventType})
|
||||||
|
} else if (delegate.actionType) {
|
||||||
|
pageStack.push(Qt.resolvedUrl("ActionLogPage.qml"), {thing: root.thing, actionType: delegate.actionType})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pageStack.push(Qt.resolvedUrl("DeviceLogPage.qml"), {thing: root.thing, filterTypeIds: [model.id]})
|
pageStack.push(Qt.resolvedUrl("DeviceLogPage.qml"), {thing: root.thing, filterTypeIds: [model.id]})
|
||||||
}
|
}
|
||||||
@ -347,10 +353,13 @@ ThingPageBase {
|
|||||||
}
|
}
|
||||||
Timer { id: pendingTimer; interval: 1000; repeat: false; running: false }
|
Timer { id: pendingTimer; interval: 1000; repeat: false; running: false }
|
||||||
|
|
||||||
Button {
|
Label {
|
||||||
text: actionType.displayName
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
text: actionType.displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (actionDelegate.actionType.paramTypes.count === 0) {
|
if (actionDelegate.actionType.paramTypes.count === 0) {
|
||||||
|
|||||||
@ -265,6 +265,7 @@ ThingPageBase {
|
|||||||
engine: _engine
|
engine: _engine
|
||||||
// live: true
|
// live: true
|
||||||
source: "action-" + root.thing.id + "-notify"
|
source: "action-" + root.thing.id + "-notify"
|
||||||
|
sortOrder: Qt.DescendingOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: BigTile {
|
delegate: BigTile {
|
||||||
|
|||||||
@ -61,6 +61,7 @@ Page {
|
|||||||
|
|
||||||
HeaderButton {
|
HeaderButton {
|
||||||
imageSource: "delete"
|
imageSource: "delete"
|
||||||
|
visible: root.isLogged
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var popup = deleteLogsComponent.createObject(root)
|
var popup = deleteLogsComponent.createObject(root)
|
||||||
popup.open()
|
popup.open()
|
||||||
|
|||||||
Reference in New Issue
Block a user