Skip to content

Commit

Permalink
Improve Commit viewer (#2712)
Browse files Browse the repository at this point in the history
  • Loading branch information
soininen authored Apr 18, 2024
2 parents 0fb9de9 + 284ab03 commit 516898b
Show file tree
Hide file tree
Showing 114 changed files with 990 additions and 246 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Many parts of the Spine data structure have been redesigned.
- You can now select a different Julia executable & project or Julia kernel for each Tool spec.
This overrides the global setting from Toolbox Settings.
- Headless mode now supports remote execution (see 'python -m spinetoolbox --help')
- Commit Viewer's UI has undergone some redesigning and can now handle large databases.

### Deprecated

Expand Down
17 changes: 9 additions & 8 deletions benchmarks/db_mngr_get_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os
import sys

from spinedb_api.db_mapping_base import PublicItem

if sys.platform == "win32" and "HOMEPATH" not in os.environ:
import pathlib
os.environ["HOMEPATH"] = str(pathlib.Path(sys.executable).parent)
Expand All @@ -15,18 +17,17 @@
from PySide6.QtWidgets import QApplication
from spinetoolbox.spine_db_manager import SpineDBManager
from spinedb_api import DatabaseMapping, to_database
from spinedb_api.temp_id import TempId
from benchmarks.utils import StdOutLogger


def db_mngr_get_value(
loops: int, db_mngr: SpineDBManager, db_map: DatabaseMapping, ids: Sequence[TempId], role: Qt.ItemDataRole
loops: int, db_mngr: SpineDBManager, db_map: DatabaseMapping, items: Sequence[PublicItem], role: Qt.ItemDataRole
) -> float:
duration = 0.0
for _ in range(loops):
for id_ in ids:
for item in items:
start = time.perf_counter()
db_mngr.get_value(db_map, "parameter_value", id_, role)
db_mngr.get_value(db_map, item, role)
duration += time.perf_counter() - start
return duration

Expand All @@ -40,7 +41,7 @@ def run_benchmark(output_file: Optional[str]):
db_map.add_entity_class_item(name="Object")
db_map.add_parameter_definition_item(name="x", entity_class_name="Object")
db_map.add_entity_item(name="object", entity_class_name="Object")
value_ids = []
value_items = []
for i in range(100):
alternative_name = str(i)
db_map.add_alternative_item(name=str(i))
Expand All @@ -54,16 +55,16 @@ def run_benchmark(output_file: Optional[str]):
type=value_type,
)
assert error is None
value_ids.append(item["id"])
value_items.append(item)
runner = pyperf.Runner()
benchmark = runner.bench_time_func(
"SpineDatabaseManager.get_value[parameter_value, DisplayRole]",
db_mngr_get_value,
db_mngr,
db_map,
value_ids,
value_items,
Qt.ItemDataRole.DisplayRole,
inner_loops=len(value_ids),
inner_loops=len(value_items),
)
if output_file:
pyperf.add_runs(output_file, benchmark)
Expand Down
Binary file not shown.
Binary file removed docs/source/img/add_electricity_load_from_node.png
Binary file not shown.
Binary file removed docs/source/img/add_node_commodity.png
Binary file not shown.
Binary file removed docs/source/img/add_node_temporal_block.png
Binary file not shown.
Binary file removed docs/source/img/add_power_plant_units.png
Binary file not shown.
Binary file not shown.
Binary file removed docs/source/img/add_pwr_plant_water_from_node.png
Binary file not shown.
Binary file removed docs/source/img/add_pwr_plant_water_to_node.png
Binary file not shown.
Binary file removed docs/source/img/add_rsrv_water_to_from_node.png
Binary file not shown.
Binary file removed docs/source/img/add_spillway_water_to_from_node.png
Binary file not shown.
Binary file removed docs/source/img/add_storage_commodity.png
Binary file not shown.
Binary file removed docs/source/img/add_storage_unit.png
Binary file not shown.
Binary file removed docs/source/img/case_study_a5_item_connections.png
Binary file not shown.
Binary file removed docs/source/img/case_study_a5_model_parameters.png
Binary file not shown.
Binary file removed docs/source/img/case_study_a5_output.png
Binary file not shown.
Binary file not shown.
Binary file removed docs/source/img/case_study_a5_schematic.png
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed docs/source/img/gdx_export_settings_window.png
Binary file not shown.
Binary file removed docs/source/img/gdx_exporter_properties.png
Diff not rendered.
Binary file removed docs/source/img/import_editor_mapping_options.png
Diff not rendered.
Binary file removed docs/source/img/install_spine_opt_plugin.png
Diff not rendered.
Binary file removed docs/source/img/items_connections.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/pass_input_txt_dc_properties.png
Diff not rendered.
Diff not rendered.
1 change: 0 additions & 1 deletion docs/source/img/project_item_icons/database.svg
Diff not rendered.
1 change: 0 additions & 1 deletion docs/source/img/project_item_icons/hammer.svg
Diff not rendered.
1 change: 0 additions & 1 deletion docs/source/img/project_item_icons/play-circle.svg
Diff not rendered.
Binary file removed docs/source/img/pypsa_dc.png
Diff not rendered.
Binary file removed docs/source/img/release06_main_window_empty.png
Diff not rendered.
Binary file removed docs/source/img/settings_project.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/simple_system_add_nodes.png
Diff not rendered.
Binary file removed docs/source/img/simple_system_add_output.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/simple_system_add_units.png
Diff not rendered.
Binary file removed docs/source/img/simple_system_cmdline_args.png
Diff not rendered.
Binary file removed docs/source/img/simple_system_electricity_demand.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/simple_system_fuel_balance_type.png
Diff not rendered.
Binary file removed docs/source/img/simple_system_item_connections.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/simple_system_schematic.png
Diff not rendered.
Binary file removed docs/source/img/spine_datapackage_editor_pypsa.png
Diff not rendered.
Binary file removed docs/source/img/spine_opt_plugin_tool_bar.png
Diff not rendered.
Binary file removed docs/source/img/tabular_view_edit_data.png
Diff not rendered.
Binary file removed docs/source/img/tabular_view_edit_index.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/tree_view_table_tab.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_commodities.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_connection_from_node.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_connection_node_node.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/two_hydro_connections.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_fix_node_state.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/two_hydro_model_parameters.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_node_commodities.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_node_parameters.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_nodes.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_report.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_results_discharge.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_results_electricity.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_temporal_block.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_unit_from_node.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/two_hydro_unit_node_node.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/two_hydro_unit_to_node.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/img/two_hydro_units.png
Diff not rendered.
Binary file removed docs/source/img/two_hydro_vom_cost.png
Diff not rendered.
Binary file removed docs/source/spine_db_editor/img/EAV_CR.png
Diff not rendered.
Diff not rendered.
Diff not rendered.
Binary file modified docs/source/spine_db_editor/img/commit_viewer.png
Binary file removed docs/source/spine_db_editor/img/cs-c2.png
Diff not rendered.
Diff not rendered.
Binary file removed docs/source/spine_db_editor/img/parameter_tag.png
Diff not rendered.
Diff not rendered.
3 changes: 2 additions & 1 deletion docs/source/spine_db_editor/importing_and_exporting_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ The JSON format consists of a single JSON object with the following ``OPTIONAL``
- The fourth element ``MUST`` be either a JSON object, string, number, or null,
indicating the parameter value.

There is one ``OPTIONAL`` element
There is one ``OPTIONAL`` element:

- The fifth element ``MUST`` either be a JSON string indicating the alternative, or null. If this element
is not present, an alternative named Base will be created if it doesn't exist and the values will be set
in that alternative.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ def data(self, column, role=Qt.ItemDataRole.DisplayRole):
if role == Qt.ItemDataRole.DisplayRole and not self.id:
return "Enter new list value here..."
if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole, Qt.ItemDataRole.ToolTipRole, PARSED_ROLE):
return self.db_mngr.get_value(self.db_map, self.item_type, self.id, role=role)
item = self.db_mngr.get_item(self.db_map, self.item_type, self.id)
return self.db_mngr.get_value(self.db_map, item, role=role)
return super().data(column, role)

def list_index(self):
Expand Down
3 changes: 2 additions & 1 deletion spinetoolbox/spine_db_editor/mvcmodels/pivot_table_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,8 @@ def _data(self, index, role):
if data[0][0] is None:
return None
db_map, id_ = data[0][0]
return self.db_mngr.get_value(db_map, "parameter_value", id_, role)
item = self.db_mngr.get_item(db_map, "parameter_value", id_)
return self.db_mngr.get_value(db_map, item, role)

def _do_batch_set_inner_data(self, row_map, column_map, data, values):
return self._batch_set_parameter_value_data(row_map, column_map, data, values)
Expand Down
3 changes: 2 additions & 1 deletion spinetoolbox/spine_db_editor/mvcmodels/single_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@ def data(self, index, role=Qt.ItemDataRole.DisplayRole):
PARSED_ROLE,
):
id_ = self._main_data[index.row()]
return self.db_mngr.get_value(self.db_map, self.item_type, id_, role)
item = self.db_mngr.get_item(self.db_map, self.item_type, id_)
return self.db_mngr.get_value(self.db_map, item, role)
return super().data(index, role)


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
######################################################################################################################
# Copyright (C) 2017-2022 Spine project consortium
# Copyright Spine Toolbox contributors
# This file is part of Spine Toolbox.
# Spine Toolbox is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

################################################################################
## Form generated from reading UI file 'commit_viewer_affected_item_info.ui'
##
## Created by: Qt User Interface Compiler version 6.5.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QHeaderView, QLabel, QSizePolicy,
QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget)

class Ui_Form(object):
def setupUi(self, Form):
if not Form.objectName():
Form.setObjectName(u"Form")
Form.resize(400, 300)
self.verticalLayout = QVBoxLayout(Form)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.affected_items_table = QTableWidget(Form)
self.affected_items_table.setObjectName(u"affected_items_table")

self.verticalLayout.addWidget(self.affected_items_table)

self.fetch_status_label = QLabel(Form)
self.fetch_status_label.setObjectName(u"fetch_status_label")

self.verticalLayout.addWidget(self.fetch_status_label)


self.retranslateUi(Form)

QMetaObject.connectSlotsByName(Form)
# setupUi

def retranslateUi(self, Form):
Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
self.fetch_status_label.setText(QCoreApplication.translate("Form", u"TextLabel", None))
# retranslateUi

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
######################################################################################################################
# Copyright (C) 2017-2022 Spine project consortium
# Copyright Spine Toolbox contributors
# This file is part of Spine Toolbox.
# Spine Toolbox is free software: you can redistribute it and\/or modify it under the terms of the GNU Lesser 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 Lesser General
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see <http:\/\/www.gnu.org\/licenses\/>.
######################################################################################################################
-->
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTableWidget" name="affected_items_table"/>
</item>
<item>
<widget class="QLabel" name="fetch_status_label">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
154 changes: 154 additions & 0 deletions spinetoolbox/spine_db_editor/ui/db_commit_viewer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# -*- coding: utf-8 -*-
######################################################################################################################
# Copyright (C) 2017-2022 Spine project consortium
# Copyright Spine Toolbox contributors
# This file is part of Spine Toolbox.
# Spine Toolbox is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

################################################################################
## Form generated from reading UI file 'db_commit_viewer.ui'
##
## Created by: Qt User Interface Compiler version 6.5.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QHBoxLayout, QHeaderView,
QLabel, QSizePolicy, QSplitter, QStackedWidget,
QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem,
QVBoxLayout, QWidget)

class Ui_DBCommitViewer(object):
def setupUi(self, DBCommitViewer):
if not DBCommitViewer.objectName():
DBCommitViewer.setObjectName(u"DBCommitViewer")
DBCommitViewer.resize(716, 218)
self.horizontalLayout_2 = QHBoxLayout(DBCommitViewer)
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.splitter = QSplitter(DBCommitViewer)
self.splitter.setObjectName(u"splitter")
self.splitter.setOrientation(Qt.Horizontal)
self.commit_list = QTreeWidget(self.splitter)
__qtreewidgetitem = QTreeWidgetItem()
__qtreewidgetitem.setText(0, u"1");
self.commit_list.setHeaderItem(__qtreewidgetitem)
self.commit_list.setObjectName(u"commit_list")
self.splitter.addWidget(self.commit_list)
self.verticalFrame = QFrame(self.splitter)
self.verticalFrame.setObjectName(u"verticalFrame")
self.verticalFrame.setStyleSheet(u"QFrame {\n"
" background-color: white;\n"
"}")
self.verticalFrame.setFrameShape(QFrame.Box)
self.verticalLayout = QVBoxLayout(self.verticalFrame)
self.verticalLayout.setSpacing(3)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setContentsMargins(5, 5, 5, 0)
self.label = QLabel(self.verticalFrame)
self.label.setObjectName(u"label")

self.verticalLayout.addWidget(self.label)

self.affected_items_widget_stack = QStackedWidget(self.verticalFrame)
self.affected_items_widget_stack.setObjectName(u"affected_items_widget_stack")
self.items_page = QWidget()
self.items_page.setObjectName(u"items_page")
self.horizontalLayout_3 = QHBoxLayout(self.items_page)
self.horizontalLayout_3.setSpacing(0)
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
self.affected_item_tab_widget = QTabWidget(self.items_page)
self.affected_item_tab_widget.setObjectName(u"affected_item_tab_widget")
self.affected_item_tab_widget.setDocumentMode(True)

self.horizontalLayout_3.addWidget(self.affected_item_tab_widget)

self.affected_items_widget_stack.addWidget(self.items_page)
self.no_items_page = QWidget()
self.no_items_page.setObjectName(u"no_items_page")
self.horizontalLayout = QHBoxLayout(self.no_items_page)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.no_affected_items_notice = QTextBrowser(self.no_items_page)
self.no_affected_items_notice.setObjectName(u"no_affected_items_notice")
self.no_affected_items_notice.setFocusPolicy(Qt.NoFocus)
self.no_affected_items_notice.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.no_affected_items_notice.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.no_affected_items_notice.setOpenLinks(False)

self.horizontalLayout.addWidget(self.no_affected_items_notice)

self.affected_items_widget_stack.addWidget(self.no_items_page)
self.loading_page = QWidget()
self.loading_page.setObjectName(u"loading_page")
self.horizontalLayout_4 = QHBoxLayout(self.loading_page)
self.horizontalLayout_4.setSpacing(0)
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
self.loading_label = QLabel(self.loading_page)
self.loading_label.setObjectName(u"loading_label")
self.loading_label.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)

self.horizontalLayout_4.addWidget(self.loading_label)

self.affected_items_widget_stack.addWidget(self.loading_page)
self.no_commit_selected_page = QWidget()
self.no_commit_selected_page.setObjectName(u"no_commit_selected_page")
self.verticalLayout_2 = QVBoxLayout(self.no_commit_selected_page)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.label_2 = QLabel(self.no_commit_selected_page)
self.label_2.setObjectName(u"label_2")
self.label_2.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)

self.verticalLayout_2.addWidget(self.label_2)

self.affected_items_widget_stack.addWidget(self.no_commit_selected_page)

self.verticalLayout.addWidget(self.affected_items_widget_stack)

self.splitter.addWidget(self.verticalFrame)

self.horizontalLayout_2.addWidget(self.splitter)


self.retranslateUi(DBCommitViewer)

self.affected_items_widget_stack.setCurrentIndex(3)
self.affected_item_tab_widget.setCurrentIndex(-1)


QMetaObject.connectSlotsByName(DBCommitViewer)
# setupUi

def retranslateUi(self, DBCommitViewer):
self.label.setText(QCoreApplication.translate("DBCommitViewer", u"Affected items", None))
self.no_affected_items_notice.setHtml(QCoreApplication.translate("DBCommitViewer", u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"hr { height: 1px; border-width: 0; }\n"
"li.unchecked::marker { content: \"\\2610\"; }\n"
"li.checked::marker { content: \"\\2612\"; }\n"
"</style></head><body style=\" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">No affected items found for selected commit.</p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Note, that it is not possible to show items that have been removed by this or a later commit.</p></body></html>", None))
self.loading_label.setText(QCoreApplication.translate("DBCommitViewer", u"Loading...", None))
self.label_2.setText(QCoreApplication.translate("DBCommitViewer", u"Select a commit from the list on the left.", None))
pass
# retranslateUi

Loading

0 comments on commit 516898b

Please sign in to comment.