Fix a bug where the compose box didn't collapse when sending a message
from the preview area by hitting the send button. The bug ocurred because
the preview area wasn't being properly cleared when this flow was executed.
This was fixed by moving the clear_preview_area function call for a place
that will be reached by both the enter and button flow.
Fixes: #14889
Previously, we handled these updates in server_events_dispatch
and could accidentally call widget.render() before initializing
the widget.
Original report: https://chat.zulip.org/#narrow/near/875608.
The sync_realm_settings function ensures that if the settings are
not open, any updates are a noop.
If you were on "All Streams" tab and unsubscribed to a private
stream, that stream row would momentarily disappear. If you
click again on "All Streams" button, it would appear again.
The problem was that the selector was finding two elements
instead of just the tab element. To solve this we used a more
specific selector to make sure we are getting the Subscribed
tab only.
This commit fixes the bug of incorrectly showing/hiding the
realm logo delete button by using realm_night_logo_source for
checking the source of night mode logo instead of previously
used realm_logo_source for both day and night logos.
When a user changes its avatar image, the user's avatar in popovers
wasn't being correctly updated, because of browser caching of the
avatar image. We added a version on the request to get the image in
the same format we use elsewhere, so the browser knows when to use the
cached image or to make a new request to the server.
Edited by Tim to preserve/fix sort orders in some tests, and update
zulip_feature_level.
Fixes: #14290
* Remove old topic and reprocess both old and new topic to ensure
that we are correctly storing the last_msg_id of users in the
topic. Also, Handle topic's stream (& topic) edit updates.
* Add function to get all messages in a topic in message_utils.js.
* Send topic edit event to recent_senders.
* Add func get sorted list of recent_senders to topic.
The function will be useful to handle topic edits in Recent Topic UI.
This commits improves how we handle <a> tags within the navbar
description. The code previously overlaid click regions on top of each
other, which was messy and probably somehow buggy.
It is cleaner if we just check if the click was on an <a> tag or not.
* This feature is currently only visible to admins.
* Locally echoed messages are also updated.
* Add UI for editing stream if user is admin.
* Show propagate mode selector if either stream or topic changed.
We use this new widget in bot settings panels
(personal and org). It lets you re-assign a
bot to a new human user.
Ideally we can improve this code to use
our existing list widgets to make it more
performant for realms with lots of users.
We no longer use `/json/users` in the codepath
for bot settings (admin side).
We also specifically don't load human users when
we load bots, so you no longer have to pay for
the server round trip as a side effect of loading
bots. Instead, there is a dedicated `set_up_bots`
entry point.
We also get the bot ids directly from `bot_data` now.
This commit, to some degree, builds on the prior commit
that had us hydrate data from `people.js` instead
of the payload from `/json/users`.
Our `list_render` list widget gives us the
option to use ids as our "list" and then
hydrate that list on-demand with an
`opts.get_item` function.
We now use that for the bots list, passing
in `bot_info` as that option.
And, importantly, we are now actually
hydrating the bot data from `bot_data.js`
data structures, and not `/json/bots`.
Using the `get_item` scheme has a couple
benefits:
- Our sort functions are based on the
actual items that we use to build the
template, so there's a bit less
code duplication. (Generally, the
data that we pass in to the template
is "finalized" in some sense, such
as the bot owner name.)
- We are less likely to display stale
data.
- We are less likely to wire up filters
to intermediate data elements that are
not actually displayed to users (think
of email vs. delivery_email).
We do rely on `get_item` (i.e. `bot_info`)
to be inexpensive, which it should be.
Note that we haven't completely decoupled
ourselves from `/json/bots`, which we still
use as our source for bot user_ids. We will
fix that in the next commit.
We want to move toward having list consumers
pass us in a list of ids that we hydrate later
in the process. This should help live-update
scenarios. The next commit will describe the
benefits in a bit more detail, using the
concrete example of our bot settings table
in the org settings.
A slightly longer-term goal here is to be
able to ask `list_render` to re-render a particular
id, and this moves us closer to that. But even
before that, this change should eliminate a class
of bugs dealing with stale data, such as when
you manually patch a list (with direct jQuery
hacks) but then later go to sort/filter the rows.
We will now re-hydrate the items in those scenarios.
We don't really need to know whether we've loaded
the user-related panels, since we only used `meta.loaded`
for a tiny optimization to avoid a jQuery lookup.
We rely mostly on the list widgets from `list_render`,
and they are smart enough to repopulate themselves
when they're called subsequent times.
For the below payloads we want `owner_id` instead
of `owner`, which we should deprecate. (The
`owner` field is actually an email, which is
not a stable key.)
page_params.realm_bots
realm_bot/add
realm_bot/update
IMPORTANT NOTE: Some of the data served in
these payloads is cached with the key
`bot_dicts_in_realm_cache_key`.
For page_params, we get the new field
via `get_owned_bot_dicts`.
For realm_bot/add, we modified
`created_bot_event`.
For realm_bot/update, we modified
`do_change_bot_owner`.
On the JS side, we no longer
look up the bot's owner directly in
`server_events_dispatch` when we get
a realm_bot/update event. Instead, we
delegate that job to `bot_data.js`.
I modified the tests accordingly.
This fixes the fact that we update the bot table
with the owner's email instead of a name, but as
the TODO indicates, this is not a full fix, since
I don't linkify the owner name.
To do the full fix properly, I want to make it
so that the `list_render` widgets can just be given
an id of a row to update, and that's coming soon,
hopefully. If I get sidetracked, the ugly ways to
do this are one of the following:
- just duplicate what the template does in
jQuery
- extract a partial to draw the bot owner link
The full solution here should fix ALL the live
update code in `update_user_data`, which is why
I'm hesitant to add any interim complexity.
This is just a lexical change. We are going
to use some shared code soon that we don't want
to export, and if `update_user_data()` is
declared too early in the file, then the function
we extract will either need to be exported (to
satisy the linter) or placed far away from its
most natural siblings.
We will use this for a patch to the live-update
code, and it also de-clutters `bot_info`.
This function could plausibly live in `people.js`,
but it's not worth the indirection at this time,
and, also, one of the upcoming callers to the
function will only temporarily need it.
There's a little bit of a chicken/egg problem
going on:
- It's hard to have nice system-wide
APIs related to bots while bot settings
are still in flux.
- It's hard to clean up the bot settings
code while the system-wide API is still
kinda messy.
But I'm making slow progress on that front.
Instead of taking a subsection option and calling the settings_org
function to update that subsection, we now take a callback function
as on_update. Also, we now store the value initial value of the
widget in opts.value instead of reading again from page_params.
These changes allow us to use this widget outside of settings_org
and for values other than settings that are in page_params.
We now no longer have to remember that
`is_guest` is on `user` but `is_current_user`
is in `..`.
And we no longer have to remember that
`full_name` is on `user` but `display_email`
is in `..`.
We now gather all the bot info in one place, rather
than grabbing some of it during the triage phase and
then some of it later.
We also explicitly copy over the fields that we
need for the template, in preparation for two
efforts:
- We want to get data from `people.js` and
avoid the round trip to `<server>/json/users`.
- We want to simplify the template by
flattening our data. (It's really somewhat
arbitrary whether `is_admin` is a calculated
value, for example, but we currently leak
that implementation detail to the template.)
We can't flatten this data quite yet, since we
share the same template for bot users as human users,
so we'll fix the human data in a bit.
We now close on status_field in our event handlers,
so that there's no chance of writing to the wrong
status field if somebody switches panels before
we have a status to report.
We can't eliminate `get_status_field` yet, but that
will go away in a future commit.
We now create the event handlers directly in
`set_up()`, and we explicitly tie them to
each of the three tables.
The goal here is to allow us to set up
the three tables individually, and this gets
us closer to that goal.
This is a purely lexical move (apart from changing
a closure variable to an argument), which is
simply designed to make less indentation for the
reader and to de-clutter `handle_human_form`.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
This is purely refactoring.
The new call tree is:
on_load_success
populate_users
handle_deactivation
handle_reactivation
handle_user_form
handle_bot_owner_profile
handle_bot_deactivation
The actual sequence of operations should be
identical to before.
When reading the calling code, it's helpful to know
that we're really just passing in a selector. The
calls to open_modal/close_modal are nicer now to
reconcile with surrounding code, and you don't have
to guess whether the parameter is some kind of
"key" value--it really just refers directly to a DOM
element.
There is nothing user-visible about this change, but
the blueslip info messages now include the hash:
open modal: open #change_email_modal
Since production testing of `message_retention_days` is finished, we can
enable this feature in the organization settings page. We already had this
setting in frontend but it was bit rotten and not rendered in templates.
Here we replaced our past text-input based setting with a
dropdown-with-text-input setting approach which is more consistent with our
existing UI.
Along with frontend changes, we also incorporated a backend change to
handle making retention period forever. This change introduces a new
convertor `to_positive_or_allowed_int` which only allows positive integers
and an allowed value for settings like `message_retention_days` which can
be a positive integer or has the value `Realm.RETAIN_MESSAGE_FOREVER` when
we change the setting to retain message forever.
This change made `to_not_negative_int_or_none` redundant so removed it as
well.
Fixes: #14854
It's a preliminary step to enable message_retention_setting in org settings
UI, which is a non-limited plan only feature. So we require a page_param
property that tells us the limited-plan state of the Zulip realm.
This change makes `.get_input_element_value()` return a `undefined` instead
of `null` when `input_type` is not defined. Which also make sense
logically, as
> null: absence of value for a variable;
> undefined: absence of variable itself;
Source: https://stackoverflow.com/q/5076944/7418550
In our recent navbar changes, we made it so that the
Esc key auto-closed the navbar. Unfortunately,
that code would break other typeaheads with a traceback.
One user-facing symptom was that if you drafted a PM
and started a typeahead on a recipient, then hitting
the Esc key wouldn't close the typeahead.
Now we use an `on_escape` mechanism that is specific
to the navbar typeahead, so that it's both generic and
harder to break for widgets that don't opt in to it.
See bbdc66a214 for
more details on the commit that introduced this
regression.
Note that I only call `tab_bar.exit_search` now.
I don't check the class name of the input element,
since I know that the Esc key is happening in the
context of search. And I don't blur the input,
since it's going to be hidden.
We were creating errors for task keys that were
from older versions of the widget. We don't migrate
data for the widgets yet (they're all still considered
to be somewhat beta); instead, we just drop bad data
on the floor.
Rohitt and I re-tested the widget on czo pretty
extensively to verify that these errors don't show
up for newly created widgets.
The click handler for closing stream settings in click_handlers.js
is removed as overlays.js contains common logic for closing all
overlays.
'exports.close' in subs.js is removed and 'hashchange.exit_overlay'
is used in 'overlays.open_overlay' call.
This completes the implementation of support for moving a topic to
another stream by adding a basic UI for it.
Fixes#6427, which was previously the most-upvoted issue request in
Zulip.
There are likely to be a bunch of follow-up UI improvements on top of
this change to fully flesh out the feature.
For privacy-minded folks who don't want to leak the
information of whether they're online, this adds an
option to disable sending presence updates to other
users.
The new settings lies in the "Other notification
settings" section of the "Notification settings"
page, under a "Presence" subheading.
Closes#14798.
This adds a way to keep track of max_message_id of a
stream and fetch it using the method get_max_message_id().
This will be useful for sorting streams by most recent
activity which will be implemented in the upcoming commit.
Essentially rewritten by tabbott to have a coherent tracking system,
and provide documentation.
Part of #10794.
Member of the org can able see list of invitations sent by him/her.
given permission for the member to revoke and resend the invitations
sent by him/her and added tests for test member can revoke and resend
the invitations only sent by him/her.
Fixes#14007.
This does not rely on the desktop app being able to register for the
zulip:// scheme (which is problematic with, for example, the AppImage
format).
It also is a better interface for managing changes to the system,
since the implementation exists almost entirely in the server/webapp
project.
This provides a smoother user experience, where the user doesn't need
to do the paste step, when combined with
https://github.com/zulip/zulip-desktop/pull/943.
Fixes#13613.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
Previously, a spinner was created and this spinner element passed to
do_settings_change function, which also created a spinner, making the
first spinner creation useless. This commit removes the spinner creation
logic and just passes the element where the spinner is to be rendered.
Prior to this change, there were reports of 500s in
production due to `export.extra_data` being a
Nonetype. This was reproducible using the s3
backend in development when a row was created in
the `RealmAuditLog` table, but the export failed in
the `DeferredWorker`. This left an entry lying
about that was never updated with an `extra_data`
field.
To fix this, we catch any exceptions in the
`DeferredWorker`, and then update `extra_data` to
encode the failure. We also fix the fact that we
never updated the export UI table with pending exports.
These changes also negated the use for the somewhat
hacky `clear_success_banner` logic.
This removes the weird edit-bot sidebar, replacing it with a modal,
matching our edit-user widget (and various similar ones).
Fixes#13644 by removing the buggy code.
When switching from Private Messages narrow to
All messages narrow, stream list max-height was not
correctly updated. Stream list max-height was calculated
before new height were updated by browser for
All message narrow.
Inshort:
Stream list max-height was being updated before the browser could
render height for `#global_filters`. Calling resize after narrow
completes removes this issue.
This will eventually let us delete a bit of annoying compatibility
code from the desktop app’s injected JavaScript.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
Running the close handler won’t break anything; it’s safe to delete
from a Map while iterating through it.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This exists in all versions of the desktop app that we still support,
and will eventually let us delete a bit of annoying compatibility code
from the desktop app’s injected JavaScript.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
The condition was removed because in either case we
want to have the stream_row and not the sub/unsub
button, so we can always get the stream_row directly.
We had a user have problems with the user
profile menus that you get when you click
on either sender avatars or mention pills.
If a deactivated user had a long enough email
that we would normally want to un-hide the clipboard
icon for them, we would crash inside of
`init_email_clipboard`, because the icon isn't
there for them. If the user didn't have the
console open to see the crash, the symptom
became that you would get multiple cards
visible and kind of "stuck".
I chose to fix this by just making the code
defensive with respect to the absence of the
icon, instead of short-circuiting it for
deactivated users.
It's a bit odd that we still have an element
matching `.user_email_popover` in the profile
card for deactivated users, since that element
doesn't actually include an email, but it instead
says "(This user has been deactivated)". I
considered removing the class, but the CSS
that we use for emails kind of applies here
too.
Testing this is a kind of a pain, as you want
either long emails or to just temporarily hack
this condition to true:
if (this.clientWidth < this.scrollWidth) {
// ...
}
And then test with a deactivated user, of course.
Fixes#14473
Previously, the message and event APIs represented the user differently
for the same reaction data. To make this more consistent, I added a
user_id field to the reaction dict for both messages and events. I
updated the front end to use the user_id field rather than the user
dict. Lastly, I updated front end and back end tests that used user
info.
I primarily tested this by running my local Zulip build and
adding/removing reactions from messages.
Fixes#12049.
The check here was too late, and it should
have given a blueslip error. We obviously
don't expect these errors at runtime; this
is a convenience for developers creating
new widgets.
When clicking on the tick to subscribe to a stream,
an error occurred while trying to find the spinner
location because there are two DOM elements with the
same class, sub_unsub_button, and this made the
selector get the subscribe/unsubscribe button instead
the correct stream_row, where the tick is.
We now check whether the tick or the subscribe/unsubscribe
button was clicked, and if it was the last one we make
sure the stream_row and not the button is being passed
to the sub_or_unsub function.
1. Replaced the deactivate and reactivate buttons with icons.
2. Added (you) near the current user name to denote his/her account in
the entire user list.
Tweaked by tabbott to reuse the (you) formatting from the right
sidebar here for readability and consistency.
Fixes#6313.
This commit:
- Switches margin for padding on the search closed icon, to ensure we
cover the region to the right of icon as clickable area.
- Applies the click handler that initiates the search to the second
last element of the navbar:
- This will most commonly be the narrow_description element, but may
also be the entire navbar eg in the case of "ALL" or "starred".
Applying this change to user names in "group-pm-with: ..." based
narrows is a little questionable, but there are no other triggers
on these names so this change makes sense for now.
- The narrow_description may also contain links, which need to be
handled correctly so that the behave like links should. We work
around the onClick on the narrow_description, by applying a
handler to <a> tags and invoking stopPropagation.
- We also add CSS to change the cursor to a pointer to make the
search icon change color on hover over the clickable area to
indicate that the search box can be opened with a single click.
- However, since <a> tags are handled differently, we add a hover
listener which makes sure it behaves appropriately. We also increase
the vertical padding of the <a> tags so they cover the entire
vertical navbar region.
This is a finicky change; we need to adapt around bootstrap internals
to first steal focus from the list, and then if the user uses arrow
keys, send that key to the list letting bootstrap focus on the list
elements.
The reverse: stealing abck focus to the input from the list, is not
possible without changing third/bootstrap.js because it's concept of
currently selected item depends on the item being focused. We retain
the pre-commit behavior for this, where the user can SHIFT+TAB to get
back to the input and type.
Ideally, a user will now interact with this widget like this:
1. Click the button to open the widget. The input is in focus.
2. Type a query to filter the results.
3. Seemlessly start using arrow keys to select an option.
4. Press "enter" to select the option.
We shouldn't add redundant data to page_params. Since we already have
page_params.realm_notifications_stream_id, we can use that value instead
of creating page_params.notifications_stream.
We, however, still need the name of the notifications stream to render
it in templates. Thus we create stream_data.get_notifications_stream().
This commit removes most of the duplicate logic for the stream selection
dropdowns for the settings: `realm_signup_notifications_stream_id` and
`realm_notifications_stream_id`.
We also make minot changes to DropdownListWidget to accomodate the stream
rendering of the format: `#stream_name`.
We finally switch to using stream_ids instead of stream_name everywhere
which makes reading data from page_params simpler.
'get_active_message_people` function is added which returns active
users who have sent the messages that are currently showing up in
the feed.
typeahead fetches the users from 'get_active_message_people` instead
of `get_message_people` and thus shows only active users in the
mention typeahead and excludes deactivated users.
Fixes#14310
It is more semantically accurate to remove these elements instead of
just hiding them. We were previously using a .empty().append() chain
during creation/display of these forms, hence, we clearly don't desire
to preserve the element anyway (neither are there any worthwhile
benefits of trying to).
Message_edit.js had a bug where if the inline topic_edit failed, it
would not show an error because it attempted to make a look up for
the message_id as though it were a message row edit, which would not
work. That was changed in a refactor, which made it apparent that
there was no error being rendered at all. This commit corrects it by
rendering the error, it also adds some styling to ensure the error
message is displayed inline and it makes a change to the template so
the error is rendered before the spinner.
This commit cleans up the dirty if/else structure of
handle_edit_keydown by switching to switch case statements, and also
separates the handler for inline_topic_edits and that for message
row edits.
This commit makes it so that inline (recipient bar) topic edits follow
a different path from full message row edits in `message_edit.js`.
This commit:
- deletes `.save()` endpoint and replaces all calls to it with
`.save_message_row_edit()` and `.save_inline_topic_edit()`
- deletes `.end()` endpoint and replaces all calls to it with calls to
either ".end_message_row_edit()" and ".end_inline_topic_edit()".
As long as the current narrow isn't already a search narrow or empty,
we add a single space at the end of the current filter so that the
user can just press the right arrow key and begin typing their search
term, instead of having to add a space themselves.
The set_up_muted_topics_ui and templates have been
refactored to use list_render.
This is done to support filtering and sorting of
the muted stream topics.
This also includes the addition of a new Date muted header.
This commit makes sure that we replace the text in the search box
every time a user calls `exit_search()` eg via the escape hotkey or by
clicking the `x` icon, so that the search box discards any input and
always starts at the current narrow.
The div containing options for filtering streams was placed in the
centre. Aligned it towards the right. Had to pass a special check
variable in subs.js:540 to add the specific class for this purpose.
This was a specific scenario where this sort of CSS was to be added,
hence had to make a specific case.
Also, fixed the bottom border color of the search streams bar for night
mode.
Previously, we would always pick up the stream and topic name from
compose_state. This would work for message edits as well when the
composebox was open.
Now, if we are in a message edit, we get the stream and topic of the
message being edited before falling back on trying to populate using
the composebox state.
Fixes#14545.
This commit changes the code to show user according to emails based
on email_address_visibilty_values and the type of user.
1. email_address_visibility = admins,members and guests
Typeaheads are shown according to original emails.
2. email_address_visibility = admins only
Typeaheads are shown according to original email to admins which
were previously shown according to system-generated email of
form "user10@zulipdev.com".
For non-admins, typeaheads are not shown according to emails as
they are not visible in the typeahead itself to non-admins.
3. email_address_visibility = nobody
Typeaheads are not shown according to emails for all type of users.
Previously, when email_address_visibility was set to admins only, the
non-admin users were not shown emails in typeaheads, while admins were
shown emails of the form 'user11@zulipdev.com'.
This commit corrects it to show the original emails in typeaheads and
input box of adding subscribers to admins and the behaviour is same
for non-admins.
This commit moves the get_visible_email function to people.js
as this function will be used in other places and people.js seems
relevant file for this.
Tests are added to get full coverage.
This change adds a toggle widget to the "add streams" page that
lets the user change the sort order of the streams list. So far,
this supports sorting by stream name, by number of subscribers,
or by estimated weekly traffic.
Previously, in narrow viewports, the "filter"
option would disappear, which was very confusing.
This commit moves the filter streams input to the
next line, making it visible at all viewport widths.
@showell modified the commit message and got Casper
tests passing.
Fixes#12898.
This removes the messy click-or-drag detection algorithm originally
added in fe8f63c389, which fixed a messy
bug in an earlier algorithm from ~2013, whose sole purpose as to check
whether we're doing a selection and if so, not trigger the
click-on-message-body click handler.
The right fix is of course to do that check correctly.
We can use getSelection to distinguish between clicks and drags while
accessing the body of a saved draft. Previously, the draft would be
restored when trying to select draft text to copy/paste.
Fixes#14447.
Before this change, on clicking a checkbox to toggle subscription to a
stream no UI feedback was shown and users could toggle the checkbox
multiple times to send multiple requests causing bugs. This commit
initializes a spinner on clicking the checkbox, to provide a UI feedback
to the user. This commit also disables the checkbox once a request for
subscription has been sent and re-enables the checkbox only after a
response.
This change has been accomplished by introducing a div to display the
spinner in subscription.hbs. The corresponding styles for the spinner
have been added in subscriptions.scss. The ajaxSubscribe &
ajaxUnsubscribe functions in subs.js have been updated to show & hide
the spinners for the time the request is in process. An additional
parameter, the concerned stream object is passed to these functions(
through the sub_or_unsub function) to get the location where the spinner
is to be displayed. Finally, the checkbox click handler is updated to
support these changes.
The testing for this has been done by adding a wait of 2 secs in
actions.py for the response. This gives sufficient time to test the
working manually. Also, for error cases an error has been sent from
action.py and the behaviour has been manually observed.
Fixes#14481.
Some uploads can be rejected in the frontend, like when the file
size is too big, without sending the file to the server. Remove the
'Uploading file...' message from the compose box in such cases.
Now, the system uses word='' and an editing=True for rendering an
form for addition of alert words. This is a very vulnerable
way to implement said feature and this commit fixes that.
The addition form has been moved to alert_word_settings.hbs
thereby rendering it only once but always. Now, we do not have
to manually add an empty word and editing for the form to be
rendered.
As part of refactoring, the editing parameter has also been
removed as there is no purpose left.
This updates the logged-in top navbar to display the stream/message
name, number of users, and description. It also replaces the search
bar with a search icon that expands into a full-width search bar.
Co-authored-by: Max Nussenbaum <max@maxnuss.com>
Fixes: #164.
Fixes: #5198.
In ee0d4541b4, we renamed the topic_date
-> stream_topic_history, and in the process renamed some local object
properties from .name => .topic_name, and accidentally change the
type for the data from the server as well.
The test fixtures were incorrectly migrated in the same way, so we fix
that as well.
The disabled property actually prevented text selection, so it seems
better to use CSS through the `readonly="readonly"` property.
For this, swapped .prop() with .attr() since .prop() was setting it as
`readonly=""`.
`stream_topic_history` is a more appropriate name as this
module will contain information about last message of a
stream in upcoming commits. Function and variable names
are changed accordingly like:
* topic_history() -> per_stream_history()
* get_recent_names() -> get_recent_topic_names()
* name -> topic_name
If a file cannot be added for upload because of restrictions in frontend
we call cancelAll immediately in 'info-visible' callback. This would
prevent files that are already added to be cancelled but does not cancel
files that are yet to be added. So we use break to prevent any more files
from being added.
Calling uppy.cancelAll() when a batch of uploads is completed
result in the cancelation of any other batch of uploads that is
in progress. This case happens when a user uploads some files
and then tries to upload another bunch of files before the existing
upload is completed.
The form for entering alert words has been moved above the list
of words.
The list of words will be presented alphabetically rather than
time of addition.
This refactors add_default_stream in zerver/views/streams.py to
take in stream_id as parameter instead of stream_name.
Minor changes have been made to test_subs.py and settings_streams.js
accordingly.
Added UI support for uploding the new profile picture by
clicking on the avatar rather than a button.
Added new spinner for loading indication while uploading
a new avatar over the avatar area.
Fixes#10255
The original commit here was sorting bot owners by
id, which is of course meaningless to users:
444ce74a8e
It was also returning 1/-1 in cases where the bot
owner on both sides of a comparison were missing,
which is a big no-no for sorting algorithms.
We want to avoid creating jQuery objects that just
get turned right back into strings by the list
widget, so we now have our template just include
`last_active_date` instead of kludging it in
after the fact, and we return the template
string in `modifier` rather than wrapping it.
To deal with plain HTML we switch to using
`render_now`.
Calling `render_now` leads to a more simple
codepath than `render_date`, beyond just dealing
with text.
The `render_date` function has special-case logic
that only applies to our time dividers in our
message view, which is why we were passing the
strange `undefined` parameter to it before this
fix.
The `render_date` function was also putting
the dates into `update_list` for once-a-day
updates, which is overkill for an admin screen.
We don't use this logic for drafts or attachments
either. I'm not sure how well tested that logic
is, and it's prone to slow leaks.
This commit sets us up to simplify the list
widget not to have bit-rot-prone code related
to jQuery objects.
We now:
- Skip the broken "Never" case. (The way
we were distinguishing "Unknown" from
"Never" was based on brittle checks that
were just wrong due to bitrot--see Steve
Shank on czo as an example. If we want
to make this distinction rigorous in the
future, we should have a clear mechanism.
If somebody's never actually been active,
we probably want to treat that more like
a dead-on-arrival login, anyway, and make
it easy to clean them up.)
- Use the `presence.last_active_date` instead
of reaching into private data structures.
- Avoid the unnecessary intermediate constants
of LAST_ACTIVE_NEVER and LAST_ACTIVE_UNKOWN.
- Avoid setting `last_active` in `populate_users`.
This commit was modified by @showell:
- I cleaned up the commit message.
- I simplified the diff a bit to avoid
some renaming and lexical moves.
We already know which list widget a `<th>`
tag is associated with when we set up the
event handler, so it's silly to read data
from the DOM to find that widget again
when the handler runs.
This commit eliminates a whole class of possible
errors and busy work.
For some widgets we now avoid duplicate redraw
events from this old pattern:
widget = list_render.create(..., {
}).init();
widget.sort(...);
The above code was wasteful and possibly
flicker-y due to the fact that `init` and
`sort` both render.
Now we do this:
widget = list_render.create(..., {
init_sort: [...],
});
For other widgets we just clean up the need
to call `init()` right after `create()`.
We also allow widgets to pass in `sort_fields`
during initialization (since you may want to
have `init_sort` use a custom sort before the
first render.)
Finally, we make the second and third calls
eliminate the prior updates from the previous
widget. This can prevent strange bugs with
double-reversing columns (although that's
been prevented in a better way with a recent
commit), as well as avoiding double work
with sorting.
This code has always been kind of convoluted
and buggy, starting with the first
sorting-related commit, which put filtering
before sorting for some reason:
3706e2c6ba
This should fix bugs like the fact that
changing filter text would not respect
reversed sorts.
Now the scheme is simple:
- external UI actions set `meta` values like
filter_value, reverse_mode, and
sorting_function, as needed, through
simple setters
- use `hard_redraw` to do a redraw and
trigger external actions
- all filtering/sorting/reverse logic on
the *data* happens in a single, simple
function called `filter_and_sort`
We don't use this anywhere. You can do
`git grep -A 40 list_render.create` to verify
this (with a little bit of noise in the grep).
A better strategy for generalizing
this code is to extract the useful logic
into a function that callers can use in their
own custom event handlers, which I'll do
in an upcoming commit.
We put this in `scroll_util` to make it more likely
we will eventually unify this with other scrolling
logic. (A big piece to move is ui.get_scroll_element,
but that's for another PR.)
And then the other tactical advantage is that we get
100% line coverage on it.
I changed the warning to an error, since I don't
think we ever expect scrolling at the `body` level,
and I don't bother with the preview node.
We extract a general purpose widget to create dropdown lists with
search. This widget is used for default code block language, but can
be easily extended to cover notifications_stream and similar options.
The current usage is:
```js
const widget = DropdownListWidget({
setting_name: 'realm_alpha_beta',
data: [{name: 'hello', value: 'world'}, {...}, ...],
subsection: 'msg-editing',
default_text: 'Nothing is selected',
});
```
and
```handlebars
{{> dropdown_list_widget
setting_name="realm_alpha_beta"
list_placeholder=(t 'Filter the data')
reset_button_text=(t '[Unset]')
label=admin_settings_label.realm_alpha_beta }}
```
This can further be refined by shifting more variables from handlebars
to javascript in the future.
By taking these functions out of exports.build_page, we can
reuse them for handling other widgets. We also declare
default_code_language_widget after the helper functions to
avoid the linter complaining.
I pushed this risk commit to the end of
a PR that had a bunch of harmless prep
commits at the front, and I didn't make
it clear enough that the last commit (this
one) hadn't been tested thoroughly.
For the list_render widget, we can simplify
the intialization pretty easily (avoid
extra sorts, for example), but the cache aspects
are still tricky on subsequent calls.
Changes .data() Jquery methods to .attr() to prevent unnecessary data
type conversions of the emoji name.
Tested the fix manually and verified the test-js-with-node test suite.
Fixes: #14377
For some widgets we now avoid duplicate redraw
events from this old pattern:
widget = list_render.create(..., {
}).init();
widget.sort(...);
The above code was wasteful and possibly
flicker-y due to the fact that `init` and
`sort` both render.
Now we do this:
widget = list_render.create(..., {
init_sort: [...],
});
For other widgets we just clean up the need
to call `init()` right after `create()`.
We also allow widgets to pass in `sort_fields`
during initialization (since you may want to
have `init_sort` use a custom sort before the
first render.)
The get() logic here was broken, because
when you enter the settings panel for invites
on the 2nd or 3rd time, the text filter
would not work.
This commit doesn't intend to fix the problem; it
just simplifies the code for a later commit
that fixes this holistically.
The way that we update `list_render` objects
is janky with respect to events, so we can end
up double-sorting lists (which puts them back
to normal) and strange things like that.
This is all cosmetic.
Instead of:
const.widget = {
foo: function () = {
},
bar: function () {
},
};
We have:
const widget = {};
widget.foo = function () = {
};
widget.bar = function () {
};
Before this fix, we'd get a traceback if you looked
at invites in the settings (and if one of them was
a multi-user invite link). This commit fixes
that problem by adding a custom sort.
We also rename the "Email" column to "Invitee",
since it's often the case the invitee isn't an
actually an email, but it's instead a multi-use
link.
Note that the invites UI only works the first time you
enter settings. Many of the controls break the second
time you enter it. You can't sort by column header
or use the text filter.
I'll fix that in a subsequent commit.
Giving these functions a name and moving them to
the top-level scope has a couple tactical advantages:
- names show in tracebacks
- code is less indented
- setup code is less cluttered
- will be easier to add unit tests
- will make some upcoming diffs nicer
These are technically more `compare_foo` than `sort_foo`,
but we already had a naming convention that was sort of
in place.
We had a bug where if your peer mentioned you in
message, but then edited the message not to mention
you, the latter wouldn't reset your unread counts
for "Mentions". And the same problem would happen
vice versa.
The fix basically extracts `update_message_for_mention`
and makes sure it handles all combinations of
unread/mentioned flags, instead of assuming
any invariants about which directions of change
are possible.
And then we call that new function from
`message_events.js` whenever we get message
edit events.
Fixes#14544
Earlier, the non-editable text-boxes(on clicking view source/edit
topic) were not so apparent due to absence of `disabled` attribute.
Adding the `disabled` attribute makes them consistent with the approach
for non-editable text-boxes and text-areas in organization settings
(for non-admins).
Fixes: #14375
The `send_message_ajax` function was a relic
of us having an alternative way to send messages
(web sockets) to the server, but now the indirection
is more confusing than helpful.
This also fixes trying to cancel a resend of a
local message.
The problem were was type confusion between
strings and ints.
The function in `rows.js` may feel like overkill,
but I really want to enforce type safety here,
as we usually treat message ids as floats, but
for the local-echo case we're gonna get
strings. I put it in `rows` because we mostly
do a good job of encapsulating the "zid" role
in the DOM there.
By going directly to the DOM here, we avoid
parsing a string to a float and then converting
it right back to a string, which always make
me queasy about float rounding, so one less
moving part.
Due to type confusion, we were silently failing
to delete local_id values for messages that were
being acked by the server.
This used to work when we kept values in our
old Dict data structure, since client_message.id
and message.local_id are really the same value,
just the former is a float and the latter's a
string, and Dict never cared.
We can avoid all this confusion, though, by just
consistently using `local_id`, which I extract
to a local var.
The function message_send_error was messing up
on calls to message.get when we were passing in
string versions of `local_id`. Now we pass in
float ids.
This fixes a traceback where we tried to set
`.failed_request` on to an `undefined` value
that we had instead expected to be a locally
echoed message from our message store.
This will allow us access to the float version of the
message's id in an upcoming commit, without us having
to do possibly brittle string-to-float translations.
Option is added to video_chat_provider settings for disabling
video calls.
Video call icon is hidden in two cases-
1. video_chat_provider is set to disabled.
2. video_chat_provider is set to Jitsi and settings.JITSI_SERVER_URL
is none.
Relevant tests are added and modified.
Fixes#14483
This adds a new realm setting: default_code_block_language.
This PR also adds a new widget to specify a language, which
behaves somewhat differently from other widgets of the same
kind; instead of exposing methods to the whole module, we
just create a single IIFE that handles all the interactions
with the DOM for the widget.
We also move the code for remapping languages to format_code
function since we want to preserve the original language to
decide if we override it using default_code_clock_language.
Fixes#14404.
The filter-linkifier input box was disabled which prevented users from
filtering through the linkifiers list. Removed the part of code which
caused the input box to be disabled. This allows users to edit the input
and so filter linkifiers.
With EMAIL_ADDRESS_VISIBILITY_NOBODY (or as a non-admin with
EMAIL_ADDRESS_VISIBILITY_HIDDEN), we were incorrectly generating
zuliprc files containing the shareable email address, which naturally
didn't work.
Most failures result from invalid emoji names, so this makes it easier
to recover without re-uploading a file.
Previously, this model would have been problematic, but now that we
have the visual preview, this is clearly better behavior.
This adds a preview of the uploaded emoji image while uploading custom
emoji right below the upload form.
Modified upload_widget.build_widget() to take in the preview
span text and image. In case a parameter isn't passed
for preview text, it defaults to null and the snippets in
build_widgets() related to preview don't run.
Fixes#9229.
Styling tweaked by tabbott.
We now only compute idx on the outbound side,
instead of spreading out the responsibility.
We just iterate through all our items to find
the next available number.
The name here is a bit more precise, as we're
not checking whether a task exists so much
as whether just a particular name is in use.
We also move the function out of the `check_task`
layer, which feels a bit overkill in terms
of nesting (plus, we're gonna remove the other
function inside of `check_task` soon).
This is a prep commit for changes to the top navbar, it adds helpers
to filter.js which will help control the behavior of some aspects of
the redesigned navbar.
Modified by tabbott to add comments, internationalization tags on the
strings, support streams:public, and change various title strings.
We fix this by adding a more expressive data function, with tests, for
whether a filter is on UserMessage data, which would mean that
streams:public could never add additional matches.
We now use `assert.throws()` to test that we're
properly calling `blueslip.fatal`.
In order to not break line coverage here, we have
to remove an unreachable `return` in `stream_data.js`.
Usually we test `fatal` for line coverage reasons.
Most places where we use `blueslip.fatal` fall in
these categories:
* the code is theoretically unreachable, but
we have `blueslip.fatal` for defensive reasons
* we have some upstream bug that we should just
fix
* the code should recover gracefully and just
use blueslip.errors()
It's possible that we should eliminate `blueslip.fatal`
from our API and just throw errors when really important
invariants get broken. This will make it more obvious
to somebody reading the code that we're not going to
continue after the call, and `blueslip` already knows
how to catch exceptions and report them.
The todo_widget was using the using a counter to store the key value of
every task. This would cause assiging multiple tasks the same key value
in a race condition. To avoid this we make "sender_id" a part of the key
along with the counter.
Also the `key` now not being a integer value, we can't use it to find the
index of the task using it. Thus, a function is made that will find the
index of task whose key is sent by the user to strike.
This is part of #6427, adding support for live-updating the Zulip UI
to move messages to a new topic.
As noted in the comments, there is still a bug to be fixed here
involving guest users, but the overall implementation is pretty well
tested manually (which is how we test most message-edit UI work since
there's so much complexity involved).
Co-Authored-By: Wbert Adrián Castro Vera <wbertc@gmail.com>
We no longer delete existing drafts if you happen
to clear the text in your compose box for a message
that was restored from an existing draft. This
prevents folks from losing drafts when they accidentally
delete selected text.
There are still two ways to delete a draft:
* send the message (obviously not always desirable)
* use the drafts UI (with `d` as a shortcut to bring it up)
See https://chat.zulip.org/#narrow/stream/9-issues/topic/lost.20draft
for more discussion.
If the subscription data was changed from the left sidebar,
we previously would attempt to display the savings indicator
in the stream edit page which wasn't rendered yet. The bug was
introduced in commit 39577b58ba.
This approach is used to harden the codepath against bugs by
keeping the expectOne check in `settings_ui.do_settings_change`
function.
Fixes#14467.
When we redraw the left sidebar, we need to tell the
topic list to clear its data structures (and do other
stuff like hiding its popover), since we are clearing
its parent container.
The commit f0e18b3b3e
introduced this regression in late January 2020.
That commit made topic_list use a vdom to avoid
unnecessary updates. Before that, topic_list did
a lot of brute-force redraws, which covered up the
fact that we weren't having stream_list telling it
when the rug was being pulled out from under it.
The boundary between stream_list and topic_list
has always been kind of complicated code, since
topic lists get embedded into the stream list.
The main interactions, though, are basically:
* topic_zoom.clear_topics() - you're leaving
a narrow that may or may not be zoomed
* topic_list.clear() - you're about to redraw
stream items in the unzoomed stream list
* topic_list.rebuild(stream_li, stream_id) -
you're building or updating a topic list
for the newly active stream
Fixes#14465
Users are unable to modify organization's profile picture, but
disabled buttons for the same are being shown to the user on the
organization profile settings page. This commit removes those
buttons. The file realm-logo-widget.hbs renders those buttons only
if the user is an admin and realm_logo.js has been updated to allow
operations(like click) on the buttons only to admins.
Users are unable to modify organization's logos, but disabled
buttons for the same are being shown to the user on the organization
settings page. This commit removes those buttons. The file
realm-logo-widget.hbs renders those buttons only if the user is an
admin and realm_logo.js has been updated to allow operations
(like click) on the buttons only to admins.
The `options` parameter is not being passed in any call
of `lightbox.open()` and it uses the same option i.e.
`lightbox_canvas` everytime which is now computed inside
`display_image()` directly.
`image` passed to lightbox.open() is already a jQuery object,
so we don't need to convert it explicitly. Also, the parameter
is renamed from `image` to `$image`.
Previously, lightbox.open() was responsible for retrieving
the image data from the DOM, saving it in `asset_map` and
finally displaying the image using that data. This
implementation wasn't correct for image list at bottom of
the lightbox because the `image` parameter passed to
lightbox.open() could contain more than one instances of
the image that had to be opened.
Now, the metadata of all the images in image-list is stored
in the `asset_map` while rendering the `image-list` inside
`render_lightbox_list_images()` and `lightbox.open()` only
looks for the metadata from `asset_map`.
Fixes#14152.
In case of video embeds, the previous logic used
`data-src-fullsize` or `src` as a key to look
for the metadata of video in `lightbox.open()`,
but while parsing, the key used while storing
the metadata was the video ID.
This doesn't make any sense because video's data
could never be accessed from `asset_map` and we
always needed to lookup the DOM for this.
This commit fixes this by using $img.attr('src')
as a key for `asset_map` for both, images and
videos. Since `src` is the link of preview image
in case of video embeds, it will always uniquely
determine the video ID and we won't loose
anything with the change in how videos handle
things.
Part of #14152.
The value of `canvas.parentNode` in `sizeCanvas()`
appears to be `null` sometimes and it throwed an
exception specially when you switch images from
the images-list quickly.
This changes the payload that is used
to populate `page_params` for the webapp,
as well as responses to the once-every-50-seconds
presence pings.
Now our dictionary of users only has these
two fields in the value:
- activity_timestamp
- idle_timestamp
Example data:
{
6: Object { idle_timestamp: 1585746028 },
7: Object { active_timestamp: 1585745774 },
8: Object { active_timestamp: 1585745578,
idle_timestamp: 1585745400}
}
We only send the slimmer type of payload
to clients that have set `slim_presence`
to True.
Note that this commit does not change the format
of the event data, which still looks like this:
{
website: {
client: 'website',
pushable: false,
status: 'active',
timestamp: 1585745225
}
}
When we tried to copy/paste multiple rows up to
and including the last row in our view, we'd have
a blueslip error when the `for` loop checked the
condition `rows.id(row) <= ...` after we had
called `row = rows.next_visible(row)` on the last
row. Basically, `rows.id()` would complain
about a non-existent row.
Now we extract that code into `visible_range`, so
that our `while` loop can exit as soon as we found
the last row in the range.
The selector we were passing to `condense_and_collapse`
included rows from our drafts UI, which don't have
zids and don't play nice with condense/collapse code
(which expects message ids for settings things like
`.condense` flags).
Now we just use a better selector.
If folks use an overly broad selector for message rows,
they will accidentally include drafts from the drafts
dialog, which won't have zids. More specific selectors
will be more efficient and possibly prevent strange
behaviors.
For testing convenience, we extract the message.
We now handle the esc key completely within the
keydown handler that we already have for message
editing. We allow escape to work no matter what
the focused element is within an edited message,
and we blur that element properly and end the
edit.
We remove all the strange, duplicated logic
from hotkey.js.
This should also fix a blueslip error where the
hotkey code was passing message_edit a jQuery
element with zero length.
Fixes the traceback reported in #14151, though we should still look at
the DOM cleanup discussed there.
The UI in the `#settings/notifications` page is updated similarly
to what is done in the `update_global_notifications` path present
in the `server_events_dispatch` file.
We have an alert for when the stream name is changed.
This also adds an alert when subscription settings
are updated and the widget is similar to that used in
the settings page.
This is also necessary because the stream specific
notification settings UI updation goes through this
path and it is necessary to display a confirmation
to match with other settings confirmation pattern.
This setting is being overridden by the frontend since the last
commit, and the security model is clearer and more robust if we don't
make it appear as though the markdown processor is handling this
issue.
Co-authored-by: Tim Abbott <tabbott@zulipchat.com>
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
While we could fix this issue by changing the markdown processor,
doing so is not a robust solution, because even a momentary bug in the
markdown processor could allow cached messages that do not follow our
security policy.
This change ensures that even if our markdown processor has bugs that
result in rendered content that does not properly follow our policy of
using rel="noopener noreferrer" on links, we'll still do something
reasonable.
Co-authored-by: Tim Abbott <tabbott@zulipchat.com>
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
If we can't find data on a mentioned user to update its full_name to
the current value, we'll have to go with the value in the message
itself.
This can happen if e.g. we hard-deleted the originally mentioned user
from the database (which can sometimes happen after a "delete my
account completely" request).
The user has an option for setting global
notification settings as well as the same settings
for individual streams. Currently the user has to
keep track of each unmatched stream and then visit
each individual stream whose settings he wants to
update.
Thus this adds a dedicated UI table allowing the user
to view and update the notifications of the specific
streams which differs from the global settings.
It is located on the same page where the user defined
global notification settings can be modified.
Fixes#9228.
Currently we are updating the checkbox UI as soon as the user clicks.
This block is removed to match with the pattern of rest of the
properties in the stream edit page where `stream_events.update_property`
is responsible for updating the UI after a successful server response.
This function returns a list of objects to create a
list_render object, and each item contains the streams
whose atleast one notification setting differs from the
default set by the user.
This is done by comparing the global settings in the
`#settings/notifications` page with those settings
present in the subscribed streams.
Work towards #9228.
This flag was used to delay unread count updates while the bankruptcy
modal was visible. Now that bankrupcty is no longer a modal, we don't
need this flag at all.
Switched to top-of-page prompt to make it natural to fit in with other
notifications. As we switch to panel-based prompt, templates for the
bankruptcy modal are moved along with its usage in application's
homepage.
We include a bit of delay before reloading to make it easy for the
user to read the "Marking all messages as read" banner before it is
covered by the "Reloading..." notice in environments where the reload
is fast.
Fixes#3347.
When stream_post_policy modal is closed either after saving or using
cancel button or cross button, the pointer-events is set to none which
does not allow to close the stream settings overlay on one click.
Added overlay.close_modal on saving such that pointer-events:none is
removed.
Added line which removes pointer-events:none again on clicking cancel
button or close icon.
This is a prep commit which extracts the part of the code in open_modal
and close_modal to separate methods which adds inline style of
pointer-events to enable/disable the background mouse events.
Block comments are added for easy understanding of reader.
If a non-author user clicked on view source in a poll and then close it,
the edit question icon would incorrectly get visible. This made changing
the question in local echo possible for non-author users.
Fixes: #14299
Starred messages from muted topics were not shown in the starred
messages view. Condition for muting_enabled is modified accordingly
such that the starred messages from muted topics is shown in the
starred messages narrowed view.
Node tests are updated accordingly.
Fixes#13548