-
Notifications
You must be signed in to change notification settings - Fork 78
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 conversation-part-closed component #1638
Add conversation-part-closed component #1638
Conversation
Clocking out for the day. Working through this is hard, but I think i have a semi-direction? It could be/probably is wrong, but my plan when I start tomorrow is to write a computed object that gets the author (either part.author.id or currentUser.user.id) and then passes it to the hbs which is written-ish (I know I'm missing stuff.) |
isSelf: computed('author', 'user', function() { | ||
return get(this, 'author.id') === get(this, 'user.id'); | ||
|
||
closedUser: computed ('isSelf', 'currentUser', function() { |
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 is the component I'm talking about. Hoping that this will compute what author will be passed into the HBS.
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.
Your reasoning here is good, but remember, the component will spell out You closed this
or {{username}} closed this
, so you don't really care about the closedUser
. Your isSelf
is correct, so what you need now is to modify your template and replace {{#if currentUser}}
with {{#if isSelf}}
.
@@ -0,0 +1,9 @@ | |||
<div class="conversation-part-closed"> |
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 div
is not necessary since the component itself creates a div
with this class (using the classNames
you defined).
isSelf: computed('author', 'user', function() { | ||
return get(this, 'author.id') === get(this, 'user.id'); | ||
|
||
closedUser: computed ('isSelf', 'currentUser', function() { |
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.
Your reasoning here is good, but remember, the component will spell out You closed this
or {{username}} closed this
, so you don't really care about the closedUser
. Your isSelf
is correct, so what you need now is to modify your template and replace {{#if currentUser}}
with {{#if isSelf}}
.
You closed this at... | ||
{{else}} | ||
<div class="conversation-part-closed__message-wrapper"> | ||
{{author.username}} closed this at... |
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.
See comment above on what to do here. Also, your syntax is incorrect. You use the if
helper like this:
{{#if something}}
Foo
{{else}}
Bar
{{/if}}
Note the indentations, the `#` and the `{{/if}}`
return get(this, 'author.id') === get(this, 'user.id'); | ||
|
||
|
||
}) |
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.
Blank lines need to go
79b55de
to
7da31f3
Compare
author=author | ||
closedAt=closedAt | ||
}} | ||
`); | ||
|
||
moduleForComponent('conversations/conversation-part-closed', 'Integration | Component | conversations/conversation part closed', { | ||
integration: true | ||
}); | ||
|
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.
Would love feedback on test statements on 21 + 25.
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.
For future reference, you should comment below those lines so we can see them in this view. Also, would be helpful to have some direction in terms of what you want feedback on specifically?
} from 'ember-cli-page-object'; | ||
|
||
export default { | ||
title: text('h1') |
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.
Would also love feed back on page object. Think I have everything I need though, at least that I've found I need so far.
@daveconnis remember to set the label, too. |
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.
Commented on the component file. Also, not to forget, you need to rename the other conversation-part
files - the .hbs
, the integration/.../...-test.js
and the pages/.../conversation-part.js
test('it renders', function(assert) { | ||
|
||
// Set any properties with this.set('myProperty', 'value'); | ||
// Handle any actions with this.on('myAction', function(val) { ... }); |
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.
Don't forget to remove this test.
|
||
test('if user closes message, "You closed this at" is rendered', function(assert){ | ||
|
||
}) |
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.
These blank tests seems like they would test correct behavior, so the thinking is probably sound. Just need to implement them.
|
||
isSelf: computed('author', 'user', function() { | ||
return get(this, 'author.id') === get(this, 'user.id'); | ||
}) |
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.
Two problems here
It's not clear what author
is
You specify the value of author through the .hbs
, as exampled in the test module you wrote:
{{conversations/conversation-part-closed author=author closedAt=closedAt}}
When we do that, we also add that property into the .js
and give it a default value, usually null
, unless some other value makes sense. You already did this with closedAt: null
, so you should do the same with author: null
.
The code will work regardless, but we do this so that, when someone is reading the .js
, they do not need to navigate back and forth between the .js
and the .hbs
and the component is relatively clear from the .hbs
alone.
user
is not defined at all
The author
is whichever user is responsible for this specific conversation part being created.
The user
is supposed to be whichever user is currently signed in to the app. You get it from the currentUser
service as currentUser.user
, so to have it available to you as just user
, you need to define an alias. You can look at the basic conversation-part-comment
component to see how that's done.
Clocking out for the day. Started working on tests for
This one is giving me the trouble, specifically
I'm getting an expected result of 2, but only getting 1 on my test. Considering how were trying to create a second conversation part, I'm assuming that 'channel.trigger('new:conversation-part', {});' is somehow missing the mark. When I change I'm planning on starting here in the morning, but if someone could give me some thoughts on if I'm heading in the right direction, that'd be swell. |
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.
Good progress, but a few things left to do
author=conversationPartComment.author | ||
body=conversationPartComment.body | ||
readAt=conversationPartComment.readAt | ||
sentAt=conversationPartComment.insertedAt |
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 what you probably wanna do here is keep the {{#each conversation.conversationParts as |conversation_part|}}
and then do a couple of if-else
chains inside the {{#if conversationPart.isLoaded}}
Think of this way. A conversation has a bunch of conversation parts and we want to render all of them in the order we got them in.
Then, for each of them, if it's a comment-type conversation part, render it as a comment type. If it's a closed-type conversation part, render is as a closed type, etc.
{{#each conversation.conversationParts as |conversationPart|}}
{{#if conversationPart.isLoaded}}
{{#if (eq conversationPart.partType 'closed')}}
{{conversations/conversation-part-closed ..}}
{{else}}
{{conversations/conversation-part-comment ...}}
{{/if}}
{{/if}}
{{/each}}
Note that in the example, the comment type is sort of considered the default - the thing we render if it's not any other type. It's not perfect and really, if we do not support all the types our API supports, we have a bug, but at least this will render something, which is preferable to and easier to detect as an issue than nothing.
There may be more elegant ways to do this, but for now, this is good enough. Then, when we add another conversation part type, such as conversation-part-open
, we would add an else if
here, between the if
and the else
.
renderPage(); | ||
|
||
assert.ok(page.closedAt.text, 'You closed this two days ago', 'The closed at timestamp is rendered'); | ||
}); |
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 one is good, but I would call it 'if the current user closes the message...
, just to emphasize the current
The other test is 'if someone other than the current user closes the message...'
Okay, I'm stuck. It seems like I'm getting conflicting thoughts here. Right now, I'm working on failing tests for
Which leads me to believe that my path to that part is wrong. This is probably the case considering I've renamed things to conversation-part-comment. Considering Nikola's earlier comments about
I went back and fixed this, taking the
In [https://github.com//issues/1636], you guys stated that you wanted |
|
||
set(this, 'author', { user1 }); | ||
set(this, 'closedAt', moment().from()); | ||
stubService(this, 'current-user', { user }); |
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 also can't get the "author" nor the "time" to pass in here, either. Been trying for too long so moving onto something else.
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.
There's a misunderstanding here with the author.
{ user }
is an object shorthand. Basically, it's a shorter way of writing { user: user }
With that in mind
set(this, 'author', { user1 });
means you're actually doing
set(this, 'author', { user1: user1 });
which clearly wont work.
In your setup, there's no author.username
, author.id
, etc., there's 'author.user1.username,
author.user1.id`, etc.
Thus, what you need to do instead is,
set(this, 'author', user1);
Meaning, the value of author
in our component is the same as user1
What might be confusing you is the
stubService(this, 'current-user', { user });
but we actually do a different thing there.
If you take a look at how the actual current-user
service is implemented, under app/services/current-user.js
, you will see that it's an Ember.Service
, with a user
property in it, so what we're doing is exactly what we want to do - replace the actual service with a fake one, where the value of user
is our user.
That means, we will have currentUser.user
, currentUser.user.id
, currentUser.user.username
, etc., exactly as we want.
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.
As for the time stamp, look for an example in admin-github-event-test.js
The general idea is to get some timestamp, either using Date.now()
or moment()
. Both will return the exact current time. The example above uses moment()
.
Then, store that time stamp into a variable. This is critical. You can't just go and do the following, for example:
let timestamp = moment();
assert.equal(timestamp, moment());
The simple reason you can't do this is that both Date.now()
and moment()
return a different value every time you call them - the current timestamp, meaning the exact time at the time the function was called.
So if we want to test our code here, we need to understand what our component is supposed to do - The intent of the test is to ensure that the component does what it supposed to do.
Our component is supposed to tell us who closed our conversation and when.
The who will be either the username of the author, or just "You" if the author is the current user, so we need two tests for that, which I think you'll know how to cover.
The "when" will be the time of the closing event, meaning the time the conversation part of "partType
" "closed"
was created (or, in terms of the code, the value of closedAt
). We also want the when
to nicely formatted in some manner, which is something I described in my comment above.
To give a few examples for the username part
- If the current user is
begedin
, and the person who closed the conversation isdaveconnis
, we want the text to contain"daveconnis closed this"
- If the current user is
daveconnis
anddaveconnis
closed the conversation, we want the text to say"You closed this"
As for the timestamp, it gets a bit more complicated because you sort of need to know how the friendly formatting works, but what you would do is something like
- Create a couple of timestamps at varying moments in the past
- For each of them
- set the value of
closedAt
to that - check if the text contains the friendly version of that timestamp
- due to some weird ember internals, you need to use the run loop to do that, otherwise it won't update
- set the value of
As a concrete example
// moment() returns the current time. `subtract(amount, type)` then modifies that
let twoMinutesAgo = moment().subtract(2, 'minutes');
// from() is the friendly formatted version of the above, same as what the {{moment-from-now}} helper does
let twoMinutesAgoFriendly = twoMinutesAgo.from();
// this is where we use the run loop to set the new value
run(() => { set(this, 'closedAt', twoMinutesAgo) }
// indexOf will return -1 if the text does not contain twoMinutesAgoFriendly
// If it does, it will contain the position in the text where it starts, so 0 or higher
// checking if it's higher than -1 means we check if the text contains it
assert.ok(page.closedAt.text.indexOf(twoMinutesAgoFriendly) > -1)
Then you do the same thing with, for example, two seconds ago, 2 days ago, etc. Actually, just those 3 examples ought to be enough in total.
set(this, 'author', user); | ||
set(this, 'closedAt', moment().subtract(2, 'days')); | ||
set(this, 'closedAt', moment().fromNow()); | ||
stubService(this, 'current-user', { user: { id: 1 } }); | ||
|
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.
For the life of me, I can't figure out how to get the timestamp to pass in and have been working on it for an very inefficient length of time, by that I mean all day. This thing has kicked my ass to and fro and I'm sick of looking at it and am going to move to something else so the day isn't a complete wash. Nikola has stepped in a bunch with some guidance, but it didn't seem to help my stupidity.
set(this, 'author', user); | ||
set(this, 'closedAt', moment().subtract(2, 'days')); | ||
set(this, 'closedAt', moment().fromNow()); |
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 found `fromNow()); from the moment docs here .
You closed this at {{moment-format conversationPart.updatedAt 'MM/DD/YYYY hh:mm:ss'}} | ||
{{else}} | ||
{{author.username}} closed this at {{moment-format conversationPart.updatedAt 'MM/DD/YYYY hh:mm:ss'}} | ||
{{/if}} |
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.
Indentation error here.
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.
Still have this indentation error, It starts at line 5, if it's not clear. The whole if-else chunk needs to be indented 3 levels deeper.
{{#if conversationPart.isLoaded}} | ||
{{conversations/conversation-part | ||
{{#if (eq conversationPart.partType 'Closed')}} |
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'm reasonably sure the type will be lowercased at all times, so this should probably be
{{#if (eq conversationPart.partType 'closed')}}
{ isLoaded: true, body: 'foo 3' } | ||
{ isLoaded:true, body: 'foo 1' }, | ||
{ isLoaded:true, body: 'foo 2' }, | ||
{ isLoaded:true, body: 'foo 3' } |
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 removed the spaces between isLoaded:
and true
here. You should put them back. That is the preferred formatting.
|
||
set(this, 'author', { user1 }); | ||
set(this, 'closedAt', moment().from()); | ||
stubService(this, 'current-user', { user }); |
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.
There's a misunderstanding here with the author.
{ user }
is an object shorthand. Basically, it's a shorter way of writing { user: user }
With that in mind
set(this, 'author', { user1 });
means you're actually doing
set(this, 'author', { user1: user1 });
which clearly wont work.
In your setup, there's no author.username
, author.id
, etc., there's 'author.user1.username,
author.user1.id`, etc.
Thus, what you need to do instead is,
set(this, 'author', user1);
Meaning, the value of author
in our component is the same as user1
What might be confusing you is the
stubService(this, 'current-user', { user });
but we actually do a different thing there.
If you take a look at how the actual current-user
service is implemented, under app/services/current-user.js
, you will see that it's an Ember.Service
, with a user
property in it, so what we're doing is exactly what we want to do - replace the actual service with a fake one, where the value of user
is our user.
That means, we will have currentUser.user
, currentUser.user.id
, currentUser.user.username
, etc., exactly as we want.
{{#if isSelf}} | ||
You closed this on {{moment-format conversationPart.closedAt 'MM/DD/YYYY hh:mm:ss'}} | ||
{{else}} | ||
{{author.username}} closed this on {{moment-format conversationPart.closedAt 'MM/DD/YYYY hh:mm:ss'}} |
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.
First of all, even if you write the test correctly, it wont pass because your component has a bug here:
It's supposed to be
{{#if isSelf}}
You closed this on {{moment-format closedAt 'MM/DD/YYYY hh:mm:ss'}}
{{else}}
{{author.username}} closed this on {{moment-format closedAt 'MM/DD/YYYY hh:mm:ss'}}
{{/if}}
Secondly, I apologize for this, but the task was incorrectly written. We don't want a formatted timestamp, we want a "friendly" timestamp, which we get ,using moment-from
instead of moment-format
, so what you actually want here is
{{#if isSelf}}
You closed this {{moment-from-now closedAt interval=60000}}
{{else}}
{{author.username}} closed this {{moment-from-now closedAt interval=60000}}
{{/if}}
Similar to how the conversation-part-comment
does it with its own timestamp.
This will cause the text to say something like
"You closed this a few seconds ago"
"Joe closed this a minute ago"
"James closed this a couple of hours ago"
"etc."
|
||
set(this, 'author', { user1 }); | ||
set(this, 'closedAt', moment().from()); | ||
stubService(this, 'current-user', { user }); |
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.
As for the time stamp, look for an example in admin-github-event-test.js
The general idea is to get some timestamp, either using Date.now()
or moment()
. Both will return the exact current time. The example above uses moment()
.
Then, store that time stamp into a variable. This is critical. You can't just go and do the following, for example:
let timestamp = moment();
assert.equal(timestamp, moment());
The simple reason you can't do this is that both Date.now()
and moment()
return a different value every time you call them - the current timestamp, meaning the exact time at the time the function was called.
So if we want to test our code here, we need to understand what our component is supposed to do - The intent of the test is to ensure that the component does what it supposed to do.
Our component is supposed to tell us who closed our conversation and when.
The who will be either the username of the author, or just "You" if the author is the current user, so we need two tests for that, which I think you'll know how to cover.
The "when" will be the time of the closing event, meaning the time the conversation part of "partType
" "closed"
was created (or, in terms of the code, the value of closedAt
). We also want the when
to nicely formatted in some manner, which is something I described in my comment above.
To give a few examples for the username part
- If the current user is
begedin
, and the person who closed the conversation isdaveconnis
, we want the text to contain"daveconnis closed this"
- If the current user is
daveconnis
anddaveconnis
closed the conversation, we want the text to say"You closed this"
As for the timestamp, it gets a bit more complicated because you sort of need to know how the friendly formatting works, but what you would do is something like
- Create a couple of timestamps at varying moments in the past
- For each of them
- set the value of
closedAt
to that - check if the text contains the friendly version of that timestamp
- due to some weird ember internals, you need to use the run loop to do that, otherwise it won't update
- set the value of
As a concrete example
// moment() returns the current time. `subtract(amount, type)` then modifies that
let twoMinutesAgo = moment().subtract(2, 'minutes');
// from() is the friendly formatted version of the above, same as what the {{moment-from-now}} helper does
let twoMinutesAgoFriendly = twoMinutesAgo.from();
// this is where we use the run loop to set the new value
run(() => { set(this, 'closedAt', twoMinutesAgo) }
// indexOf will return -1 if the text does not contain twoMinutesAgoFriendly
// If it does, it will contain the position in the text where it starts, so 0 or higher
// checking if it's higher than -1 means we check if the text contains it
assert.ok(page.closedAt.text.indexOf(twoMinutesAgoFriendly) > -1)
Then you do the same thing with, for example, two seconds ago, 2 days ago, etc. Actually, just those 3 examples ought to be enough in total.
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.
Almost there. Only minor details left :)
|
||
let text = `You closed this ${twoMinutesAgoFriendly}`; | ||
assert.equal(page.closedAt.text, text, 'The closed at timestamp is rendered'); |
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.
Good thinking with this. Easier to read than indexOf
.
A further suggestion would be to name it expectedText
, so you'd have
let expectedText = //...
assert.equal(page.closedAt.text, expectedText, //...
You closed this at {{moment-format conversationPart.updatedAt 'MM/DD/YYYY hh:mm:ss'}} | ||
{{else}} | ||
{{author.username}} closed this at {{moment-format conversationPart.updatedAt 'MM/DD/YYYY hh:mm:ss'}} | ||
{{/if}} |
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.
Still have this indentation error, It starts at line 5, if it's not clear. The whole if-else chunk needs to be indented 3 levels deeper.
Made the changes that Nikola laid out, got to the end where he said tests would break (they did) but I can't figure out what to do now. We've changed a lot of things, mostly exactly what Nik asked to change, but what I'm not sure about his HOW tests are breaking due to renaming closedByCurrentUser and sentByCurrentUser into isByCurrentUser.
Does adding |
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.
It would be much easier to help if you provided output of where the tests are failing and what you've done to diagnose.
@@ -4,7 +4,7 @@ import { alias } from '@ember/object/computed'; | |||
import { inject as service } from '@ember/service'; | |||
|
|||
export default Component.extend({ | |||
classNames: ['conversation-part'], | |||
classNames: ['conversation-part, conversation-part-comment'], |
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'm not sure precisely where your tests are breaking, but this is certainly a syntactical problem.
|
||
author: null, | ||
|
||
classNames: ['conversation-part-closed'], |
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 is missing a conversation-part
class name.
author: null, | ||
|
||
classNames: ['conversation-part-closed'], | ||
classNameBindings: ['isSelf:conversation-part-closed--is-self'], |
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 needed? I'm not sure what would differ stylistically here so it looks like it's just extra work.
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.
Do you mean classNameBindings: ['isSelf:conversation-part-closed--is-self'],
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.
Right, I'm not sure why it's needed here, since there's nothing special about you vs someone else closing (vs the chat bubble where it's gray vs blue).
app/models/conversation-part.js
Outdated
@@ -7,6 +7,7 @@ export default Model.extend({ | |||
insertedAt: attr(), | |||
readAt: attr(), | |||
updatedAt: attr(), | |||
closedAt: attr(), |
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 needs alpha-ordered.
You closed this {{moment-from-now closedAt interval=60000}} | ||
{{else}} | ||
{{author.username}} closed this {{moment-from-now closedAt interval=60000}} | ||
{{/if}} |
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 have indentation issues here.
{{conversation/conversation-part-closed | ||
author=conversationPart.author | ||
closedAt=conversationPart.insertedAt | ||
}} |
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.
Indentation here is off.
author=conversationPart.author | ||
body=conversationPart.body | ||
readAt=conversationPart.readAt | ||
sentAt=conversationPart.insertedAt | ||
}} | ||
}} |
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.
Indentation here is also off.
sentByCurrentUser: hasClass('conversation-part--is-self') | ||
isComment: hasClass('conversation-part--comment'), | ||
isClosed: hasClass('conversation-part--closed'), | ||
isByCurrentUser: hasClass('conversation-part--is-self') |
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 alpha-ordering here is off.
author: null, | ||
|
||
classNames: ['conversation-part', 'conversation-part--closed'], | ||
classNameBindings: ['isSelf:conversation-part-closed--is-self'], |
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.
@joshsmith Your comment got marked as outdated. I still think it's needed for the "displaying it left vs right" part of the style.
@daveconnis This needs to be
classNameBindings: ['isSelf:conversation-part--is-self'],
In case it's not clear, this tells Ember to add a conversation-part--is-self
css class to the component's HTML element, whenever the isSelf
property on the component is true
(or truthy).
We then use that class to style component differently when it's displayed to the user. Like in any other chat interface, if it's your message, or your action, it's written on your side (left vs right), compared to when it's the other user's message, where it's written on their side.
readAt=conversationPart.readAt | ||
sentAt=conversationPart.insertedAt | ||
}} | ||
{{/if}} |
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 whole {{else}}
block needs to be indented one level deeper.
app/models/conversation-part.js
Outdated
@@ -4,6 +4,7 @@ import { belongsTo } from 'ember-data/relationships'; | |||
|
|||
export default Model.extend({ | |||
body: attr(), | |||
closedAt: attr(), |
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.
There is no closedAt
on the model
The component's closedAt
property can be set to the model's insertedAt
or updatedAt
as we discussed. You already do this on line 16 of app/templates/components/conversations/conversation-thread.hbs
.
|
||
isComment: hasClass('conversation-part--comment'), | ||
isClosed: hasClass('conversation-part--closed'), | ||
isByCurrentUser: hasClass('conversation-part--is-self'), |
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 saw a question that got marked as outdated, which caused me to think page objects might not be completely clear to you. They are only ever used in tests and they are defined in a way that provides us with information we need to answer questions in tests.
If a conversation thread lists multiple conversations of different partType
values, we want to ask
- is this part displayed as a comment
- is this other part displayed as "user closed at"
We know that a comment has a conversation-part--coment
class, and we know that the other one has a conversation-part--closed
class, so we could ask
assert.ok($('conversation-part').classNames().indexOf('conversation-part--comment') > -1);
assert.ok($('conversation-part').classNames().indexOf('conversation-part--closed') > -1);
and that works, except it's not always completely clear what it is we're actually asking. Also, in multiple tests, we tend to ask the same or similar questions, so we have to repeat all of that. Then, if, for example, the class name changes, we have to change it in all of those places.
What page objects allow us to do is to specify
isClosed: hasClass('conversation-part--closed'),
in just one place and use that.
assert.ok(conversationPart.isClosed);
assert.ok(conversationPart.isComment);
That makes the question much clearer. Also, if the class changes, we change it in just that one place - in the page object.
closedAt=conversationPart.insertedAt | ||
}} | ||
{{else}} | ||
{{conversations/conversation-part-comment |
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.
Your indentation here is wrong.
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.
Need to reorder properties in app/components/conversations/conversation-part-closed.js and then this is good to go.
Just realized I can't really finish the "client filtering of parts based on authorization" without making a feature branch off of |
Realistically we don’t want to be merging all these branches into We could also – and this might be easier – branch off Does that make sense? |
I think that makes sense. So I'd create a |
👍 merged. Good work. |
Add conversation-part-closed component Rewrite existing conversation-part as conversation-part-comment
What's in this PR?
Adding a 'conversation-part-closed' component.
References #1636
Progress on: #1597