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 typing indicators for streams. #17040

Closed
wants to merge 6 commits into from
Closed

Conversation

chdinesh1089
Copy link
Collaborator

@chdinesh1089 chdinesh1089 commented Jan 11, 2021

Fixes #11152

This is almost done. Things left to be done are

  • Fix and add few frontend tests.
  • Document the new arguments stream_id and topic for api/v1/typing in zerver/openapi/zulip.yaml.
  • Send typing notification only if the topic already exists as we want to show typing notification only in a topic narrow.

Sending a request to streams with 0 or 1 subscriber(only sender) won't throw any error. Do we want to return any error for that?

@chdinesh1089 chdinesh1089 changed the title Add typing indicators for streams. [WIP]Add typing indicators for streams. Jan 11, 2021
@chdinesh1089
Copy link
Collaborator Author

@showell I see this in the issue page.

This is a non-trivial feature, and you'll want to discuss performance on #backend.

Could you do a review and tell if I should open a thread for this in #backend

@@ -1888,20 +1888,27 @@ def do_send_typing_notification(
realm: Realm,
Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer to just have a separate action function for stream notifications, so that you don't need the optional parameters and the conditional logic. Two simple functions are better than one complex one, and we're not really sharing any useful logic here.

I would also consider just having a new type (no pun intended) for the event with the value stream_typing, so that the documentation piece is easier here (again, no Union types would be needed).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, having a different type would make it simpler and separating the function will make it seem less complex. Will make the required changes.

(Thought I'd make the changes and ask for another review soon but not I'm getting a chance to work on this as most of my time is going into academics. Leaving an update since it's been 2weeks..:)

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

Yeah, I think the separate function makes sense, with a bit of preparatory refactoring to avoid duplicating code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Separated the function. There wasn't much duplicate code.

Also added type stream_typing.

zerver/views/typing.py Outdated Show resolved Hide resolved
zerver/lib/actions.py Outdated Show resolved Hide resolved
@chdinesh1089
Copy link
Collaborator Author

chdinesh1089 commented Feb 10, 2021

Sorry for the delay. Haven't been getting time due to academics. Our teachers are tending to give more assignments as everything is online 😬

Made the changes based on reviews. I'll try to do the other work i.e adding frontend tests and documenting in the weekend.

@@ -263,6 +264,7 @@ run_test("basics", () => {
// test that we correctly detect if worker.get_recipient
// and typing_status.state.current_recipient are the same

compose_state.get_message_type = () => "private";
compose_pm_pill.get_user_ids_string = () => "1,2,3";
typing_status.state.current_recipient = typing.get_recipient();

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I haven't added/modified tests here as it's intended to test typing_status.js to which this PR makes no changes. But we make use of this module to send start/stop requests from client which only extends the possible values for status.current_recipient to also be an object consisting stream_id and topic. since we only check if current recipient is equal to previous recipient, adding tests to include recipient format of object:stream_id, topic will be redundant and won't add much value I think.

Will add few tests to also include that format for current_recipient if you think it's necessary.

@chdinesh1089
Copy link
Collaborator Author

chdinesh1089 commented Feb 20, 2021

Do we want to show "several people are typing..." only for streams or for PMs too if more than 3 users are typing? (The PR shows it for both)

@chdinesh1089 chdinesh1089 force-pushed the typing branch 5 times, most recently from c3f0c47 to 6bb27dc Compare March 6, 2021 19:13
@chdinesh1089 chdinesh1089 changed the title [WIP]Add typing indicators for streams. Add typing indicators for streams. Mar 6, 2021
@chdinesh1089
Copy link
Collaborator Author

chdinesh1089 commented Mar 6, 2021

You can ignore the below. Was not much familiar with API docs and tests, and ended up generating a wrong curl example. Fixed and added examples for python too. Didn't add any js example for stream typing as this params.to.length in zulip-js causes an error because there's no params.to in stream typing case.


How do I fix the API test failure? I'm unable to figure out a solution. Here's the issue:
We now added to extra params(stream_id, topic that could be sent to json/typing. The test_curl_examples is failing as it's generating an example consisting of all three parameters which gives an error according to the actual code but the test is asserting it with a success message.

Tried adding this in zulip.yaml, but it still didn't work.

        "400":
          description: Bad request.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/JsonError"
                  - example:
                      {
                        "code": "BAD_REQUEST",
                        "msg": "Bad arguments. Should have 'to' or both 'stream_id' and 'topic'.",
                        "result": "error",
                      }

I think we should still have this. will push it once we figure out a fix for the failure.

@@ -1081,6 +1081,7 @@ def set_typing_status(client: Client) -> None:
"to": [user_id1, user_id2],
}
result = client.set_typing_status(request)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added this space(and below) intentionally to make it look good in API docs with each of start, stop separated as a different chunk.

For the timing part of sending requests,
it will be same as pms as the code in typing_status.js
is being reused for that purpose.

As a note, `state.current_recipient` and `new_recipient` of update()
in typing_status.js used to be a string of recipients ids always
previously but it can now be either of:
1) An object of format {stream_id: 2, topic:'hello'}
2) a string of recipient user ids like previously

Also made required changes in typing_status.js and
typing_status.js.flow i.e documenting the new format of
new_recipient.
We used this function to show who's typing in private messages narrow.
With addition of stream typists to `typist_dct` in next commit,
this might be confusing. So, renamed it.
This commit adresses the discussed issue by replacing get_all_typists()
with get_all_pms_typists().
These existing typing related functions are re-usable in case of
stream typing except that the key differs. So, to make it possible to
re-use the code in these functions, this commit removes the `get_key`
call in those functions and instead passes the key directly.

Also, renamed `get_key` to `get_pms_key` to differentiate it
from the `get_topic_key` we'll add later for stream typing.
Returns `stream_id` if narrowed to stream else `undefined`.

Required for displaying stream typing notifications.
@chdinesh1089
Copy link
Collaborator Author

A write up as requested in #19200 (comment)

For the typing notifications one, I'd really appreciate your doing a bit of a writeup on the strategy for how you managed the issues around potential for duplicated code, since that's the thing I've been stuck on in thinking about that PR.

Sending start/stop notifications

This primarily relies on static/shared/js/typing_status.js for the timing part i.e when (or how often) to send start/stop. typing_status.update(worker, new_recipient), the only function used outside of its module, is called (from static/js/typing.js) every time we might want to send a notification and it takes care of the rest. The worker argument is expected to look as follows:

    const worker = {
        get_current_time,
        notify_server_start,
        notify_server_stop,
    };

notify_server_start(to) (and _stop) are just functions that send relevant requests taking in the recipient as to.

The only part that changes when we integrate stream typing notifications is, the new_recipient(and to) argument. Previously, it used an array of user IDs. Now, it can also be an object({stream_id, topic}). There's no problem with typing_status.update to support the new possibility for new_recipient. So, we do not need any functional changes in typing_status.

But the insides of notify_server_start/stop would require a few if/elses, So I've extracted those into smaller functions. I think that'll be clear on looking at typing.js.

(All this is done in the first commit)

Displaying typing... notifications for the receiver

The flow of this so far looks as follows:

  1. server_events_dispatch.js calls typing_events.display_notification(event) upon receiving a typing notification
  2. display_notification stores the typists into typing_data.typist_dct using typing_data.add_typists(key, sender_id). This data is later used to actually display typists based on narrow where the key in typing_data.add_typists indicates the narrow. (for e.g. it is a string of sorted user ids for group pms)
  3. Actually display typing notifications using typing_events.render_notifications_for_narrow(). This also takes care of hiding notifications. This function also has some calls in narrow.js to make sure these notifications are displayed correctly when a narrow is changed.
  4. Start timer to hide the notification hide_notification which also takes care of removing typists from typing_data.typist_dct using typing_data.remove_typists(key, sender_id).

The flow is the same for stream typing notifications too but now we want to store {stream_id, topic} along with typists in typing_data.typist_dct but that wouldn't be cleaner with two possible forms of key value when we rely on the key format at a few other places for fetching typists. So I added pm_typists_dict, and stream_typists_dict and removed the earlier one. The add_typist(key, typist) now becomes add_typist(key, typist, message_type) to separately store the typists into their respective dicts. Similarly for remove_typist too. The message_type is sent using event.message_type in typing_events.js.

typist_data.js also has functions for proper generation of keys for each type of message: get_pms_key, get_topic_key. These are used in a bunch of places to get items from the two dicts. I recommend checking their references.

typist_data.js also has inbound_timer_dict which keeps track of timer ids of setTimeouts to remove typists. Using this for both stream and private notifications wouldn't do any harm and keep things simple. Moreover, the wrapper functions clearing these receive the key. So, writing if/else here by creating two objects each for stream and private will only complicate things.

Display/hide "X is typing" notification
on receiving start/stop typing event for streams.
Filters muted users in get_stream_typists().
@timabbott timabbott added release goal We'd like to resolve this for the current major release and removed post release Issues to focus attention on after the current major release labels Apr 14, 2022
@zulipbot
Copy link
Member

Heads up @chdinesh1089, we just merged some commits that conflict with the changes your made in this pull request! You can review this repository's recent commits to see where the conflicts occur. Please rebase your feature branch against the upstream/main branch and resolve your pull request's merge conflicts accordingly.

@timabbott timabbott added the chat.zulip.org review Added by maintainers when a PR requires chat.zulip.org testing to proceed. label Jul 28, 2022
@timabbott timabbott added post release Issues to focus attention on after the current major release and removed release goal We'd like to resolve this for the current major release labels Nov 2, 2022
@pdurbin
Copy link
Collaborator

pdurbin commented Mar 17, 2023

@chdinesh1089 hi! I'd love to see typing indicators for streams and it seems like this PR of yours gets us there! Thanks! ❤️

I noticed a related topic in chat and asked about this PR there. It sounds like the next step is to rebase. I just thought I'd pass that along. Have a great weekend! 🏖️

@brijsiyag
Copy link
Member

In the event that @chdinesh1089 has no intention of working on it, I would be interested in taking over. Thank you!!

@pdurbin
Copy link
Collaborator

pdurbin commented Mar 20, 2023

@brijsiyag great! Locally I rebased main as of b21d93c into this branch and the merge conflicts don't look too bad. There were two auto merges and one test file that needs to be fixed manually:

Auto-merging web/src/typing.js
Auto-merging web/tests/typing_status.test.js
CONFLICT (content): Merge conflict in web/tests/typing_status.test.js

Here are the two places where typing_status.test.js has conflicts, in only a few lines:

Screenshot 2023-03-19 at 9 00 10 PM

Screenshot 2023-03-19 at 9 00 31 PM

I hope this helps either you or @chdinesh1089. ❤️

I haven't set up a dev environment yet, but maybe I can help with testing or something. 😅

Update (after setting up a dev environment): Here's how I resolved the conflicts above:

diff --git a/web/tests/typing_status.test.js b/web/tests/typing_status.test.js
index 9fea40a7f4..8e073f5b69 100644
--- a/web/tests/typing_status.test.js
+++ b/web/tests/typing_status.test.js
@@ -6,6 +6,7 @@ const {mock_esm, set_global, zrequire} = require("./lib/namespace");
 const {run_test} = require("./lib/test");
 
 const compose_pm_pill = mock_esm("../src/compose_pm_pill");
+const compose_state = mock_esm("../src/compose_state");
 
 const typing = zrequire("typing");
 const typing_status = zrequire("../shared/src/typing_status");
@@ -265,6 +266,7 @@ run_test("basics", ({override, override_rewire}) => {
     // and typing_status.state.current_recipient are the same
 
     override(compose_pm_pill, "get_user_ids_string", () => "1,2,3");
+    override(compose_state, "get_message_type", () => "private");
     typing_status.state.current_recipient = typing.get_recipient();
 
     const call_count = {

After committing I realized there were further conflicts in these files:

  • web/src/typing_data.ts
  • web/tests/typing_data.test.js

I'm not sure where the conflicts end, to be honest.

@chdinesh1089
Copy link
Collaborator Author

Thanks for bumping this thread, @pdurbin!

I haven't been getting much free time these days. I might delay this if I pick up again. I'd be super happy to see this feature merged soon so I'd appreciate if @brijsiyag or anyone would like to take this forward. 🙂

@pdurbin it's quite simple to setup development environment. see https://zulip.readthedocs.io/en/latest/development/overview.html

@pdurbin
Copy link
Collaborator

pdurbin commented Mar 24, 2023

@chdinesh1089 sure. Coming from Slack and Matrix, I'm interested in this feature.

@brijsiyag are you interested in taking over? I do have a dev environment set up now (you're right, @chdinesh1089, not too bad to set up), but I'm having trouble resolving all the merge conflicts. I put a few additional details in my comment above. There are more conflicts than I realized. (I'm used to a merge workflow rather than a rebase workflow.) Also, the label "size: XL" makes me a bit nervous, as I haven't contributed before.

@brijsiyag
Copy link
Member

@brijsiyag are you interested in taking over?

Yes @pdurbin , I'm working on this.

@timabbott
Copy link
Sponsor Member

Closing in favor of #26904, thanks for all the work on this @chdinesh1089!

@timabbott timabbott closed this Sep 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chat.zulip.org review Added by maintainers when a PR requires chat.zulip.org testing to proceed. has conflicts post release Issues to focus attention on after the current major release size: XL
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add typing indicators for streams.
7 participants