Use configured nickname in profile view in the control box.
Remove doc for the unimplemented `fullname` setting.
This commit is contained in:
JC Brand 2023-06-02 07:22:55 +02:00
parent 0a338feb40
commit 27a47c6ee8
9 changed files with 139 additions and 112 deletions

View File

@ -7,7 +7,9 @@
- Fix `autojoin` checkbox state in MUC bookmark form
- Remove call to `api.confirm` in `@converse/headless`
- Generate TypeScript declaration files into `dist/types`
- Removed documentation about the no longer implemented `fullname` option.
- #3156: Add function to prevent drag stutter effect over iframes when resize is called in overlay mode
- #3165: Use configured nickname in profile view in the control box
- New config option [stanza_timeout](https://conversejs.org/docs/html/configuration.html#stanza-timeout)

View File

@ -925,12 +925,6 @@ filter_url_query_params
Accepts a string or array of strings. Any query strings from URLs that match this setting will be removed.
fullname
--------
If you are using prebinding, can specify the fullname of the currently
logged in user, otherwise the user's vCard will be fetched.
geouri_regex
------------

View File

@ -104,6 +104,8 @@ module.exports = function(config) {
{ pattern: "src/plugins/omemo/tests/muc.js", type: 'module' },
{ pattern: "src/plugins/omemo/tests/omemo.js", type: 'module' },
{ pattern: "src/plugins/profile/tests/password-reset.js", type: 'module' },
{ pattern: "src/plugins/profile/tests/profile.js", type: 'module' },
{ pattern: "src/plugins/profile/tests/status.js", type: 'module' },
{ pattern: "src/plugins/push/tests/push.js", type: 'module' },
{ pattern: "src/plugins/register/tests/register.js", type: 'module' },
{ pattern: "src/plugins/roomslist/tests/roomslist.js", type: 'module' },

View File

@ -5,11 +5,11 @@ import { _converse, api, converse } from '@converse/headless/core';
const { Strophe, $pres } = converse.env;
const XMPPStatus = Model.extend({
export default class XMPPStatus extends Model {
defaults () {
defaults () { // eslint-disable-line class-methods-use-this
return { "status": api.settings.get("default_state") }
},
}
initialize () {
this.on('change', item => {
@ -20,16 +20,19 @@ const XMPPStatus = Model.extend({
api.user.presence.send(this.get('status'), null, this.get('status_message'));
}
});
},
}
getNickname () {
getDisplayName () {
return this.getFullname() || this.getNickname() || _converse.bare_jid;
}
getNickname () { // eslint-disable-line class-methods-use-this
return api.settings.get('nickname');
},
}
getFullname () {
// Gets overridden in converse-vcard
return '';
},
getFullname () { // eslint-disable-line class-methods-use-this
return ''; // Gets overridden in converse-vcard
}
/** Constructs a presence stanza
* @param { string } [type]
@ -85,6 +88,4 @@ const XMPPStatus = Model.extend({
presence = await api.hook('constructedPresence', null, presence);
return presence;
}
});
export default XMPPStatus;
}

View File

@ -2,7 +2,6 @@
const $msg = converse.env.$msg;
const u = converse.env.utils;
const Strophe = converse.env.Strophe;
describe("The Controlbox", function () {
@ -105,67 +104,4 @@ describe("The Controlbox", function () {
await u.waitUntil(() => rosterview.querySelector('.msgs-indicator') === null);
}));
});
describe("The Status Widget", function () {
it("shows the user's chat status, which is online by default",
mock.initConverse([], {}, async function (_converse) {
mock.openControlBox(_converse);
const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true);
expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
}));
it("can be used to set the current user's chat status",
mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
cbview.querySelector('.change-status').click()
const modal = _converse.api.modal.get('converse-chat-status-modal');
await u.waitUntil(() => u.isVisible(modal), 1000);
modal.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
modal.querySelector('[type="submit"]').click();
const sent_stanzas = _converse.connection.sent_stanzas;
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
expect(Strophe.serialize(sent_presence)).toBe(
`<presence xmlns="jabber:client">`+
`<show>dnd</show>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="TfHz9vOOfqIG0Z9lW5CuPaWGnrQ=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`);
const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
const first_child = view.querySelector('.xmpp-status span:first-child');
expect(u.hasClass('online', first_child)).toBe(false);
expect(u.hasClass('dnd', first_child)).toBe(true);
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
}));
it("can be used to set a custom status message",
mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
cbview.querySelector('.change-status').click()
const modal = _converse.api.modal.get('converse-chat-status-modal');
await u.waitUntil(() => u.isVisible(modal), 1000);
const msg = 'I am happy';
modal.querySelector('input[name="status_message"]').value = msg;
modal.querySelector('[type="submit"]').click();
const sent_stanzas = _converse.connection.sent_stanzas;
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
expect(Strophe.serialize(sent_presence)).toBe(
`<presence xmlns="jabber:client">`+
`<status>I am happy</status>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="TfHz9vOOfqIG0Z9lW5CuPaWGnrQ=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`);
const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
const first_child = view.querySelector('.xmpp-status span:first-child');
expect(u.hasClass('online', first_child)).toBe(true);
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
}));
});
});

View File

@ -1,6 +1,6 @@
import 'shared/avatar/avatar.js';
import { __ } from 'i18n';
import { _converse, api } from "@converse/headless/core";
import { api } from "@converse/headless/core";
import { getPrettyStatus, logOut } from '../utils.js';
import { html } from "lit";
@ -21,7 +21,6 @@ function tplUserSettingsButton (o) {
export default (el) => {
const chat_status = el.model.get('status') || 'offline';
const fullname = el.model.vcard?.get('fullname') || el.model.vcard?.get('nickname') || _converse.bare_jid;
const status_message = el.model.get('status_message') || __("I am %1$s", getPrettyStatus(chat_status));
const i18n_change_status = __('Click to change your chat status');
const show_settings_button = api.settings.get('show_client_info') || api.settings.get('allow_adhoc_commands');
@ -44,7 +43,7 @@ export default (el) => {
nonce=${el.model.vcard?.get('vcard_updated')}
height="40" width="40"></converse-avatar>
</a>
<span class="username w-100 align-self-center">${fullname}</span>
<span class="username w-100 align-self-center">${el.model.getDisplayName()}</span>
${show_settings_button ? tplUserSettingsButton(el) : ''}
${api.settings.get('allow_logout') ? tplSignout() : ''}
</div>

View File

@ -0,0 +1,17 @@
/*global mock, converse */
const u = converse.env.utils;
describe("The Controlbox", function () {
describe("The user profile", function () {
it("shows the user's configured nickname",
mock.initConverse([], { blacklisted_plugins: ['converse-vcard'], nickname: 'nicky'},
async function (_converse) {
mock.openControlBox(_converse);
const el = await u.waitUntil(() => document.querySelector('converse-user-profile .username'));
expect(el.textContent).toBe('nicky');
}));
});
});

View File

@ -0,0 +1,69 @@
/*global mock, converse */
const u = converse.env.utils;
const Strophe = converse.env.Strophe;
describe("The Controlbox", function () {
describe("The Status Widget", function () {
it("shows the user's chat status, which is online by default",
mock.initConverse([], {}, async function (_converse) {
mock.openControlBox(_converse);
const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true);
expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
}));
it("can be used to set the current user's chat status",
mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
cbview.querySelector('.change-status').click()
const modal = _converse.api.modal.get('converse-chat-status-modal');
await u.waitUntil(() => u.isVisible(modal), 1000);
modal.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
modal.querySelector('[type="submit"]').click();
const sent_stanzas = _converse.connection.sent_stanzas;
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
expect(Strophe.serialize(sent_presence)).toBe(
`<presence xmlns="jabber:client">`+
`<show>dnd</show>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="TfHz9vOOfqIG0Z9lW5CuPaWGnrQ=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`);
const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
const first_child = view.querySelector('.xmpp-status span:first-child');
expect(u.hasClass('online', first_child)).toBe(false);
expect(u.hasClass('dnd', first_child)).toBe(true);
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
}));
it("can be used to set a custom status message",
mock.initConverse([], {}, async function (_converse) {
await mock.openControlBox(_converse);
const cbview = _converse.chatboxviews.get('controlbox');
cbview.querySelector('.change-status').click()
const modal = _converse.api.modal.get('converse-chat-status-modal');
await u.waitUntil(() => u.isVisible(modal), 1000);
const msg = 'I am happy';
modal.querySelector('input[name="status_message"]').value = msg;
modal.querySelector('[type="submit"]').click();
const sent_stanzas = _converse.connection.sent_stanzas;
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
expect(Strophe.serialize(sent_presence)).toBe(
`<presence xmlns="jabber:client">`+
`<status>I am happy</status>`+
`<priority>0</priority>`+
`<c hash="sha-1" node="https://conversejs.org" ver="TfHz9vOOfqIG0Z9lW5CuPaWGnrQ=" xmlns="http://jabber.org/protocol/caps"/>`+
`</presence>`);
const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
const first_child = view.querySelector('.xmpp-status span:first-child');
expect(u.hasClass('online', first_child)).toBe(true);
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
}));
});
});

View File

@ -643,31 +643,8 @@ function clearStores () {
window.sessionStorage.removeItem(cache_key+'fetched');
}
const theme = ['dracula', 'classic', 'concord'][Math.floor(Math.random()*3)];
async function _initConverse (settings) {
clearStores();
await clearIndexedDB();
_converse = await converse.initialize(Object.assign({
'animate': false,
'auto_subscribe': false,
'bosh_service_url': 'montague.lit/http-bind',
'discover_connection_methods': false,
'enable_smacks': false,
'i18n': 'en',
'loglevel': 'debug',
'no_trimming': true,
'persistent_store': 'localStorage',
'play_sounds': false,
'theme': theme,
'use_emojione': false,
'view_mode': view_mode
}, settings || {}));
window._converse = _converse;
_converse.api.vcard.get = function (model, force) {
function getMockVcardFetcher (settings) {
return (model, force) => {
let jid;
if (typeof model === 'string' || model instanceof String) {
jid = model;
@ -702,7 +679,37 @@ async function _initConverse (settings) {
'vcard_updated': dayjs().format(),
'vcard_error': undefined
};
};
}
}
const theme = ['dracula', 'classic', 'concord'][Math.floor(Math.random()*3)];
async function _initConverse (settings) {
clearStores();
await clearIndexedDB();
_converse = await converse.initialize(Object.assign({
'animate': false,
'auto_subscribe': false,
'bosh_service_url': 'montague.lit/http-bind',
'discover_connection_methods': false,
'enable_smacks': false,
'i18n': 'en',
'loglevel': 'debug',
'no_trimming': true,
'persistent_store': 'localStorage',
'play_sounds': false,
'theme': theme,
'use_emojione': false,
'view_mode': view_mode
}, settings || {}));
window._converse = _converse;
if (_converse.api.vcard) {
_converse.api.vcard.get = getMockVcardFetcher(settings);
}
if (settings?.auto_login !== false) {
_converse.api.user.login('romeo@montague.lit/orchard', 'secret');
await _converse.api.waitUntil('afterResourceBinding');