diff --git a/.gitignore b/.gitignore index 0127b5a..ee00d16 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,7 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +.idea/inspectionProfiles/ +.idea/vcs.xml +Pipfile +Pipfile.lock diff --git a/README.md b/README.md index 24c6345..0b21592 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,23 @@ # Bug-Reporter App A Shotgun app for submit ticket for reporting bugs and request. +![Bug Report](./resources/app_ui.png) + +This app originally was created by +[Shotgun Software](https://www.shotgunsoftware.com/), I believe by +[Jeff Beeland](https://www.linkedin.com/in/jefferybeeland/), and was +demonstrated in [this video](https://www.youtube.com/watch?v=bT2WlQaJVmY). I +modified it a bit to accommodate my need in our studio. + +### New Features +* Ability to add the _error_ messages +* Include the environment variable +* Include the current _engine_ and _context_ + +### Future Features +* Specify Ticket Type _ex: bug or feature_ +* Specify the priority + +### Icon +The Bug Icon is by youtube.com/AlfredoCreates & Flaticondesign.com from the +Noun Project \ No newline at end of file diff --git a/icon_256.png b/icon_256.png index cbef9e6..2738663 100644 Binary files a/icon_256.png and b/icon_256.png differ diff --git a/python/app/dialog.py b/python/app/dialog.py index 22cc884..7978828 100644 --- a/python/app/dialog.py +++ b/python/app/dialog.py @@ -8,29 +8,32 @@ # agreement to the Shotgun Pipeline Toolkit Source Code License. All rights # not expressly granted therein are reserved by Shotgun Software Inc. -import sgtk import os -import sys -import threading -import tempfile import re +import tempfile +import sgtk # by importing QT from sgtk rather than directly, we ensure that # the code will be compatible with both PySide and PyQt. from sgtk.platform.qt import QtCore, QtGui + from .ui.dialog import Ui_Dialog -screen_grab = sgtk.platform.import_framework("tk-framework-qtwidgets", "screen_grab") -shotgun_fields = sgtk.platform.import_framework("tk-framework-qtwidgets", "shotgun_fields") +screen_grab = sgtk.platform.import_framework("tk-framework-qtwidgets", + "screen_grab") +shotgun_fields = sgtk.platform.import_framework("tk-framework-qtwidgets", + "shotgun_fields") + def show_dialog(app_instance): """ Shows the main dialog window. """ - # in order to handle UIs seamlessly, each toolkit engine has methods for launching - # different types of windows. By using these methods, your windows will be correctly - # decorated and handled in a consistent fashion by the system. - + # in order to handle UIs seamlessly, each toolkit engine has methods for + # launching different types of windows. By using these methods, your + # windows will be correctly decorated and handled in a consistent fashion + # by the system. + # we pass the dialog class to this method and leave the actual construction # to be carried out by toolkit. app_instance.engine.show_dialog("Report Bugs!", app_instance, AppDialog) @@ -40,27 +43,27 @@ class AppDialog(QtGui.QWidget): """ Main application dialog window """ - + def __init__(self): """ Constructor """ # first, call the base class and let it do its thing. - QtGui.QWidget.__init__(self) - + super(AppDialog, self).__init__() + # now load in the UI that was created in the UI designer self.ui = Ui_Dialog() self.ui.setupUi(self) - - # most of the useful accessors are available through the Application class instance - # it is often handy to keep a reference to this. You can get it via the following method: + + # most of the useful accessors are available through the Application + # class instance it is often handy to keep a reference to this. You can + # get it via the following method: self._app = sgtk.platform.current_bundle() - + # via the self._app handle we can for example access: # - The engine, via self._app.engine # - A Shotgun API instance, via self._app.shotgun # - A tk API instance, via self._app.tk - self.ui.buttons.accepted.connect(self.create_ticket) self.ui.buttons.rejected.connect(self.close) self.ui.screen_grab.clicked.connect(self.screen_grab) @@ -69,10 +72,10 @@ def __init__(self): self._cc_widget = None # The ShotgunFieldManager is a factory used to build widgets for fields - # associated with an entity type in Shotgun. It pulls down the schema from - # Shotgun asynchronously when the initialize method is called, so before - # we do that we need to hook up the signal it emits when it's done to our - # method that gets the widget we want and adds it to the UI. + # associated with an entity type in Shotgun. It pulls down the schema + # from Shotgun asynchronously when the initialize method is called, so + # before we do that we need to hook up the signal it emits when it's + # done to our method that gets the widget we want and adds it to the UI. self._field_manager = shotgun_fields.ShotgunFieldManager(parent=self) self._field_manager.initialized.connect(self._get_shotgun_fields) self._field_manager.initialize() @@ -117,12 +120,27 @@ def create_ticket(self): """ # Create the new Ticket entity, pulling the project from the current # context, and the title, ticket body, and cc list from the UI. + context_info = "__Engine Name__: {}\n__Engine Version__: " \ + "{}\n__Context__: {}".format(self._app.engine.name, + self._app.engine.version, + self._app.context) + environment_info = "\n".join(["{} = {}".format(env, value) + for env, value in os.environ.items()]) + description = self.ui.ticket_body.toPlainText() + error_log = '```\n{}\n```'.format(self.ui.error_log.toPlainText()) + + ticket_body = "{}\n### Description \n{}\n ### Error Log\n{}\n " \ + "### Environment Variable\n{}".format(context_info, + description, + error_log, + environment_info) + result = self._app.shotgun.create( "Ticket", dict( project=self._app.context.project, title=self.ui.ticket_title.text(), - description=self.ui.ticket_body.toPlainText(), + description=ticket_body, addressings_cc=self._cc_widget.get_value(), ) ) @@ -148,5 +166,3 @@ def create_ticket(self): "Ticket #%s successfully submitted!" % result["id"], ) self.close() - - diff --git a/python/app/ui/dialog.py b/python/app/ui/dialog.py index eaf2314..a4ef3fa 100644 --- a/python/app/ui/dialog.py +++ b/python/app/ui/dialog.py @@ -11,7 +11,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(431, 392) + Dialog.resize(452, 490) self.verticalLayout = QtGui.QVBoxLayout(Dialog) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtGui.QHBoxLayout() @@ -30,6 +30,9 @@ def setupUi(self, Dialog): self.cc_label.setObjectName("cc_label") self.cc_layout.addWidget(self.cc_label) self.verticalLayout.addLayout(self.cc_layout) + self.label_2 = QtGui.QLabel(Dialog) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) self.ticket_body = QtGui.QPlainTextEdit(Dialog) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -38,6 +41,17 @@ def setupUi(self, Dialog): self.ticket_body.setSizePolicy(sizePolicy) self.ticket_body.setObjectName("ticket_body") self.verticalLayout.addWidget(self.ticket_body) + self.label_3 = QtGui.QLabel(Dialog) + self.label_3.setObjectName("label_3") + self.verticalLayout.addWidget(self.label_3) + self.error_log = QtGui.QPlainTextEdit(Dialog) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.error_log.sizePolicy().hasHeightForWidth()) + self.error_log.setSizePolicy(sizePolicy) + self.error_log.setObjectName("error_log") + self.verticalLayout.addWidget(self.error_log) self.lower_layout = QtGui.QHBoxLayout() self.lower_layout.setSpacing(5) self.lower_layout.setContentsMargins(-1, 0, -1, -1) @@ -67,6 +81,8 @@ def retranslateUi(self, Dialog): Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Report a bug!", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("Dialog", "Subject:", None, QtGui.QApplication.UnicodeUTF8)) self.cc_label.setText(QtGui.QApplication.translate("Dialog", "CC:", None, QtGui.QApplication.UnicodeUTF8)) + self.label_2.setText(QtGui.QApplication.translate("Dialog", "Description:", None, QtGui.QApplication.UnicodeUTF8)) + self.label_3.setText(QtGui.QApplication.translate("Dialog", "Error Log:", None, QtGui.QApplication.UnicodeUTF8)) self.screen_grab.setText(QtGui.QApplication.translate("Dialog", "Take a screenshot!", None, QtGui.QApplication.UnicodeUTF8)) from . import resources_rc diff --git a/resources/app_ui.png b/resources/app_ui.png new file mode 100644 index 0000000..401cc41 Binary files /dev/null and b/resources/app_ui.png differ diff --git a/resources/dialog.ui b/resources/dialog.ui index b41ad93..65e9fcc 100644 --- a/resources/dialog.ui +++ b/resources/dialog.ui @@ -6,8 +6,8 @@ 0 0 - 431 - 392 + 452 + 490 @@ -42,6 +42,13 @@ + + + + Description: + + + @@ -52,6 +59,23 @@ + + + + Error Log: + + + + + + + + 0 + 1 + + + +