Skip to content

Refactor extract conversation FileWidget #1369

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

Conversation

gonzalo-bulnes
Copy link
Contributor

@gonzalo-bulnes gonzalo-bulnes commented Dec 7, 2021

Description

This is preliminary work relevant to #1354. This PR moves (but doesn't otherwise modify) the widgets involved in drawing the files (FileWidget) in the conversation timeline. Providing user feedback while downloading the files will expand on existing FileWidget behavior, and it will be easier to manage change in a small file than it would be in widgets.py.

Goal: Make clearer which widgets depend on which, and package together the ones that are likely to change together. For the package names, I went for "domain concepts" (e.g. Source, Conversation, authentication...) and features (e.g. export, print...). The idea is that the domain should only change slowly (stability is good) and features can be added or removed all at once, so it's nice when they're relatively independent and clearly identified. Naming is hard and YMMV, please comment what you think!! 🙂

Package structure at this point

tree securedrop_client/gui/

securedrop_client/gui/     # These UI components are known externally as...
├── __init__.py
├── auth
│   ├── __init__.py
│   └── dialog.py          # ...LoginDialog
├── base   # Contains generic components (e.g. PasswordEdit, toggle button...)
│   ├── __init__.py
│   ├── buttons.py
│   ├── dialogs.py 
│   ├── inputs.py 
│   └── misc.py     
├── conversation
│   ├── __init__.py
│   ├── export
│   │   ├── __init__.py
│   │   └── dialog.py      # ...ExportDialog
│   ├── file.py            # ...FileWidget
│   └── print
│       ├── __init__.py
│       └── dialog.py      # ...PrintDialog, eventually print.Dialog etc.
├── main.py
└── widgets.py

Closes #1340

Test Plan

  • Confirm that CI build is green
  • Confirm that the FileWidget appearance hasn't changed
  • Confirm that the Login, Export and Print dialogs looks the same as usual
  • Check that the documentation headers of the new packages make sense

Checklist

If these changes modify code paths involving cryptography, the opening of files in VMs or network (via the RPC service) traffic, Qubes testing in the staging environment is required. For fine tuning of the graphical user interface, testing in any environment in Qubes is required. Please check as applicable:

  • I have tested these changes in the appropriate Qubes environment
  • I do not have an appropriate Qubes OS workstation set up (the reviewer will need to test these changes)
  • These changes should not need testing in Qubes

If these changes add or remove files other than client code, the AppArmor profile may need to be updated. Please check as applicable:

  • I have updated the AppArmor profile
  • No update to the AppArmor profile is required for these changes
  • I don't know and would appreciate guidance

If these changes modify the database schema, you should include a database migration. Please check as applicable:

  • I have written a migration and upgraded a test database based on main and confirmed that the migration applies cleanly
  • I have written a migration but have not upgraded a test database based on main and would like the reviewer to do so
  • I need help writing a database migration
  • No database schema changes are needed

The FileWidget is only ever used as part of a conversation,
and the new package structure reflects that.

I only touched the related files and I grouped them around
domain concepts and features.
@gonzalo-bulnes gonzalo-bulnes requested a review from a team as a code owner December 7, 2021 08:12
The packages provide namespacing, and class names don't need to
be globally unique. Simpler names also make easier to highlight
the parallels between different packages.

def test_class_name_matches_css_object_name_for_export_dialog(export_dialog):
assert "ExportDialog" == export_dialog.__class__.__name__
def test_preferred_name_matches_css_object_name_for_export_dialog(export_dialog):
assert "ExportDialog" in export_dialog.passphrase_form.objectName()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These two specific assertions are not met anymore. I decided not to touch the stylesheet in order to keep the changes scoped (they're large already 😬).
Eventually, I think that breaking the stylesheet into smaller files that follow the package structure would make maintenance easier, and also would make redundant the need to have global matching names for Python classes and QSS names.

Until then, PrintDialog and ExportDialog seems to me that they remain the most appropriate QSS names for conversation.ExportDialog and conversation.PrintDialog (even though they are called export.Dialog and print.Dialog as an implementaiton detail of the conversation package.) Does this make sense?

Copy link
Contributor

Choose a reason for hiding this comment

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

The convention, enforced by these tests, is to use the class name as the object name in the CSS to make it easier to find the relevant code. For now, let's stick to this convention and rename the CSS objects to match the new class names. This will make it cleaner when you're ready to move the relevant CSS code to the new project structure.

Copy link
Contributor

@sssoleileraaa sssoleileraaa Dec 14, 2021

Choose a reason for hiding this comment

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

The direction of this PR is great! I just have one main concern, which is that this change, left as is, breaks a couple conventions:

  • tests should exist in a test structure that mirrors the project structure, e.g. tests that test securedrop_client/gui/dialogs.py need to go in tests/gui/test_dialogs.py, not tests/gui/test_widgets.py
  • CSS object names should match the Python classes they are used in

If you refactor one class at a time, you can migrate the relevant tests so that you don't break these conventions, and it's still small enough for the reviewer.

Also, regarding CSS, were you thinking of doing something like this eventually?

styles/gui
├── auth
│   └── dialog.css
├── buttons.css
├── conversation
│   └── print
│       └── dialog.css
├── dialogs.css
└── ...

Or would you move the CSS files into the project structure like this:

securedrop_client/gui
├── __init__.py
├── auth
│   ├── __init__.py
│   └── dialog.py
│   └── dialog.css
├── buttons.py
├── buttons.css
├── conversation
│   ├── __init__.py
│   ├── export
│   │   ├── __init__.py
│   │   └── dialog.py
│   ├── file.py
│   └── print
│       ├── __init__.py
│       └── dialog.py
├── dialogs.py
├── dialogs.css
└── ...

Or keep it flat:

styles
├── auth_dialog.css
├── print_dialog.css
├── dialogs.css
└── ...

Copy link
Contributor Author

@gonzalo-bulnes gonzalo-bulnes Dec 14, 2021

Choose a reason for hiding this comment

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

I can add those changes 👍

Regarding the stylesheets location, I have a strong preference for the second layout you described, where the all the parts of a given component are grouped together, for a few reasons:

  • That option splits concerns by component, which in our case closely aligns with the domain boundaries (e.g. auth, conversation, source, "conversation export feature", "source deletion feature" are concepts that are shared by the team beyond the code.)
  • That option also makes clear the fact that components are scoped to themselves. Because all the files are grouped together it makes less likely that dependencies will be drawn from unrelated places.
  • I find the separation by language just as arbitrary and not very convenient in practice when I work with components. After all, QSS and Python code do indeed change together (we even have tests to check object names and QSS names are in sync!). YMMV (Support material - that entire side deck is interesting IMHO)

What do you think @creviera? (and @rocodes @Er1kkkaaa!)

Note: this thread is relevant to #303

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with your points. 🚀

Since there's a lot of code moving around, it might make sense to break this up into multiple commits or PRs scoped to moving one class/file at a time, e.g. move ModalDialog and any associated css and tests from widgets.py, test_widgets.py, and some-name.css into dialogs.py, test_dialogs.py, and dialog.css. This should make both of our lives much easier during the migration and review of the migration. Otherwise, I'm down for a slower review where I piece it all together in the diffs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since there's a lot of code moving around, it might make sense to break this up into multiple commits or PRs scoped to moving one class/file at a time [...]

Yes! I was thinking the same, I'll "re-package" this PR (and #1373) into one-class-at-a-time chunks. 👍

Copy link
Contributor Author

@gonzalo-bulnes gonzalo-bulnes Dec 15, 2021

Choose a reason for hiding this comment

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

For road mapping purposes, I'll proceed as follows:

I'm not 100% sure about the end of the sequence, but I'll update when we get there.

@sssoleileraaa
Copy link
Contributor

@gonzalo-bulnes should we close this PR since you're breaking it up now?

@gonzalo-bulnes
Copy link
Contributor Author

gonzalo-bulnes commented Dec 19, 2021

@creviera The review plan here is:

Happy to 🍐 on this (you review, I rebase the branches as we go).

⚠️ Note:

@creviera Before merging [any of these] PR[s], let's talk about signatures. It seems that the author signature gets stripped when merging without a merge commit, resulting in an unsigned commit in main. We could put extra attention on this one and see if we can merge while preserving the signatures on the commits that introduce diffs. (The automated merge commit should be empty because we update/rebase out branches before merging.) (original comment)

@gonzalo-bulnes
Copy link
Contributor Author

I'll close this PR, as the updated checklist is done now 🙂

Note that nor all the moves were actually performed (initial intent), but I think those can be performed as we go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants