-
-
Notifications
You must be signed in to change notification settings - Fork 668
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
webview header: Modify topic header to include date. #3435
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ishammahajan !
This generally looks good. One procedural request: would you add a screenshot in the PR thread? That's helpful in general for review when making UI changes.
Some comments below on specifics in the code.
@@ -39,7 +40,8 @@ export default ( | |||
data-narrow="${topicNarrowStr}" | |||
data-msg-id="${item.id}" | |||
> | |||
$!${topicHtml} | |||
<div>$!${topicHtml}</div> | |||
<div>$!${humanDate(new Date(item.timestamp * 1000))}</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anything that isn't explicitly already HTML should be included with plain ${...}
, without the extra (danger-signifying!) $!
. See the jsdoc on template
, in src/webview/html/template.js
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Thanks, fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I see that I hadn't addressed this in the latest push (for reasons I don't know, the diff got erased from WD.)
Anyways it's fixed now.
src/webview/js/js.js
Outdated
? 'header' | ||
: target.matches('a') | ||
? 'link' | ||
: 'message', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this is getting messy.
- If we do end up with logic looking like this, it should definitely get pulled out into a local variable -- it's too complex to belong inline in a function call like this one.
- How about using
closest
instead? See docs, and example usage for.message_inline_image a
and friends above.- This could also simplify the other part of the diff, above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, was going to ask about that. Fixed! 😄.
@gnprice Thanks for the review, have addressed the concerns on my machine! Sorry about the screenshot, I wasn't ready for a review right now 😅, regardless I'll add screenshots/suitable recordings to this shortly. Been busy lately, didn't have enough time to dedicate to the project. Another thing, I had originally marked this as a WIP because the CSS and some JS might change because of the complexity of implementing this in topics/1:1 pms, which is why I was holding back on asking for a review. |
Got it, no problem 🙂 When you'd like another review, just leave a comment here! |
9c1b661
to
cc5824b
Compare
cc5824b
to
800df20
Compare
800df20
to
f217283
Compare
f217283
to
9cac708
Compare
src/webview/js/js.js
Outdated
@@ -593,6 +593,14 @@ documentBody.addEventListener('click', (e: MouseEvent) => { | |||
return; | |||
} | |||
|
|||
if (target.parentNode instanceof Element && target.parentNode.matches('.header')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change required only because you've added a div
inside the '.header'?
Try using CSS: pointer-events: none;
for that div
and it will stop handling click/touch events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Thanks for the advice! 🙂
flex: 1; | ||
padding-left: 0.5em; | ||
background: #ccc; | ||
min-width: 30%; | ||
} | ||
.topic-text { | ||
overflow: hidden; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You definitely want some margin on the left.
Check out how longer topics almost blend with the date div
.
Try 0.5em
or 1em
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some margin on the left.
I agree, it's definitely blending in a lot. Also I assume you mean margin on the right of the topic-text?
src/webview/css/css.js
Outdated
.topic-text { | ||
overflow: hidden; | ||
text-overflow: ellipsis; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding some transparency to the text (about 0.5) will make it look better, as this is secondary information to the topic name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, done!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again @ishammahajan ! Comments below on the first 3/5 commits.
</div> | ||
`; | ||
} | ||
|
||
if (item.type === 'stream') { | ||
if (item.type === 'stream' && (isSpecialNarrow(narrow) || isHomeNarrow(narrow))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this in fact redundant? (And in the private
case below, is the new condition in fact equivalent to the old?) How do you know -- or, how would you find out for sure?
Also, there's already kind of a long list of possible types of narrows. What if a new one gets added -- how can you write this so that it will stay correct then?
I think what you probably want here is !isStreamOrTopicNarrow
. That's what this block is really about -- that's the description that will stay true regardless of what other miscellaneous types of narrows exist.
Another solution which would make sure you've comprehensively covered the cases, and make sure it stays correct if/when more cases are added, would be to use caseNarrow
. (See the example uses of it in utils/narrow.js
. See also git log --stat -p fa6134aa6^..e9fe1e801
.) But I think in this case the simpler isStreamOrTopicNarrow
will do just fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, or here's an alternate way of organizing this logic: put a caseNarrow
at the outside, before looking at item.type
. Then you get to be super explicit about what the behavior is for each possible type of narrow.
Because much of the logic will be shared across several types of narrow, I'd probably structure that something like this:
const headerStyle = caseNarrow(narrow, {
stream: () => 'topic+date',
pm: () => 'date',
search: () => 'full',
// ... etc.
});
// Now we're completely done with `narrow` -- the information we need from it is all in `headerStyle`.
if (item.type === 'stream' && headerStyle === 'topic+date') {
// ...
} else // ...
The exact set of possible values for headerStyle
will be up to what you're doing, and might change in later commits in the branch. This will be a way to separate that decision-making in its own bit of code where it's easy to see what's happening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the detailed analysis!
I agree with all of the points you made. I do think the second solution is what we would want to implement. Unfortunately I did see the review on this commit after I saw the others, so I'll take some time to implement this (and fix conflicts) and push the final version.
const topicNarrowStr = JSON.stringify(topicNarrow(item.display_recipient, item.subject)); | ||
const topicHtml = renderSubject(item); | ||
|
||
return template` | ||
<div | ||
class="header-wrapper header topic-text" | ||
class="header-wrapper header topic-content" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name is kind of confusing -- we generally use "content" for the content of the message itself.
Perhaps topic-header
?
<div class="header stream-text" | ||
style="color: ${textColor}; | ||
background: ${backgroundColor}" | ||
data-narrow="${streamNarrowStr}"> | ||
# ${item.display_recipient} | ||
</div> | ||
<div class="header topic-text" data-narrow="${topicNarrowStr}"> | ||
$!${topicHtml} | ||
<div class="header-wrapper header topic-content" data-narrow="${topicNarrowStr}"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the nested header-wrapper
, and the nested header
? That seems likely to cause confusion and/or a bug, if it doesn't cause a live bug already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also topic-content
is definitely going to be confusing if what it really means is "topic plus date". The date isn't really anything to do with the topic, so topic-content
doesn't give a hint of that.
If you want a common class for "topic + date" in this and the other case, you could if nothing else call it "topic-and-date". But before that, I would ask why they're grouped together in the first place. 🙂 Why not add the "date" div as a sibling of both the stream-text
and the topic-text
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original intention of grouping them as separate div's was to make it clear that there will be different classes to represent both the text and the date, and I'll admit my inexperience with CSS; I don't know how to not bring two divs and still maintain the flexbox with justify-content: space-between;
The date manages to overflow no matter what changes I make to the CSS to prevent it from doing so. Making two divs solves this problem, so I went with it.
Suggestions about changes to the CSS are welcome! 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header-wrapper
and header
nesting was definitely redundant (although no observable bugs could be found by me) and has been taken care of, thanks! Also changed the name for topic-content
to topic-header
in order to correctly represent what type of narrow the header belongs to (like stream-header
and private-header
represent their narrows.)
: item.display_recipient.filter(r => r.email !== ownEmail); | ||
if (item.type === 'private') { | ||
let recipientsStr; | ||
let privateNarrowStr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like these mutable variables -- they're a smell, a sign that something's off in the logic.
One observation: you're including the div for "recipients" even when there's nothing there. That seems likely to cause trouble -- if nothing else, confusion.
Probably better to just have a separate case for the new situation where we're showing this header but don't want to show the recipients.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this. Introduced another case instead of checking with variables (now checking the narrow with isPrivateNarrow() && !isSpecialNarrow()
to check for if the screen the user is on is a private conversation.)
.sort() | ||
.join(', ')} | ||
<div class="topic-text">$!${recipientsStr}</div> | ||
<div class="human-date">$!${humanDate(new Date(item.timestamp * 1000))}</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dangerous -- this is really important!
Same thing I mentioned in a comment in the last round:
#3435 (comment)
Essentially this is a type error -- you are taking content that is plain text, and using it in a place that expects HTML. The only correct way to do that is to encode the text as HTML.
Otherwise when some user changes their name in Zulip to something like, say, <script>alert("lol pwned");</script>
, and then sends you a PM -- something very much the wrong thing happens. 😜
The term for this is "HTML injection". Here's one reasonable piece of background on the issue:
https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md
In that page's terms, "Rule # 1" is the applicable rule here.
In our template
function which we're using here, the normal way to encode text as HTML is to use a plain ${...}
. The !
in $!$
is a bright red warning sign! Please heed the warning sign.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation and the link (helped a lot more than understanding HTML injection too :) )!
I was actually aware of HTML injection being a real thing, and I had fixed this issue in WD before (as explained in the comment above) must have forgotten to commit it for some reason.
(That link is very resourceful!)
Also, thanks for those recordings! Very helpful 🙂 In the 1:1 PM case, the bar looks oddly blank with just the date at the end -- it looks like there's some kind of bug. (Reminds me of how some paper exams, forms, etc. will say "This Page Intentionally Left Blank" rather than actually leave a page blank, to avoid people worrying that there was some error in printing.) Not immediately sure what'd be the best way to address that, though. |
9cac708
to
baedf3e
Compare
@borisyankov @gnprice thanks for the reviews! I have addressed all the points covered and made the appropriate changes. The failed check is because of the changes introduced in the first commit with using I will be posting updated screenshots after the design is finalised and implemented, so that work done in capturing and posting these is not repeated. The design finalisation I am talking about is the problem concerning how dates should be shown in the PM narrow (as said in the last comment). I've given it some thought and my opinion is to keep the entirety of the header (the background) and the header text is aligned to the middle (optionally giving it a defined width with rounded corners, although I don't think this would go well with the rest of the app). The reasoning behind this is that we cannot remove the name from the appbar because that would involve removing the |
I'm not too sure about the design though, if there are better ideas I would like to hear them. |
I was definitely not a fan of adding the headers in the narrows that previously didn't have one. The first issue I have is that they are just very confusing, you expect this to be a separator that just got stuck at top temporarily but in these narrows it is a permanent thing that is also empty (besides the date on the right). A smaller issue, these take vertical space that previously was free for display of messages. Another thing that we have to improve:
I don't see a reason not to merge the changes for the narrows already with sticky headers, as these look great. We can iterate on the other narrows more though. Maybe a sticky date that only takes the right side of the screen (basically a header that is something like |
Thanks @ishammahajan for these revisions!
|
On the next commit, modifying the header only for stream messages:
It's true that With this change, if the topic is actually "2 + 2 < 5", it gets doubly encoded to become "2 + 2 < 5", which means it displays as "2 + 2 < 5". I just wrote and pushed to master a quick test that demonstrates this -- see #3467. When you rebase on the new master, you'll find that this change breaks that test. Same thing in the other case here, even though I didn't add a test for that today.
One thing: what is Also the nesting of Is it intentional that tapping on the date will narrow to the topic? If so, that should definitely be explicit in the commit message. There may also be a cleaner way to do that that doesn't involve this nesting (and the worry that maybe some edge around the stream name will also narrow to the topic.)
|
@borisyankov thanks for the insight on design!
I have continued the discussion in zulip about this, let's discuss the points further over there. The gist of my opinion about this is that, while it does sacrifice a tiny bit of the vertical space, it brings uniformity to the design, since now headers appear everywhere and actually have a function which makes them non-static. It also gives the added benefit of being in sync with the webapp's design. The possible designs are the two following and everything in between.
I do agree with this, we don't yet have a solution for showing dates in private headers, and while I have posted some mockups of a possible design in chat, I do think there may be better solutions out there.
I do think both are necessary, since if there is a case where the timerow is in the middle of the screen, the date on the header will not reflect that of the timerow which is on the screen, it will rather reflect the date of the timerow above it. It would also be applicable in another case where the topic of the conversation does not change as the clock strikes midnight. In this case since the topic doesn't change, another header is not created, but a timerow is still required because we do still need to display the date.
I'll be working on that next, as soon as design on this is finalised and this PR is merged :) |
baedf3e
to
d3d5918
Compare
@gnprice thanks for pushing the fix for the first commit!
It gets doubly encoded to become "2 + 2 < 5", right? Single encoding would bring it to "2 + 2 < 5".
That's exactly right! I wanted to make the structure such that the area a user taps to get to the stream (the stream name
They do contradict each other on colours, but that's because one of the colours is for dark theme and one is for light (I haven't changed anything with respect to the colours. As the commit says, I have simply renamed what was -- |
Oof, this is confusing because GitHub decodes these entities in comments... so in the rendering of my comment things come out differently than how I'd typed them. I didn't notice that until just now -- let me try again, using the "preview" feature to make sure it comes out right: With this change, if the topic is actually "2 + 2 < 5" (with a less-than), it gets doubly encoded to become (On top of everything else, in fact GitHub apparently has an HTML-encoding bug of its own 🤣 😢 where the "Quote reply" feature copies the displayed text version, without encoding things back as HTML entities... so they get decoded a second time, and your quote from my comment comes out differently from my actual comment, and the same with my quote from your comment.) Does that make better sense now? Thanks for pointing out the confusion 🙂 |
Ah I see, makes sense, thanks. I saw the two in the diff (with just the usual 3 lines of context), and mistakenly assumed they were both in the one giant block.
Hmm, I see! And thanks for the added explanation in the commit message; that's quite helpful. I like the idea of this being a modular piece that's dropped in. A couple of things that make it not quite there even with this change (and these would be a good target for followup commits):
|
I just pushed the next commit, adding dates in the existing recipient headers for stream messages. Thanks again @ishammahajan ! I also added a small commit on top that fixes the bug introduced. In general we avoid having any given commit break things, even if a later commit in the PR fixes it -- and this is an illustration of one reason why, as we're not ready to merge that next commit. 🙂 Another reason we avoid having any given commit break things is that it's generally a lot easier to read and understand the commit when you can assume the author and reviewer(s) believed it all made sense together and didn't break anything. (There can always still be bugs they missed, of course, but at least you have a much better shot at following what those humans were thinking.) So the clear identification of the bug in the commit message mitigates that, and was crucial in it being OK to merge the commit with the known bug. But I still didn't want to merge it without also promptly fixing it. 😉 |
(For design discussion for the next steps, I'll move to that chat thread you created.) Also, FTR: the commits I just merged were ada59a7 and 123fd7a. |
Oh, one next step that I think we can do before settling further design questions: PM headers, in the cases where they already appear (namely "special narrows" like all-messages, starred, and search.) In those narrows, it looks a bit incongruous to have dates on headers for stream messages but not PMs. This is basically one half of the changes that appear in your next commit:
but that commit also starts showing those headers in PM narrows, which I'd prefer to hold off on for a bit more design discussion. Would you split that change out as a separate first commit? I think that split makes things a bit clearer even if we were about to merge them both, though it wouldn't be absolutely essential in that case. (One thing I would insist on even then, though: the commit message should definitely be clear that it's making both those changes. In the current one it's easy to miss that and read it as only being about adding dates to existing headers.) |
It does 😂 ! My reply to your comment was based on the me trying to understand the test anyway.
I'll fix that promptly, thanks!
Just tested it, it appears as if the class is completely redundant, since removing it from
I'll do that, unfortunately not today though, since there's not enough time. |
This commit reverts the temporary fix introduced in commit 123fd7a.
The previous commit changed only the headers in stream narrow. This commit adds the same for the private/group headers in special narrows. The implementation for private narrows was straightforward for special narrows. Renamed the `topic-date` and the `topic-text` to `header-date` and `header-text` to reflect their actual usage, since they are used everywhere, and not only in representing topics.
a62687b
to
eaf215f
Compare
This commit removes redundant code introduced in ada59a7 (that commit itself was a bit too complicated, hence a separate commit for removing it.) This code was deemed redundant because of the modular solution adopted for headers, and `stream-text`, along with the other changes introduced in the css in the mentioned commit covered what `stream-header` used to do before.
This change is simply a switcheroo between two attributes of a div. This is done to make the code slightly more understandable due to the ease of drawing parallelism after this change.
Adding headers to PMs/groups was a little tricky. In private narrows we don't want the names of the individuals in the header because they are already present in the AppBar. The changes in `messageHeaderAsHtml` reflect this. There is an empty element introduced which acts as a buffer to enable the flexbox to do it's thing. Also edited `renderMessages` to actually add the headers to the `renderedMessages` pm/group sections in the first place.
Displays header in the topic narrow, same as stream narrow. Removes restriction for header displayed only for certain type of messages. Headers henceforth will be displayed on every narrow. Removed topic name from `Title` displayed in the `ChatNavBar`. This instead will now be shown in the topic header.
Why this was required :- The previous implementation of timestamp in header did not react to changes in dates. The dates remained the same whether or not a timerow passed by in the message list. This implementation fixes that problem and makes the timestamp reactive to scrolling events. Implementation :- Every message in the webview now includes another attribute which shows what date (human readable) it was sent. In the webview js, after everytime the scroll event fires the first visible message is calculated, and the closest header is walked to. The human readable date is extracted from the attribute introduced in message, and the content of the timestamp in the header is changed to suit that. Things to be considered :- This might induce some performance issues. Optimisation seems to be unnecessary for just one change in the DOM every scroll event, however this is still something to watch for in case users report slowdown in performance. This also has been tested for both devices on simulators and there were no stutters on them. Fixes zulip#1336.
eaf215f
to
b49c49d
Compare
Closing due to #3496. |
Many times when people are scrolling through messages they need to
see what date it is. This modification is made for this use-case.
Users can simply see the header to determine the date a particular
message was sent.
Header is converted into a flexbox and js for timestamp is added.
The date is human readable, and header is truncated if the topic
name is very large.
This would, in it's current iteration, only introduce the header
in the streams narrow. This would bring problems where users would
not be able to get the date for a certain message in 1:1 or in
the topic narrow. The complete PR, however, aims to fix this by
introducing headers to these narrows as well, the benefits of
which are detailed in #1336 (comment).
Tasklist :-
(this is the current state of this PR)
Fixes #1336