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

Add support for Polls Widget on ZT. #1551

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

Conversation

rsashank
Copy link
Member

@rsashank rsashank commented Oct 9, 2024

What does this PR do, and why?

Add support to view polls

External discussion & connections

How did you test this?

  • Manually - Behavioral changes
  • Manually - Visual changes
  • Adapting existing automated tests
  • Adding automated tests for new behavior (or missing tests)
  • Existing automated tests should already cover this (only a refactor of tested code)

Self-review checklist for each commit

  • It is a minimal coherent idea
  • It has a commit summary following the documented style (title & body)
  • It has a commit summary describing the motivation and reasoning for the change
  • It individually passes linting and tests
  • It contains test additions for any new behavior
  • It flows clearly from a previous branch commit, and/or prepares for the next commit

Visual changes

Before After Webapp
image image image

@zulipbot zulipbot added the size: XL [Automatic label added by zulipbot] label Oct 9, 2024
@rsashank rsashank added PR needs review PR requires feedback to proceed area: widgets labels Oct 10, 2024
Copy link
Collaborator

@neiljp neiljp left a comment

Choose a reason for hiding this comment

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

@rsashank This update looks good, and being able to see the poll votes is useful. This looks fine in a separate popup for now 👍

Having polls update via events would be the obvious next step here, though we may want to focus on merging the todo PR first to make integrating this easier?

zulipterminal/widget.py Outdated Show resolved Hide resolved
zulipterminal/ui_tools/messages.py Outdated Show resolved Hide resolved
zulipterminal/ui_tools/views.py Outdated Show resolved Hide resolved
Comment on lines 295 to 299
voter_names = []
for voter_id in voter_ids:
user_info = self.model.get_user_info(voter_id)
if user_info:
voter_names.append(user_info["full_name"])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this new data structure code here, instead of the new view class, since it accesses the model, or for some other reason?

In any case, user_name_from_id would be a lighter-weight function to use, if only accessing the name.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I included it here since I'm accessing the model.

Got it, updated with user_name_from_id.

Copy link
Collaborator

Choose a reason for hiding this comment

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

You addressed the latter point, but I'm not sure why the conversion into the format required for the popup occurs here, rather than in the popup code itself?
(this was my first point above)

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops my bad, I had a response written that I forgot to submit as a review.

zulipterminal/core.py Show resolved Hide resolved
@neiljp neiljp added PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback and removed PR needs review PR requires feedback to proceed labels Oct 23, 2024
Added process_poll_widget function to process submessages
containing a poll widget. Returns the question of the poll
along with options and their voters in a dict.
SHOW_POLL_VOTES : 'v' to check votes for a given poll.
Takes poll_question and options as an input and displays
voters for each option.
Creates an instance of PollResultsView class and shows the popup.
This prevents an empty-title popup in the Poll Results view.
@rsashank rsashank added PR needs review PR requires feedback to proceed and removed PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback labels Nov 4, 2024
Copy link
Collaborator

@neiljp neiljp left a comment

Choose a reason for hiding this comment

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

@rsashank Thanks for the update - this looks rather close to being ready 🎉 I tested this manually and had to remind myself why the poll updates were working even though you didn't add them in this PR! 😮

Generally, there are a few nits I noticed similar to the other PR and to avoid duplication, a few improvements to the popup, and some small possible restructuring.

The main point left to discuss is probably the key to use - or where to connect the popup to. That's not critical before merging, though I'm often wary of accepting a new hotkey unless we know it's "safe" and won't impact things later. It's easy enough to change in a later commit, but since we're not currently releasing regularly then in principle anyone may use this and start using the hotkey!

If the latter becomes a sticking point, we can certainly merge the main part first, and leave the popup part to another PR (or similar).

poll_widget = (
f"<strong>Poll\n{poll_question}</strong>"
if poll_question
else "No poll question provided. Please add one via the web app."
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: For this line and one further below, we might consider using a fixed string common to both cases, and adding a TODO comment which relates to the lack of this feature so far (in ZT).

Comment on lines +774 to +777
if not self.poll_question:
# If no poll question is provided, set a message to display
# in Poll Results popup.
self.poll_question = "No poll question provided."
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can do this last commit as part of an earlier commit when you first write this code, ie. setting a variable. This same text is used directly above, so that will avoid duplication. When you do the adding of the self. prefix, the variable will already be available.

@@ -1185,4 +1186,6 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
self.model.controller.show_emoji_picker(self.message)
elif is_command_key("MSG_SENDER_INFO", key):
self.model.controller.show_msg_sender_info(self.message["sender_id"])
elif is_command_key("SHOW_POLL_VOTES", key) and self.widget_type == "poll":
Copy link
Collaborator

Choose a reason for hiding this comment

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

For no options, the popup operates but shows no data - maybe we should just skip the popup if there is no extra data to show?



@pytest.mark.parametrize(
"submessage, expected_poll_question, expected_options",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: plural, as in other PR.

"canned,1": {"option": "No", "votes": []},
"32159,1": {"option": "Maybe", "votes": [32159]},
},
id="poll_widget_with_multiple_voters",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: This test is known to be a poll_widget already, as with other PR.

self,
controller: Any,
poll_question: str,
poll_options: Dict[str, Dict[str, Any]],
Copy link
Collaborator

Choose a reason for hiding this comment

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

This type seems inaccurate? This is one benefit of defining more complex data types that you're passing around, even if via typeddicts, since you can refer to them as a name and update them in one place.

voters_display = (
"\n".join(map(str, voter_names))
if voter_names
else f"{INVALID_MARKER} No votes yet"
Copy link
Collaborator

Choose a reason for hiding this comment

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

This does make it stand out better 👍


options_with_names[option_key] = {
"option": option_text,
"votes": voter_names if voter_names else [],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: Is this conditional necessary?

def show_poll_vote(
self,
poll_question: str,
options: Dict[str, Dict[str, Any]],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Assuming this is poll_options, this type is different again?

Comment on lines +763 to +764
elif self.widget_type == "poll":
self.poll_question, self.poll_options = process_poll_widget(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: You've added self.widget_type, but not initialized the others earlier in this commit.

@neiljp neiljp added PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback and removed PR needs review PR requires feedback to proceed labels Nov 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: widgets PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback size: XL [Automatic label added by zulipbot]
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants