Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp of mscolab operation menu and addition of "archive" operation #1782

Merged
merged 1 commit into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions mslib/mscolab/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
migrate = Migrate(APP, db, render_as_batch=True)
auth = HTTPBasicAuth()

ARCHIVE_THRESHOLD = 30
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should maybe make this configurable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. 30 days seems a tad short for me as a typical campaign may run longer.
New issue?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this needs also a documentation


try:
from mscolab_auth import mscolab_auth
except ImportError as ex:
Expand Down Expand Up @@ -489,13 +491,17 @@ def get_operation_details():
@verify_user
def set_last_used():
op_id = request.form.get('op_id', None)
days_ago = int(request.form.get('days', 0))
operation = Operation.query.filter_by(id=int(op_id)).first()
operation.last_used = datetime.datetime.utcnow()
operation.last_used = datetime.datetime.utcnow() - datetime.timedelta(days=days_ago)
temp_operation_active = operation.active
operation.active = True
if days_ago > ARCHIVE_THRESHOLD:
operation.active = False
else:
operation.active = True
db.session.commit()
# Reload Operation List
if not temp_operation_active:
if temp_operation_active != operation.active:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the wording maybe can be changed to archived, unarchived etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changing operation.active requires changes to the DB, I guess?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, in the models.

and on staging you could do this by
https://mss.readthedocs.io/en/stable/mscolab.html#data-base-migration

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review and also add new parts to the section Operation based features in

https://github.com/Open-MSS/MSS/blob/develop/docs/mscolab.rst#operation-based-features

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not convinced that we should change the DB format to be more consistent in a part that is not user-visible.

Copy link
Member

@ReimarBauer ReimarBauer May 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do this when we need another change. It is not needed now, but at the moment we introduce something new we anyways have to do a server database migration.

token = request.args.get('token', request.form.get('token', False))
json_config = {"token": token}
sockio.sm.update_operation_list(json_config)
Expand All @@ -507,11 +513,12 @@ def set_last_used():
def update_last_used():
operations = Operation.query.filter().all()
for operation in operations:
a = (datetime.datetime.utcnow() - operation.last_used).days
if a > 30:
operation.active = False
else:
operation.active = True
if operation.last_used is not None:
days_ago = (datetime.datetime.utcnow() - operation.last_used).days
if days_ago > ARCHIVE_THRESHOLD:
operation.active = False
else:
operation.active = True
db.session.commit()
return jsonify({"success": True}), 200

Expand Down
237 changes: 170 additions & 67 deletions mslib/msui/mscolab.py

Large diffs are not rendered by default.

15 changes: 3 additions & 12 deletions mslib/msui/msui.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,22 +459,13 @@ def __init__(self, mscolab_data_dir=None, *args):

# deactivate vice versa selection of Operation, inactive operation or Flight Track

def deselecter(list_a, list_b, disable):
list_a.setCurrentItem(None)
list_b.setCurrentItem(None)
if disable:
self.mscolab.ui.actionUnarchiveOperation.setEnabled(False)

self.listFlightTracks.itemClicked.connect(
lambda: deselecter(self.listOperationsMSC, self.listInactiveOperationsMSC, True))
lambda: self.listOperationsMSC.setCurrentItem(None))
self.listOperationsMSC.itemClicked.connect(
lambda: deselecter(self.listFlightTracks, self.listInactiveOperationsMSC, True))
self.listInactiveOperationsMSC.itemClicked.connect(
lambda: deselecter(self.listFlightTracks, self.listOperationsMSC, False))

lambda: self.listFlightTracks.setCurrentItem(None))
# disable category until connected/login into mscolab
self.filterCategoryCb.setEnabled(False)
self.mscolab.signal_activate_operation.connect(self.activate_operation_slot)
self.mscolab.signal_unarchive_operation.connect(self.activate_operation_slot)
self.mscolab.signal_operation_added.connect(self.add_operation_slot)
self.mscolab.signal_operation_removed.connect(self.remove_operation_slot)
self.mscolab.signal_login_mscolab.connect(lambda d, t: self.signal_login_mscolab.emit(d, t))
Expand Down
100 changes: 53 additions & 47 deletions mslib/msui/qt5/ui_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,43 +111,45 @@ def setupUi(self, MSUIMainWindow):
self.gridLayout_3 = QtWidgets.QGridLayout(self.openOperationsGb)
self.gridLayout_3.setContentsMargins(8, 8, 8, 8)
self.gridLayout_3.setObjectName("gridLayout_3")
self.workingStatusLabel = QtWidgets.QLabel(self.openOperationsGb)
self.workingStatusLabel.setWordWrap(True)
self.workingStatusLabel.setObjectName("workingStatusLabel")
self.gridLayout_3.addWidget(self.workingStatusLabel, 6, 0, 1, 2)
self.activeOperationDesc = QtWidgets.QLabel(self.openOperationsGb)
self.activeOperationDesc.setObjectName("activeOperationDesc")
self.gridLayout_3.addWidget(self.activeOperationDesc, 1, 0, 1, 2)
self.activeOperationsLabel = QtWidgets.QLabel(self.openOperationsGb)
self.activeOperationsLabel.setObjectName("activeOperationsLabel")
self.gridLayout_3.addWidget(self.activeOperationsLabel, 2, 0, 1, 1)
self.workLocallyCheckbox = QtWidgets.QCheckBox(self.openOperationsGb)
self.workLocallyCheckbox.setObjectName("workLocallyCheckbox")
self.gridLayout_3.addWidget(self.workLocallyCheckbox, 10, 0, 1, 1)
self.filterCategoryCb = QtWidgets.QComboBox(self.openOperationsGb)
self.filterCategoryCb.setAutoFillBackground(False)
self.filterCategoryCb.setEditable(False)
self.filterCategoryCb.setObjectName("filterCategoryCb")
self.filterCategoryCb.addItem("")
self.gridLayout_3.addWidget(self.filterCategoryCb, 10, 1, 1, 1)
self.categoryLabel = QtWidgets.QLabel(self.openOperationsGb)
self.categoryLabel.setObjectName("categoryLabel")
self.gridLayout_3.addWidget(self.categoryLabel, 10, 0, 1, 1)
self.inactiveOperationsLabel = QtWidgets.QLabel(self.openOperationsGb)
self.inactiveOperationsLabel.setObjectName("inactiveOperationsLabel")
self.gridLayout_3.addWidget(self.inactiveOperationsLabel, 5, 0, 1, 1)
self.listInactiveOperationsMSC = QtWidgets.QListWidget(self.openOperationsGb)
self.listInactiveOperationsMSC.setObjectName("listInactiveOperationsMSC")
self.gridLayout_3.addWidget(self.listInactiveOperationsMSC, 6, 0, 1, 2)
self.workingStatusLabel = QtWidgets.QLabel(self.openOperationsGb)
self.workingStatusLabel.setWordWrap(True)
self.workingStatusLabel.setObjectName("workingStatusLabel")
self.gridLayout_3.addWidget(self.workingStatusLabel, 7, 0, 1, 2)
self.gridLayout_3.addWidget(self.filterCategoryCb, 9, 1, 1, 1)
self.serverOptionsCb = QtWidgets.QComboBox(self.openOperationsGb)
self.serverOptionsCb.setObjectName("serverOptionsCb")
self.serverOptionsCb.addItem("")
self.serverOptionsCb.addItem("")
self.serverOptionsCb.addItem("")
self.gridLayout_3.addWidget(self.serverOptionsCb, 11, 1, 1, 1)
self.workLocallyCheckbox = QtWidgets.QCheckBox(self.openOperationsGb)
self.workLocallyCheckbox.setObjectName("workLocallyCheckbox")
self.gridLayout_3.addWidget(self.workLocallyCheckbox, 11, 0, 1, 1)
self.gridLayout_3.addWidget(self.serverOptionsCb, 10, 1, 1, 1)
self.categoryLabel = QtWidgets.QLabel(self.openOperationsGb)
self.categoryLabel.setObjectName("categoryLabel")
self.gridLayout_3.addWidget(self.categoryLabel, 9, 0, 1, 1)
self.listOperationsMSC = QtWidgets.QListWidget(self.openOperationsGb)
self.listOperationsMSC.setObjectName("listOperationsMSC")
self.gridLayout_3.addWidget(self.listOperationsMSC, 4, 0, 1, 2)
self.activeOperationDesc = QtWidgets.QLabel(self.openOperationsGb)
self.activeOperationDesc.setObjectName("activeOperationDesc")
self.gridLayout_3.addWidget(self.activeOperationDesc, 1, 0, 1, 2)
self.activeOperationsLabel = QtWidgets.QLabel(self.openOperationsGb)
self.activeOperationsLabel.setObjectName("activeOperationsLabel")
self.gridLayout_3.addWidget(self.activeOperationsLabel, 2, 0, 1, 1)
self.pbOpenOperationArchive = QtWidgets.QPushButton(self.openOperationsGb)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pbOpenOperationArchive.sizePolicy().hasHeightForWidth())
self.pbOpenOperationArchive.setSizePolicy(sizePolicy)
self.pbOpenOperationArchive.setObjectName("pbOpenOperationArchive")
self.gridLayout_3.addWidget(self.pbOpenOperationArchive, 11, 0, 1, 2)
self.horizontalLayout.addWidget(self.openOperationsGb)
self.verticalLayout_2.addLayout(self.horizontalLayout)
self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 2)
Expand Down Expand Up @@ -221,16 +223,18 @@ def setupUi(self, MSUIMainWindow):
self.actionAddOperation.setObjectName("actionAddOperation")
self.actionSearch = QtWidgets.QAction(MSUIMainWindow)
self.actionSearch.setObjectName("actionSearch")
self.actionDescription = QtWidgets.QAction(MSUIMainWindow)
self.actionDescription.setObjectName("actionDescription")
self.actionUpdateOperationDesc = QtWidgets.QAction(MSUIMainWindow)
self.actionUpdateOperationDesc.setObjectName("actionUpdateOperationDesc")
self.actionViewDescription = QtWidgets.QAction(MSUIMainWindow)
self.actionViewDescription.setObjectName("actionViewDescription")
self.actionChangeDescription = QtWidgets.QAction(MSUIMainWindow)
self.actionChangeDescription.setObjectName("actionChangeDescription")
self.actionRenameOperation = QtWidgets.QAction(MSUIMainWindow)
self.actionRenameOperation.setObjectName("actionRenameOperation")
self.actionLeaveOperation = QtWidgets.QAction(MSUIMainWindow)
self.actionLeaveOperation.setObjectName("actionLeaveOperation")
self.actionUnarchiveOperation = QtWidgets.QAction(MSUIMainWindow)
self.actionUnarchiveOperation.setObjectName("actionUnarchiveOperation")
self.actionArchiveOperation = QtWidgets.QAction(MSUIMainWindow)
self.actionArchiveOperation.setObjectName("actionArchiveOperation")
self.actionChangeCategory = QtWidgets.QAction(MSUIMainWindow)
self.actionChangeCategory.setObjectName("actionChangeCategory")
self.menuNew.addAction(self.actionNewFlightTrack)
self.menuNew.addAction(self.actionAddOperation)
self.menuFile.addAction(self.menuNew.menuAction())
Expand All @@ -256,16 +260,17 @@ def setupUi(self, MSUIMainWindow):
self.menuViews.addAction(self.actionSideView)
self.menuViews.addAction(self.actionTableView)
self.menuViews.addAction(self.actionLinearView)
self.menuProperties.addAction(self.actionDeleteOperation)
self.menuProperties.addAction(self.actionDescription)
self.menuProperties.addAction(self.actionUpdateOperationDesc)
self.menuProperties.addAction(self.actionChangeCategory)
self.menuProperties.addAction(self.actionChangeDescription)
self.menuProperties.addAction(self.actionManageUsers)
self.menuProperties.addAction(self.actionRenameOperation)
self.menuProperties.addAction(self.actionLeaveOperation)
self.menuProperties.addAction(self.actionDeleteOperation)
self.menuProperties.addAction(self.actionArchiveOperation)
self.menuOperation.addAction(self.actionChat)
self.menuOperation.addAction(self.actionVersionHistory)
self.menuOperation.addAction(self.actionManageUsers)
self.menuOperation.addAction(self.actionUnarchiveOperation)
self.menuOperation.addAction(self.actionViewDescription)
self.menuOperation.addSeparator()
self.menuOperation.addAction(self.actionLeaveOperation)
self.menuOperation.addAction(self.menuProperties.menuAction())
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuViews.menuAction())
Expand Down Expand Up @@ -298,30 +303,30 @@ def retranslateUi(self, MSUIMainWindow):
"Save a flight track to name it."))
self.openViewsLabel.setText(_translate("MSUIMainWindow", "Open Views:"))
self.listViews.setToolTip(_translate("MSUIMainWindow", "Double-click a view to bring it to the front."))
self.workingStatusLabel.setText(_translate("MSUIMainWindow", "No operations selected"))
self.activeOperationDesc.setText(_translate("MSUIMainWindow", "Select Operation to View Description"))
self.activeOperationsLabel.setText(_translate("MSUIMainWindow", "Operations"))
self.workLocallyCheckbox.setToolTip(_translate("MSUIMainWindow", "Check to work asynchronously from the server"))
self.workLocallyCheckbox.setText(_translate("MSUIMainWindow", "Work Asynchronously"))
self.filterCategoryCb.setWhatsThis(_translate("MSUIMainWindow", "filter by operation category"))
self.filterCategoryCb.setCurrentText(_translate("MSUIMainWindow", "ANY"))
self.filterCategoryCb.setItemText(0, _translate("MSUIMainWindow", "ANY"))
self.categoryLabel.setText(_translate("MSUIMainWindow", "Category:"))
self.inactiveOperationsLabel.setText(_translate("MSUIMainWindow", "Archived Operations"))
self.workingStatusLabel.setText(_translate("MSUIMainWindow", "No operations selected"))
self.serverOptionsCb.setToolTip(_translate("MSUIMainWindow", "Fetch/Save Server options"))
self.serverOptionsCb.setItemText(0, _translate("MSUIMainWindow", "Server Options"))
self.serverOptionsCb.setItemText(1, _translate("MSUIMainWindow", "Fetch From Server"))
self.serverOptionsCb.setItemText(2, _translate("MSUIMainWindow", "Save To Server"))
self.workLocallyCheckbox.setToolTip(_translate("MSUIMainWindow", "Check to work asynchronously from the server"))
self.workLocallyCheckbox.setText(_translate("MSUIMainWindow", "Work Asynchronously"))
self.categoryLabel.setText(_translate("MSUIMainWindow", "Category:"))
self.listOperationsMSC.setToolTip(_translate("MSUIMainWindow", "List of mscolab operations.\n"
"Double click a operation to activate and view its description."))
self.activeOperationDesc.setText(_translate("MSUIMainWindow", "Select Operation to View Description"))
self.activeOperationsLabel.setText(_translate("MSUIMainWindow", "Operations"))
self.pbOpenOperationArchive.setText(_translate("MSUIMainWindow", "Operation Archive"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plural?

on the upper list it is also plural and a : is missing on upper one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

singular in front of "archive" seems to be slightly more common than plural according to google

self.menuFile.setTitle(_translate("MSUIMainWindow", "&File"))
self.menuImportFlightTrack.setTitle(_translate("MSUIMainWindow", "Import Flight Track"))
self.menuExportActiveFlightTrack.setTitle(_translate("MSUIMainWindow", "Export Flight Track"))
self.menuNew.setTitle(_translate("MSUIMainWindow", "New"))
self.menuHelp.setTitle(_translate("MSUIMainWindow", "&Help"))
self.menuViews.setTitle(_translate("MSUIMainWindow", "Views"))
self.menuOperation.setTitle(_translate("MSUIMainWindow", "Operation"))
self.menuProperties.setTitle(_translate("MSUIMainWindow", "Properties"))
self.menuProperties.setTitle(_translate("MSUIMainWindow", "Maintenance"))
self.actionSaveActiveFlightTrack.setText(_translate("MSUIMainWindow", "&Save Active Flight Track"))
self.actionSaveActiveFlightTrack.setShortcut(_translate("MSUIMainWindow", "Ctrl+S"))
self.actionSaveActiveFlightTrackAs.setText(_translate("MSUIMainWindow", "Save Active Flight Track As"))
Expand Down Expand Up @@ -356,8 +361,9 @@ def retranslateUi(self, MSUIMainWindow):
self.actionSearch.setText(_translate("MSUIMainWindow", "Search"))
self.actionSearch.setToolTip(_translate("MSUIMainWindow", "Search for interactive text in the UI"))
self.actionSearch.setShortcut(_translate("MSUIMainWindow", "Ctrl+F"))
self.actionDescription.setText(_translate("MSUIMainWindow", "View Description"))
self.actionUpdateOperationDesc.setText(_translate("MSUIMainWindow", "Update Description"))
self.actionViewDescription.setText(_translate("MSUIMainWindow", "View Description"))
self.actionChangeDescription.setText(_translate("MSUIMainWindow", "Change Description"))
self.actionRenameOperation.setText(_translate("MSUIMainWindow", "Rename Operation"))
self.actionLeaveOperation.setText(_translate("MSUIMainWindow", "&Leave Operation"))
self.actionUnarchiveOperation.setText(_translate("MSUIMainWindow", "Unarchive Operation"))
self.actionArchiveOperation.setText(_translate("MSUIMainWindow", "Archive Operation"))
self.actionChangeCategory.setText(_translate("MSUIMainWindow", "Change Category"))
47 changes: 47 additions & 0 deletions mslib/msui/qt5/ui_operation_archive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'mslib/msui/ui/ui_operation_archive.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_OperationArchiveBrowser(object):
def setupUi(self, OperationArchiveBrowser):
OperationArchiveBrowser.setObjectName("OperationArchiveBrowser")
OperationArchiveBrowser.resize(754, 393)
self.verticalLayout = QtWidgets.QVBoxLayout(OperationArchiveBrowser)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(OperationArchiveBrowser)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.listArchivedOperations = QtWidgets.QListWidget(OperationArchiveBrowser)
self.listArchivedOperations.setObjectName("listArchivedOperations")
self.verticalLayout.addWidget(self.listArchivedOperations)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.pbUnarchiveOperation = QtWidgets.QPushButton(OperationArchiveBrowser)
self.pbUnarchiveOperation.setObjectName("pbUnarchiveOperation")
self.horizontalLayout.addWidget(self.pbUnarchiveOperation)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.pbClose = QtWidgets.QPushButton(OperationArchiveBrowser)
self.pbClose.setObjectName("pbClose")
self.horizontalLayout.addWidget(self.pbClose)
self.verticalLayout.addLayout(self.horizontalLayout)

self.retranslateUi(OperationArchiveBrowser)
QtCore.QMetaObject.connectSlotsByName(OperationArchiveBrowser)

def retranslateUi(self, OperationArchiveBrowser):
_translate = QtCore.QCoreApplication.translate
OperationArchiveBrowser.setWindowTitle(_translate("OperationArchiveBrowser", "Browse archived operations"))
self.label.setText(_translate("OperationArchiveBrowser", "Operation Archive"))
self.pbUnarchiveOperation.setToolTip(_translate("OperationArchiveBrowser", "<html><head/><body><p>Becomes available when you have the right to unarchive an operation. Moves this operation to the list of current operations.</p></body></html>"))
self.pbUnarchiveOperation.setText(_translate("OperationArchiveBrowser", "Unarchive"))
self.pbClose.setText(_translate("OperationArchiveBrowser", "close"))
Loading