bots: Display full user profile modal for bots.

This commit can display a full user profile modal for bots too,
by clicking on "View Full Profile" in the profile info popover
same as normal users.

Fixes part of: #21402
This commit is contained in:
Yogesh Sirsat
2022-08-24 17:16:25 +05:30
committed by Tim Abbott
parent 180a9cbdcb
commit 23fbd38b4c
6 changed files with 107 additions and 41 deletions

View File

@@ -190,7 +190,6 @@ test_ui("sender_hover", ({override, mock_template}) => {
sent_by_uri: "#narrow/sender/42-alice", sent_by_uri: "#narrow/sender/42-alice",
private_message_class: "respond_personal_button", private_message_class: "respond_personal_button",
show_email: false, show_email: false,
show_user_profile: true,
is_me: false, is_me: false,
is_active: true, is_active: true,
is_bot: undefined, is_bot: undefined,

View File

@@ -241,7 +241,6 @@ function render_user_info_popover(
private_message_class: private_msg_class, private_message_class: private_msg_class,
sent_by_uri: hash_util.by_sender_url(user.email), sent_by_uri: hash_util.by_sender_url(user.email),
show_email: settings_data.show_email(), show_email: settings_data.show_email(),
show_user_profile: !user.is_bot,
user_email: people.get_visible_email(user), user_email: people.get_visible_email(user),
user_full_name: user.full_name, user_full_name: user.full_name,
user_id: user.user_id, user_id: user.user_id,

View File

@@ -17,6 +17,7 @@ import {page_params} from "./page_params";
import * as people from "./people"; import * as people from "./people";
import * as popovers from "./popovers"; import * as popovers from "./popovers";
import * as settings_account from "./settings_account"; import * as settings_account from "./settings_account";
import * as settings_bots from "./settings_bots";
import * as settings_data from "./settings_data"; import * as settings_data from "./settings_data";
import * as settings_profile_fields from "./settings_profile_fields"; import * as settings_profile_fields from "./settings_profile_fields";
import * as stream_data from "./stream_data"; import * as stream_data from "./stream_data";
@@ -24,12 +25,34 @@ import * as sub_store from "./sub_store";
import * as subscriber_api from "./subscriber_api"; import * as subscriber_api from "./subscriber_api";
import * as ui_report from "./ui_report"; import * as ui_report from "./ui_report";
import * as user_groups from "./user_groups"; import * as user_groups from "./user_groups";
import * as user_pill from "./user_pill";
import * as util from "./util"; import * as util from "./util";
function compare_by_name(a, b) { function compare_by_name(a, b) {
return util.strcmp(a.name, b.name); return util.strcmp(a.name, b.name);
} }
function initialize_bot_owner(element_id, bot_id) {
const user_pills = new Map();
const bot = people.get_by_user_id(bot_id);
const bot_owner = people.get_bot_owner_user(bot);
// Bot owner's pill displaying on bots full profile modal.
if (bot_owner) {
const $pill_container = $(element_id)
.find(
`.bot_owner_user_field[data-field-id="${CSS.escape(
bot_owner.user_id,
)}"] .pill-container`,
)
.expectOne();
const pills = user_pill.create_pills($pill_container);
user_pill.append_user(bot_owner, pills);
user_pills.set(bot_owner.user_id, pills);
}
return user_pills;
}
function format_user_stream_list_item(stream, user) { function format_user_stream_list_item(stream, user) {
const show_unsubscribe_button = const show_unsubscribe_button =
people.is_my_user_id(user.user_id) || settings_data.user_can_unsubscribe_other_users(); people.is_my_user_id(user.user_id) || settings_data.user_can_unsubscribe_other_users();
@@ -154,6 +177,7 @@ export function show_user_profile(user) {
profile_data, profile_data,
user_avatar: people.medium_avatar_url_for_person(user), user_avatar: people.medium_avatar_url_for_person(user),
is_me: people.is_current_user(user.email), is_me: people.is_current_user(user.email),
is_bot: user.is_bot,
date_joined: dateFormat.format(parseISO(user.date_joined)), date_joined: dateFormat.format(parseISO(user.date_joined)),
user_circle_class: buddy_data.get_user_circle_class(user.user_id), user_circle_class: buddy_data.get_user_circle_class(user.user_id),
last_seen: buddy_data.user_last_seen_time_status(user.user_id), last_seen: buddy_data.user_last_seen_time_status(user.user_id),
@@ -163,6 +187,19 @@ export function show_user_profile(user) {
user_is_guest: user.is_guest, user_is_guest: user.is_guest,
}; };
if (user.is_bot) {
const is_system_bot = user.is_system_bot;
const bot_owner_id = user.bot_owner_id;
if (is_system_bot) {
args.is_system_bot = is_system_bot;
} else if (bot_owner_id) {
const bot_owner = people.get_by_user_id(bot_owner_id);
args.bot_owner = bot_owner;
args.show_email = true;
}
args.bot_type = settings_bots.type_id_to_string(user.bot_type);
}
$("#user-profile-modal-holder").html(render_user_profile_modal(args)); $("#user-profile-modal-holder").html(render_user_profile_modal(args));
overlays.open_modal("user-profile-modal", {autoremove: true}); overlays.open_modal("user-profile-modal", {autoremove: true});
$(".tabcontent").hide(); $(".tabcontent").hide();
@@ -193,12 +230,16 @@ export function show_user_profile(user) {
$elem.addClass("large allow-overflow"); $elem.addClass("large allow-overflow");
$("#tab-toggle").append($elem); $("#tab-toggle").append($elem);
settings_account.initialize_custom_user_type_fields( if (!user.is_bot) {
"#user-profile-modal #content", settings_account.initialize_custom_user_type_fields(
user.user_id, "#user-profile-modal #content",
false, user.user_id,
false, false,
); false,
);
} else {
initialize_bot_owner("#user-profile-modal #content", user.user_id);
}
} }
function handle_remove_stream_subscription(target_user_id, sub, success, failure) { function handle_remove_stream_subscription(target_user_id, sub, success, failure) {

View File

@@ -1663,19 +1663,22 @@ $option_title_width: 180px;
} }
} }
.custom_user_field .pill-container { .custom_user_field,
padding: 2px 6px; .bot_owner_user_field {
min-height: 24px; .pill-container {
max-width: 206px; padding: 2px 6px;
background-color: hsl(0, 0%, 100%); min-height: 24px;
max-width: 206px;
background-color: hsl(0, 0%, 100%);
&:focus-within { &:focus-within {
border-color: hsla(206, 80%, 62%, 0.8); border-color: hsla(206, 80%, 62%, 0.8);
outline: 0; outline: 0;
outline: 1px dotted \9; outline: 1px dotted \9;
box-shadow: inset 0 1px 1px hsla(0, 0%, 0%, 0.075), box-shadow: inset 0 1px 1px hsla(0, 0%, 0%, 0.075),
0 0 8px hsla(206, 80%, 62%, 0.6); 0 0 8px hsla(206, 80%, 62%, 0.6);
}
} }
} }

View File

@@ -102,7 +102,6 @@
{{else}} {{else}}
<hr /> <hr />
{{#if show_user_profile}}
<li> <li>
<a tabindex="0" class="view_full_user_profile"> <a tabindex="0" class="view_full_user_profile">
{{#if is_me}} {{#if is_me}}
@@ -112,7 +111,6 @@
{{/if}} {{/if}}
</a> </a>
</li> </li>
{{/if}}
{{#if can_send_private_message}} {{#if can_send_private_message}}
<li> <li>
<a tabindex="0" class="{{ private_message_class }}"> <a tabindex="0" class="{{ private_message_class }}">

View File

@@ -5,6 +5,9 @@
<button class="modal__close" aria-label="{{t 'Close modal' }}" data-micromodal-close></button> <button class="modal__close" aria-label="{{t 'Close modal' }}" data-micromodal-close></button>
<div id="name"> <div id="name">
{{full_name}} {{full_name}}
{{#if is_bot}}
<i class="zulip-icon zulip-icon-bot" aria-hidden="true"></i>
{{/if}}
{{#if is_me}} {{#if is_me}}
<a href="/#settings/profile"> <a href="/#settings/profile">
<i class="fa fa-edit" id="edit-button" aria-hidden="true"></i> <i class="fa fa-edit" id="edit-button" aria-hidden="true"></i>
@@ -29,7 +32,15 @@
</div> </div>
<div id="user-type" class="default-field"> <div id="user-type" class="default-field">
<div class="name">{{#tr}}Role{{/tr}}</div> <div class="name">{{#tr}}Role{{/tr}}</div>
<div class="value">{{user_type}}</div> {{#if is_bot}}
{{#if is_system_bot}}
<div class="value">{{#tr}}System bot{{/tr}}</div>
{{else}}
<div class="value">{{#tr}}Bot{{/tr}}</div>
{{/if}}
{{else}}
<div class="value">{{user_type}}</div>
{{/if}}
</div> </div>
<div id="date-joined" class="default-field"> <div id="date-joined" class="default-field">
<div class="name">{{#tr}}Joined{{/tr}}</div> <div class="name">{{#tr}}Joined{{/tr}}</div>
@@ -55,26 +66,41 @@
</div> </div>
<div class="bottom"> <div class="bottom">
<div id="content"> <div id="content">
{{#each profile_data}} {{#if is_bot}}
<div data-type="{{this.type}}" class="field-section custom_user_field" data-field-id="{{this.id}}"> <div class="field-section">
<div class="name">{{this.name}}</div> <div class="name">{{#tr}}Bot type{{/tr}}</div>
{{#if this.is_user_field}} <div class="bot_info_value">{{bot_type}}</div>
<div class="pill-container not-editable" data-field-id="{{this.id}}">
<div class="input" contenteditable="false" style="display: none;"></div>
</div>
{{else if this.is_link}}
<a href="{{this.value}}" target="_blank" rel="noopener noreferrer" class="value">{{this.value}}</a>
{{else if this.is_external_account}}
<a href="{{this.link}}" target="_blank" rel="noopener noreferrer" class="value">{{this.value}}</a>
{{else}}
{{#if this.rendered_value}}
<div class="value rendered_markdown">{{rendered_markdown this.rendered_value}}</div>
{{else}}
<div class="value">{{this.value}}</div>
{{/if}}
{{/if}}
</div> </div>
{{/each}} {{#if bot_owner}}
<div class="field-section bot_owner_user_field" data-field-id="{{bot_owner.user_id}}">
<div class="name">{{#tr}}Owner{{/tr}}</div>
<div class="pill-container not-editable">
<div class="input" contenteditable="false" style="display: none;"></div>
</div>
</div>
{{/if}}
{{else}}
{{#each profile_data}}
<div data-type="{{this.type}}" class="field-section custom_user_field" data-field-id="{{this.id}}">
<div class="name">{{this.name}}</div>
{{#if this.is_user_field}}
<div class="pill-container not-editable" data-field-id="{{this.id}}">
<div class="input" contenteditable="false" style="display: none;"></div>
</div>
{{else if this.is_link}}
<a href="{{this.value}}" target="_blank" rel="noopener noreferrer" class="value">{{this.value}}</a>
{{else if this.is_external_account}}
<a href="{{this.link}}" target="_blank" rel="noopener noreferrer" class="value">{{this.value}}</a>
{{else}}
{{#if this.rendered_value}}
<div class="value rendered_markdown">{{rendered_markdown this.rendered_value}}</div>
{{else}}
<div class="value">{{this.value}}</div>
{{/if}}
{{/if}}
</div>
{{/each}}
{{/if}}
</div> </div>
</div> </div>
</div> </div>