FEATURE: show user status on group pages (#19323)
This adds live user status to /g/{group-name} routes.
This commit is contained in:
parent
492f68c462
commit
ff5a0bec89
|
@ -12,6 +12,16 @@ export default Component.extend({
|
||||||
includeLink: true,
|
includeLink: true,
|
||||||
includeAvatar: true,
|
includeAvatar: true,
|
||||||
|
|
||||||
|
didInsertElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.user?.trackStatus?.();
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.user?.stopTrackingStatus?.();
|
||||||
|
},
|
||||||
|
|
||||||
@discourseComputed("user.username")
|
@discourseComputed("user.username")
|
||||||
userPath(username) {
|
userPath(username) {
|
||||||
return userPath(username);
|
return userPath(username);
|
||||||
|
|
|
@ -28,7 +28,10 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</span>
|
</span>
|
||||||
{{#if (and @showStatus @user.status)}}
|
{{#if (and @showStatus @user.status)}}
|
||||||
<UserStatusMessage @status={{@user.status}} @showDescription={{true}} @showTooltip={{false}} />
|
<UserStatusMessage
|
||||||
|
@status={{@user.status}}
|
||||||
|
@showDescription={{@showStatusDescription}}
|
||||||
|
@showTooltip={{@showStatusTooltip}} />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<PluginOutlet @name="after-user-name" @tagName="span" @connectorTagName="span" @args={{hash user=this.user}} />
|
<PluginOutlet @name="after-user-name" @tagName="span" @connectorTagName="span" @args={{hash user=this.user}} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -54,7 +54,11 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<td class="avatar" colspan="2">
|
<td class="avatar" colspan="2">
|
||||||
<UserInfo @user={{m}} @skipName={{this.skipName}} />
|
<UserInfo
|
||||||
|
@user={{m}}
|
||||||
|
@skipName={{this.skipName}}
|
||||||
|
@showStatus={{true}}
|
||||||
|
@showStatusTooltip={{true}}/>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="group-owner">
|
<td class="group-owner">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { module, test } from "qunit";
|
import { module, test } from "qunit";
|
||||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||||
import { render } from "@ember/test-helpers";
|
import { render, triggerEvent } from "@ember/test-helpers";
|
||||||
import { hbs } from "ember-cli-htmlbars";
|
import { hbs } from "ember-cli-htmlbars";
|
||||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
|
||||||
|
@ -91,4 +91,58 @@ module("Integration | Component | user-info", function (hooks) {
|
||||||
|
|
||||||
assert.notOk(exists(".user-status-message"));
|
assert.notOk(exists(".user-status-message"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("doesn't show status description by default", async function (assert) {
|
||||||
|
this.currentUser.name = "Evil Trout";
|
||||||
|
this.currentUser.status = { emoji: "tooth", description: "off to dentist" };
|
||||||
|
|
||||||
|
await render(
|
||||||
|
hbs`<UserInfo @user={{this.currentUser}} @showStatus={{true}} />`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(".user-status-message .user-status-message-description")
|
||||||
|
.doesNotExist();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shows status description if enabled", async function (assert) {
|
||||||
|
this.currentUser.name = "Evil Trout";
|
||||||
|
this.currentUser.status = { emoji: "tooth", description: "off to dentist" };
|
||||||
|
|
||||||
|
await render(
|
||||||
|
hbs`<UserInfo @user={{this.currentUser}} @showStatus={{true}} @showStatusDescription={{true}} />`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(".user-status-message .user-status-message-description")
|
||||||
|
.exists();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("doesn't show status tooltip by default", async function (assert) {
|
||||||
|
this.currentUser.name = "Evil Trout";
|
||||||
|
this.currentUser.status = { emoji: "tooth", description: "off to dentist" };
|
||||||
|
|
||||||
|
await render(
|
||||||
|
hbs`<UserInfo @user={{this.currentUser}} @showStatus={{true}} />`
|
||||||
|
);
|
||||||
|
await triggerEvent(query(".user-status-message"), "mouseenter");
|
||||||
|
|
||||||
|
assert.notOk(
|
||||||
|
document.querySelector("[data-tippy-root] .user-status-message-tooltip")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shows status tooltip if enabled", async function (assert) {
|
||||||
|
this.currentUser.name = "Evil Trout";
|
||||||
|
this.currentUser.status = { emoji: "tooth", description: "off to dentist" };
|
||||||
|
|
||||||
|
await render(
|
||||||
|
hbs`<UserInfo @user={{this.currentUser}} @showStatus={{true}} @showStatusTooltip={{true}} />`
|
||||||
|
);
|
||||||
|
await triggerEvent(query(".user-status-message"), "mouseenter");
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
document.querySelector("[data-tippy-root] .user-status-message-tooltip")
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -162,6 +162,13 @@ table.group-members {
|
||||||
.avatar-flair {
|
.avatar-flair {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-status-message {
|
||||||
|
img.emoji {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,8 +301,8 @@ class GroupsController < ApplicationController
|
||||||
|
|
||||||
users = users
|
users = users
|
||||||
.includes(:primary_group)
|
.includes(:primary_group)
|
||||||
.joins(:user_option)
|
.includes(:user_option)
|
||||||
.select('users.*, user_options.timezone, group_users.created_at as added_at')
|
.select('users.*, group_users.created_at as added_at')
|
||||||
.order(order)
|
.order(order)
|
||||||
.order(username_lower: dir)
|
.order(username_lower: dir)
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,22 @@ class GroupUserSerializer < BasicUserSerializer
|
||||||
:last_posted_at,
|
:last_posted_at,
|
||||||
:last_seen_at,
|
:last_seen_at,
|
||||||
:added_at,
|
:added_at,
|
||||||
:timezone
|
:timezone,
|
||||||
|
:status
|
||||||
|
|
||||||
|
def timezone
|
||||||
|
user.user_option.timezone
|
||||||
|
end
|
||||||
|
|
||||||
def include_added_at?
|
def include_added_at?
|
||||||
object.respond_to? :added_at
|
object.respond_to? :added_at
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def include_status?
|
||||||
|
SiteSetting.enable_user_status && user.has_status?
|
||||||
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
UserStatusSerializer.new(user.user_status, root: false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,7 +48,12 @@
|
||||||
{{on "keyup" (action "handleUserKeyUp" user)}}
|
{{on "keyup" (action "handleUserKeyUp" user)}}
|
||||||
>
|
>
|
||||||
<ChatUserAvatar @user={{user}} @avatarSize="medium" />
|
<ChatUserAvatar @user={{user}} @avatarSize="medium" />
|
||||||
<UserInfo @user={{user}} @includeLink={{false}} @includeAvatar={{false}} @showStatus={{true}} />
|
<UserInfo
|
||||||
|
@user={{user}}
|
||||||
|
@includeLink={{false}}
|
||||||
|
@includeAvatar={{false}}
|
||||||
|
@showStatus={{true}}
|
||||||
|
@showStatusDescription={{true}} />
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe GroupUserSerializer do
|
||||||
|
let(:serializer) { described_class.new(user, scope: Guardian.new(user), root: false) }
|
||||||
|
|
||||||
|
describe '#status' do
|
||||||
|
fab!(:user_status) { Fabricate(:user_status) }
|
||||||
|
fab!(:user) { Fabricate(:user, user_status: user_status) }
|
||||||
|
|
||||||
|
it "adds user status when enabled in site settings" do
|
||||||
|
SiteSetting.enable_user_status = true
|
||||||
|
|
||||||
|
json = serializer.as_json
|
||||||
|
|
||||||
|
expect(json[:status]).to_not be_nil do |status|
|
||||||
|
expect(status.description).to eq(user_status.description)
|
||||||
|
expect(status.emoji).to eq(user_status.emoji)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't add user status when disabled in site settings" do
|
||||||
|
SiteSetting.enable_user_status = false
|
||||||
|
json = serializer.as_json
|
||||||
|
expect(json.keys).not_to include :status
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't add expired user status" do
|
||||||
|
SiteSetting.enable_user_status = true
|
||||||
|
|
||||||
|
user.user_status.ends_at = 1.minutes.ago
|
||||||
|
serializer = described_class.new(user, scope: Guardian.new(user), root: false)
|
||||||
|
json = serializer.as_json
|
||||||
|
|
||||||
|
expect(json.keys).not_to include :status
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't return status if user doesn't have it" do
|
||||||
|
SiteSetting.enable_user_status = true
|
||||||
|
|
||||||
|
user.clear_status!
|
||||||
|
user.reload
|
||||||
|
json = serializer.as_json
|
||||||
|
|
||||||
|
expect(json.keys).not_to include :status
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue