custom_profile_fields: Toggle new "display_in_profile_summary" field.

Custom profile fields table `CSS` changed to fit the new "Display"
column of checkboxes, checkboxes are for select/deselect custom
profile field to display in profile popover.

New option "Display in profile summary" added in create and edit
custom profile fields form, with the help of this the user can
pick max of 2 custom profile fields except for `LONG_TEXT` and
`USER` fields to display in his user profile popover.

Checkboxes will go in a disabled state, with an explanatory tooltip,
if we've already passed the limit of 2 fields with this setting
enabled.

Fixes #21215.
This commit is contained in:
Yogesh Sirsat 2022-08-17 17:46:15 +05:30 committed by Tim Abbott
parent cd71fdea60
commit a3094d0f26
9 changed files with 223 additions and 5 deletions

View File

@ -128,8 +128,24 @@ exports.fixtures = {
custom_profile_fields: {
type: "custom_profile_fields",
fields: [
{id: 1, name: "teams", type: 1, hint: "", field_data: "", order: 1},
{id: 2, name: "hobbies", type: 1, hint: "", field_data: "", order: 2},
{
id: 1,
name: "teams",
type: 1,
hint: "",
field_data: "",
order: 1,
display_in_profile_summary: false,
},
{
id: 2,
name: "hobbies",
type: 1,
hint: "",
field_data: "",
order: 2,
display_in_profile_summary: false,
},
],
},

View File

@ -13,10 +13,14 @@ const SHORT_TEXT_ID = 1;
const SELECT_ID = 3;
const EXTERNAL_ACCOUNT_ID = 7;
const LONG_TEXT_ID = 2;
const USER_FIELD_ID = 6;
const SHORT_TEXT_NAME = "Short text";
const SELECT_NAME = "Select";
const EXTERNAL_ACCOUNT_NAME = "External account";
const LONG_TEXT_NAME = "Long text";
const USER_FIELD_NAME = "Person";
const custom_profile_field_types = {
SHORT_TEXT: {
@ -31,6 +35,14 @@ const custom_profile_field_types = {
id: EXTERNAL_ACCOUNT_ID,
name: EXTERNAL_ACCOUNT_NAME,
},
LONG_TEXT: {
id: LONG_TEXT_ID,
name: LONG_TEXT_NAME,
},
USER: {
id: USER_FIELD_ID,
name: USER_FIELD_NAME,
},
};
page_params.custom_profile_field_types = custom_profile_field_types;
@ -71,6 +83,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
page_params.custom_profile_fields = {};
page_params.realm_default_external_accounts = JSON.stringify({});
$("#admin_profile_fields_table .display_in_profile_summary_false").toggleClass = () => {};
const template_data = [];
mock_template("settings/admin_profile_field_list.hbs", false, (data) => {
template_data.push(data);
@ -84,6 +98,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
name: "favorite color",
hint: "blue?",
field_data: "",
display_in_profile_summary: false,
valid_to_display_in_summary: true,
},
{
type: SELECT_ID,
@ -100,6 +116,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
order: 1,
},
]),
display_in_profile_summary: false,
valid_to_display_in_summary: true,
},
{
type: EXTERNAL_ACCOUNT_ID,
@ -109,6 +127,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
field_data: JSON.stringify({
subtype: "github",
}),
display_in_profile_summary: true,
valid_to_display_in_summary: true,
},
{
type: EXTERNAL_ACCOUNT_ID,
@ -119,6 +139,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
subtype: "custom",
url_pattern: "https://chat.zulip.com/%(username)s",
}),
display_in_profile_summary: true,
valid_to_display_in_summary: true,
},
];
const expected_template_data = [
@ -131,6 +153,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
choices: [],
is_select_field: false,
is_external_account_field: false,
display_in_profile_summary: false,
valid_to_display_in_summary: true,
},
can_modify: true,
realm_default_external_accounts: page_params.realm_default_external_accounts,
@ -147,6 +171,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
],
is_select_field: true,
is_external_account_field: false,
display_in_profile_summary: false,
valid_to_display_in_summary: true,
},
can_modify: true,
realm_default_external_accounts: page_params.realm_default_external_accounts,
@ -160,6 +186,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
choices: [],
is_select_field: false,
is_external_account_field: true,
display_in_profile_summary: true,
valid_to_display_in_summary: true,
},
can_modify: true,
realm_default_external_accounts: page_params.realm_default_external_accounts,
@ -173,6 +201,8 @@ run_test("populate_profile_fields", ({mock_template}) => {
choices: [],
is_select_field: false,
is_external_account_field: true,
display_in_profile_summary: true,
valid_to_display_in_summary: true,
},
can_modify: true,
realm_default_external_accounts: page_params.realm_default_external_accounts,

View File

@ -39,6 +39,7 @@ export function maybe_disable_widgets() {
.prop("disabled", true);
}
let display_in_profile_summary_fields_limit_reached = false;
let order = [];
const field_types = page_params.custom_profile_field_types;
@ -58,6 +59,14 @@ export function field_type_id_to_string(type_id) {
return undefined;
}
// Checking custom profile field type is valid for showing display in profile summary checkbox field.
function is_valid_to_display_in_summary(field_type) {
if (field_type === field_types.LONG_TEXT.id || field_type === field_types.USER.id) {
return false;
}
return true;
}
function update_profile_fields_table_element() {
const $profile_fields_table = $("#admin_profile_fields_table").expectOne();
@ -206,8 +215,9 @@ function set_up_create_field_form() {
$("#dialog_error").hide();
const $field_elem = $("#profile_field_external_accounts");
const $field_url_pattern_elem = $("#custom_external_account_url_pattern");
const profile_field_type = Number.parseInt($("#profile_field_type").val(), 10);
if (Number.parseInt($("#profile_field_type").val(), 10) === field_types.EXTERNAL_ACCOUNT.id) {
if (profile_field_type === field_types.EXTERNAL_ACCOUNT.id) {
$field_elem.show();
const $profile_field_external_account_type = $(
"#profile_field_external_accounts_type",
@ -230,6 +240,13 @@ function set_up_create_field_form() {
$field_url_pattern_elem.hide();
$field_elem.hide();
}
// Not showing "display in profile summary" option for long text/user profile field.
if (is_valid_to_display_in_summary(profile_field_type)) {
$("#profile_field_display_in_profile_summary").closest(".input-group").show();
} else {
$("#profile_field_display_in_profile_summary").closest(".input-group").hide();
}
}
function read_field_data_from_form(field_type_id, $profile_field_form, old_field_data) {
@ -261,6 +278,9 @@ function open_custom_profile_field_form_modal() {
hint: $("#profile_field_hint").val(),
field_type,
field_data: JSON.stringify(field_data),
display_in_profile_summary: $("#profile_field_display_in_profile_summary").is(
":checked",
),
};
const url = "/json/realm/profile_fields";
const opts = {
@ -275,6 +295,22 @@ function open_custom_profile_field_form_modal() {
set_up_select_field();
set_up_external_account_field();
clear_form_data();
// If we already have 2 custom profile fields configured to be
// displayed in the user profile summary, disable the input to
// change it.
$("#add-new-custom-profile-field-form #profile_field_display_in_profile_summary").prop(
"disabled",
display_in_profile_summary_fields_limit_reached,
);
$("#add-new-custom-profile-field-form .profile_field_display_label").toggleClass(
"disabled_label",
display_in_profile_summary_fields_limit_reached,
);
$("#add-new-custom-profile-field-form .checkbox").toggleClass(
"display_in_profile_summary_tooltip",
display_in_profile_summary_fields_limit_reached,
);
}
dialog_widget.launch({
@ -409,8 +445,10 @@ function open_edit_form_modal(e) {
name: field.name,
hint: field.hint,
choices,
display_in_profile_summary: field.display_in_profile_summary === true,
is_select_field: field.type === field_types.SELECT.id,
is_external_account_field: field.type === field_types.EXTERNAL_ACCOUNT.id,
valid_to_display_in_summary: is_valid_to_display_in_summary(field.type),
},
realm_default_external_accounts: page_params.realm_default_external_accounts,
});
@ -418,6 +456,17 @@ function open_edit_form_modal(e) {
function set_initial_values_of_profile_field() {
const $profile_field_form = $("#edit-custom-profile-field-form-" + field_id);
// If its passes or equals the max limit we are disabling option for display custom profile field
// in user profile summary and adding tooptip except already checked field.
if (display_in_profile_summary_fields_limit_reached && !field.display_in_profile_summary) {
$profile_field_form
.find("input[name=display_in_profile_summary]")
.prop("disabled", true);
$profile_field_form
.find(".checkbox")
.addClass("display_in_profile_summary_tooltip disabled_label");
}
if (Number.parseInt(field.type, 10) === field_types.SELECT.id) {
set_up_select_field_edit_form($profile_field_form, field_data);
}
@ -450,6 +499,9 @@ function open_edit_form_modal(e) {
data.name = $profile_field_form.find("input[name=name]").val();
data.hint = $profile_field_form.find("input[name=hint]").val();
data.display_in_profile_summary = $profile_field_form
.find("input[name=display_in_profile_summary]")
.is(":checked");
const new_field_data = read_field_data_from_form(
Number.parseInt(field.type, 10),
@ -493,12 +545,52 @@ function open_edit_form_modal(e) {
form_id: edit_custom_profile_field_form_id,
html_heading: $t_html({defaultMessage: "Edit custom profile field"}),
html_body,
id: "edit-custom-profile-field-form-modal",
on_click: submit_form,
post_render: set_initial_values_of_profile_field,
loading_spinner: true,
});
}
// If passes or equals the max limit, we are disabling option for
// display custom profile field in user profile summary and adding tooltip.
function update_profile_fields_checkboxes() {
// Disabling only uncheck checkboxes in table, so user should able uncheck checked checkboxes.
$("#admin_profile_fields_table .display_in_profile_summary_checkbox_false").prop(
"disabled",
display_in_profile_summary_fields_limit_reached,
);
$("#admin_profile_fields_table .display_in_profile_summary_false").toggleClass(
"display_in_profile_summary_tooltip",
display_in_profile_summary_fields_limit_reached,
);
}
function toggle_display_in_profile_summary_profile_field(e) {
const field_id = Number.parseInt($(e.currentTarget).attr("data-profile-field-id"), 10);
const field = get_profile_field(field_id);
let field_data;
if (field.field_data) {
field_data = field.field_data;
}
const data = {
name: field.name,
hint: field.hint,
field_data,
display_in_profile_summary: !field.display_in_profile_summary,
};
const $profile_field_status = $("#admin-profile-field-status").expectOne();
settings_ui.do_settings_change(
channel.patch,
"/json/realm/profile_fields/" + field_id,
data,
$profile_field_status,
);
}
export function reset() {
meta.loaded = false;
}
@ -533,6 +625,7 @@ export function do_populate_profile_fields(profile_fields_data) {
$profile_fields_table.find("tr.profile-field-form").remove(); // Clear all rows.
order = [];
let display_in_profile_summary_fields_count = 0;
for (const profile_field of profile_fields_data) {
order.push(profile_field.id);
let field_data = {};
@ -544,6 +637,7 @@ export function do_populate_profile_fields(profile_fields_data) {
choices = parse_field_choices_from_field_data(field_data);
}
const display_in_profile_summary = profile_field.display_in_profile_summary === true;
$profile_fields_table.append(
render_admin_profile_field_list({
profile_field: {
@ -555,13 +649,23 @@ export function do_populate_profile_fields(profile_fields_data) {
is_select_field: profile_field.type === field_types.SELECT.id,
is_external_account_field:
profile_field.type === field_types.EXTERNAL_ACCOUNT.id,
display_in_profile_summary,
valid_to_display_in_summary: is_valid_to_display_in_summary(profile_field.type),
},
can_modify: page_params.is_admin,
realm_default_external_accounts: page_params.realm_default_external_accounts,
}),
);
// Keeping counts of all display_in_profile_summary profile fields, to keep track.
if (display_in_profile_summary) {
display_in_profile_summary_fields_count += 1;
}
}
// Update whether we're at the limit for display_in_profile_summary.
display_in_profile_summary_fields_limit_reached = display_in_profile_summary_fields_count >= 2;
if (page_params.is_admin) {
const field_list = $("#admin_profile_fields_table")[0];
Sortable.create(field_list, {
@ -571,6 +675,7 @@ export function do_populate_profile_fields(profile_fields_data) {
});
}
update_profile_fields_checkboxes();
update_profile_fields_table_element();
loading.destroy_indicator($("#admin_page_profile_fields_loading_indicator"));
}
@ -647,4 +752,9 @@ export function build_page() {
$("#admin_profile_fields_table").on("click", ".delete", delete_profile_field);
$("#add-custom-profile-field-btn").on("click", open_custom_profile_field_form_modal);
$("#admin_profile_fields_table").on("click", ".open-edit-form-modal", open_edit_form_modal);
$("#admin_profile_fields_table").on(
"click",
".display_in_profile_summary",
toggle_display_in_profile_summary_profile_field,
);
}

View File

@ -367,4 +367,26 @@ export function initialize() {
// Avoid inheriting `position: relative` CSS on the stream sorter widget.
appendTo: () => document.body,
});
delegate("body", {
// This tooltip appears on the "Summary" checkboxes in
// settings > custom profile fields, when at the limit of 2
// fields with display_in_profile_summary enabled.
target: [
"#profile-field-settings .display_in_profile_summary_tooltip",
"#edit-custom-profile-field-form-modal .display_in_profile_summary_tooltip",
"#add-new-custom-profile-field-form .display_in_profile_summary_tooltip",
],
content: $t({
defaultMessage: "Only 2 custom profile fields can be displayed in the profile summary.",
}),
appendTo: () => document.body,
onTrigger(instance) {
// Sometimes just removing class is not enough to destroy/remove tooltip, especially in
// "Add a new custom profile field" form, so here we are manually calling `destroy()`.
if (!instance.reference.classList.contains("display_in_profile_summary_tooltip")) {
instance.destroy();
}
},
});
}

View File

@ -213,8 +213,9 @@ h3,
width: 20%;
}
.admin-table-wrapper table.admin_profile_fields_table tr td {
width: 28%;
/* Limit the actions column to not using excessive width */
.admin-table-wrapper table.admin_profile_fields_table tr .actions {
width: 11%;
}
}
@ -640,6 +641,10 @@ input[type="checkbox"] {
margin-left: calc(10em + 20px) !important;
}
margin-bottom: 15px;
.checkbox {
margin-top: 5px;
}
}
.grey-box .wrapper {
@ -1870,3 +1875,11 @@ $option_title_width: 180px;
margin-top: 12px;
}
}
#add-new-custom-profile-field-form,
#edit-custom-profile-field-form-modal {
.disabled_label {
cursor: default;
opacity: 0.7;
}
}

View File

@ -36,5 +36,12 @@
<label for="custom_field_url_pattern" >{{t "URL pattern" }}</label>
<input type="url" id="custom_field_url_pattern" name="url_pattern" autocomplete="off" maxlength="1024" placeholder="https://example.com/path/%(username)s"/>
</div>
<div class="input-group">
<label class="checkbox profile_field_display_label" for="profile_field_display_in_profile_summary">
<input type="checkbox" id="profile_field_display_in_profile_summary" name="display_in_profile_summary"/>
<span></span>
{{t 'Display in profile summary' }}
</label>
</div>
</div>
</form>

View File

@ -13,6 +13,16 @@
<td>
<span class="profile_field_type">{{type}}</span>
</td>
<td>
{{#if valid_to_display_in_summary}}
<span class="profile_field_display_in_profile_summary">
<label class="checkbox display_in_profile_summary_{{display_in_profile_summary}}" for="profile_field_display_in_profile_summary_{{id}}">
<input class="display_in_profile_summary display_in_profile_summary_checkbox_{{display_in_profile_summary}}" type="checkbox" id="profile_field_display_in_profile_summary_{{id}}" {{#if display_in_profile_summary}} checked="checked" {{/if}} data-profile-field-id="{{id}}"/>
<span></span>
</label>
</span>
{{/if}}
</td>
{{#if ../can_modify}}
<td>
<button class="button rounded small btn-warning open-edit-form-modal" title="{{t 'Edit' }}" data-profile-field-id="{{id}}">

View File

@ -36,5 +36,14 @@
<input type="url" name="url_pattern" autocomplete="off" maxlength="80" />
</div>
{{/if}}
{{#if valid_to_display_in_summary}}
<div class="input-group">
<label class="checkbox edit_profile_field_display_label" for="edit_display_in_profile_summary_{{id}}">
<input class="edit_display_in_profile_summary" type="checkbox" id="edit_display_in_profile_summary_{{id}}" name="display_in_profile_summary" {{#if display_in_profile_summary}} checked="checked" {{/if}}/>
<span></span>
{{t 'Display in profile summary' }}
</label>
</div>
{{/if}}
</form>
{{/with}}

View File

@ -13,6 +13,7 @@
<th>{{t "Hint" }}</th>
<th>{{t "Type" }}</th>
{{#if is_admin}}
<th class="display">{{t "Summary"}}</th>
<th class="actions">{{t "Actions" }}</th>
{{/if}}
</tbody>