mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
[MM-53102] Add support for multi-word highlights without notifications in web (#24050)
- Adds a new section under settings/notifications for adding custom multi-word keywords that get highlighted without notification - Adds a new classname for highlighting words although the styling is the same as mentions highlights - Added a few components to the ReduxFromProps pattern - Adds supported type for the hook of PluginComponent type - Add upsell for highlight without notification - Moved 'setting_item.tsx' to the components folder - Improved prop names and function structure for setting_item, setting_item_max and setting_item_min - Moved 'toggle_modal_button.tsx' to the components folder - Removed t and utility messages from a few components - Fixed bug where the tooltip was not getting rendered on restrictedButtons - Improved the mobile view of the settings modal - Adds E2E for the feature
This commit is contained in:
parent
48bf4e9bd8
commit
9ac389f506
@ -34,8 +34,8 @@ describe('Verify Accessibility Support in different sections in Settings and Pro
|
|||||||
{key: 'desktop', label: 'Desktop Notifications', type: 'radio'},
|
{key: 'desktop', label: 'Desktop Notifications', type: 'radio'},
|
||||||
{key: 'email', label: 'Email Notifications', type: 'radio'},
|
{key: 'email', label: 'Email Notifications', type: 'radio'},
|
||||||
{key: 'push', label: 'Mobile Push Notifications', type: 'radio'},
|
{key: 'push', label: 'Mobile Push Notifications', type: 'radio'},
|
||||||
{key: 'keysWithNotification', label: 'Keywords that trigger Notifications', type: 'checkbox'},
|
{key: 'keysWithNotification', label: 'Keywords That Trigger Notifications', type: 'checkbox'},
|
||||||
{key: 'comments', label: 'Reply notifications', type: 'radio'},
|
{key: 'comments', label: 'Reply Notifications', type: 'radio'},
|
||||||
],
|
],
|
||||||
display: [
|
display: [
|
||||||
{key: 'theme', label: 'Theme', type: 'radio'},
|
{key: 'theme', label: 'Theme', type: 'radio'},
|
||||||
|
@ -188,6 +188,8 @@ function mapFeatureIdToId(id: string) {
|
|||||||
return 'All Professional features';
|
return 'All Professional features';
|
||||||
case 'mattermost.feature.all_enterprise':
|
case 'mattermost.feature.all_enterprise':
|
||||||
return 'All Enterprise features';
|
return 'All Enterprise features';
|
||||||
|
case 'mattermost.feature.highlight_without_notification':
|
||||||
|
return 'Keywords Highlight Without Notification';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ describe('Auto Response In DMs', () => {
|
|||||||
// # Open 'Settings' modal and view 'Notifications'
|
// # Open 'Settings' modal and view 'Notifications'
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Click on 'Edit' for 'Automatic Direct Message Replies
|
// # Click on 'Edit' for 'Automatic Direct Message Replies
|
||||||
cy.get('#auto-responderEdit').should('be.visible').click();
|
cy.get('#auto-responderEdit').should('exist').scrollIntoView().and('be.visible').click();
|
||||||
|
|
||||||
// # Click on 'Enabled' checkbox
|
// # Click on 'Enabled' checkbox
|
||||||
cy.get('#autoResponderActive').should('be.visible').click();
|
cy.get('#autoResponderActive').should('be.visible').click();
|
||||||
|
@ -23,8 +23,8 @@ describe('Notifications', () => {
|
|||||||
|
|
||||||
// # Open 'Settings' modal
|
// # Open 'Settings' modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Open 'Keywords that trigger Notifications' setting and uncheck all the checkboxes
|
// # Open 'Keywords That Trigger Notifications' setting and uncheck all the checkboxes
|
||||||
cy.findByRole('heading', {name: 'Keywords that trigger Notifications'}).should('be.visible').click();
|
cy.findByRole('heading', {name: 'Keywords That Trigger Notifications'}).should('be.visible').click();
|
||||||
cy.findByRole('checkbox', {name: `Your case-sensitive first name "${otherUser.first_name}"`}).should('not.be.checked');
|
cy.findByRole('checkbox', {name: `Your case-sensitive first name "${otherUser.first_name}"`}).should('not.be.checked');
|
||||||
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
||||||
cy.findByRole('checkbox', {name: 'Channel-wide mentions "@channel", "@all", "@here"'}).click().should('not.be.checked');
|
cy.findByRole('checkbox', {name: 'Channel-wide mentions "@channel", "@all", "@here"'}).click().should('not.be.checked');
|
||||||
|
@ -252,7 +252,7 @@ function setNotificationSettings(desiredSettings = {first: true, username: true,
|
|||||||
cy.findAllByText('Notifications').should('be.visible');
|
cy.findAllByText('Notifications').should('be.visible');
|
||||||
|
|
||||||
// Open up 'Words that trigger mentions' sub-section
|
// Open up 'Words that trigger mentions' sub-section
|
||||||
cy.findByText('Keywords that trigger Notifications').
|
cy.findByText('Keywords That Trigger Notifications').
|
||||||
scrollIntoView().
|
scrollIntoView().
|
||||||
click();
|
click();
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ describe('Notifications', () => {
|
|||||||
|
|
||||||
// # Open 'Settings' modal
|
// # Open 'Settings' modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Open 'Keywords that trigger Notifications' setting
|
// # Open 'Keywords That Trigger Notifications' setting
|
||||||
cy.findByRole('heading', {name: 'Keywords that trigger Notifications'}).should('be.visible').click();
|
cy.findByRole('heading', {name: 'Keywords That Trigger Notifications'}).should('be.visible').click();
|
||||||
|
|
||||||
// * As otherUser, ensure that 'Your non-case sensitive username' is not checked
|
// * As otherUser, ensure that 'Your non-case sensitive username' is not checked
|
||||||
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
||||||
|
@ -9,7 +9,7 @@ export default class DeletePostModal {
|
|||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.confirmButton = this.container.locator('#deletePostModalButton');
|
this.confirmButton = container.locator('#deletePostModalButton');
|
||||||
}
|
}
|
||||||
|
|
||||||
async toBeVisible() {
|
async toBeVisible() {
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
type NotificationSettingsSection = 'keysWithHighlight' | 'keysWithNotification';
|
||||||
|
|
||||||
|
export default class NotificationsSettings {
|
||||||
|
readonly container: Locator;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async expandSection(section: NotificationSettingsSection) {
|
||||||
|
if (section === 'keysWithHighlight') {
|
||||||
|
await this.container.getByText('Keywords That Get Highlighted (without notifications)').click();
|
||||||
|
await this.verifySectionIsExpanded('keysWithHighlight');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifySectionIsExpanded(section: NotificationSettingsSection) {
|
||||||
|
await expect(this.container.locator(`#${section}Edit`)).not.toBeVisible();
|
||||||
|
|
||||||
|
if (section === 'keysWithHighlight') {
|
||||||
|
await expect(
|
||||||
|
this.container.getByText(
|
||||||
|
'Enter non case-sensitive keywords, press Tab or use commas to separate them:',
|
||||||
|
),
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
this.container.getByText(
|
||||||
|
'These keywords will be shown to you with a highlight when anyone sends a message that includes them.',
|
||||||
|
),
|
||||||
|
).toBeVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getKeywordsInput() {
|
||||||
|
await expect(this.container.locator('input')).toBeVisible();
|
||||||
|
return this.container.locator('input');
|
||||||
|
}
|
||||||
|
|
||||||
|
async save() {
|
||||||
|
await expect(this.container.getByText('Save')).toBeVisible();
|
||||||
|
await this.container.getByText('Save').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {NotificationsSettings};
|
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
import {NotificationsSettings} from './notification_settings';
|
||||||
|
|
||||||
|
export default class SettingsModal {
|
||||||
|
readonly container: Locator;
|
||||||
|
|
||||||
|
readonly notificationsSettingsTab;
|
||||||
|
readonly notificationsSettings;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
|
||||||
|
this.notificationsSettingsTab = container.locator('#notificationsButton');
|
||||||
|
this.notificationsSettings = new NotificationsSettings(container.locator('#notificationSettings'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async openNotificationsTab() {
|
||||||
|
await expect(this.notificationsSettingsTab).toBeVisible();
|
||||||
|
await this.notificationsSettingsTab.click();
|
||||||
|
|
||||||
|
await this.notificationsSettings.toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async closeModal() {
|
||||||
|
await this.container.getByLabel('Close').click();
|
||||||
|
|
||||||
|
await expect(this.container).not.toBeVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {SettingsModal};
|
@ -7,11 +7,19 @@ export default class GlobalHeader {
|
|||||||
readonly container: Locator;
|
readonly container: Locator;
|
||||||
|
|
||||||
readonly productSwitchMenu;
|
readonly productSwitchMenu;
|
||||||
|
readonly recentMentionsButton;
|
||||||
|
readonly settingsButton;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
this.productSwitchMenu = container.getByRole('button', {name: 'Product switch menu'});
|
this.productSwitchMenu = container.getByRole('button', {name: 'Product switch menu'});
|
||||||
|
this.recentMentionsButton = container.getByRole('button', {name: 'Recent mentions'});
|
||||||
|
this.settingsButton = container.getByRole('button', {name: 'Settings'});
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible(name: string) {
|
||||||
|
await expect(this.container.getByRole('heading', {name})).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
async switchProduct(name: string) {
|
async switchProduct(name: string) {
|
||||||
@ -19,8 +27,14 @@ export default class GlobalHeader {
|
|||||||
await this.container.getByRole('link', {name}).click();
|
await this.container.getByRole('link', {name}).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
async toBeVisible(name: string) {
|
async openSettings() {
|
||||||
await expect(this.container.getByRole('heading', {name})).toBeVisible();
|
await expect(this.settingsButton).toBeVisible();
|
||||||
|
await this.settingsButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async openRecentMentions() {
|
||||||
|
await expect(this.recentMentionsButton).toBeVisible();
|
||||||
|
await this.recentMentionsButton.click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import {ChannelsSidebarLeft} from './channels/sidebar_left';
|
|||||||
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
||||||
import {DeletePostModal} from './channels/delete_post_modal';
|
import {DeletePostModal} from './channels/delete_post_modal';
|
||||||
import {FindChannelsModal} from './channels/find_channels_modal';
|
import {FindChannelsModal} from './channels/find_channels_modal';
|
||||||
|
import {SettingsModal} from './channels/settings/settings_modal';
|
||||||
import {Footer} from './footer';
|
import {Footer} from './footer';
|
||||||
import {GlobalHeader} from './global_header';
|
import {GlobalHeader} from './global_header';
|
||||||
import {MainHeader} from './main_header';
|
import {MainHeader} from './main_header';
|
||||||
@ -30,6 +31,7 @@ const components = {
|
|||||||
ChannelsPost,
|
ChannelsPost,
|
||||||
FindChannelsModal,
|
FindChannelsModal,
|
||||||
DeletePostModal,
|
DeletePostModal,
|
||||||
|
SettingsModal,
|
||||||
PostDotMenu,
|
PostDotMenu,
|
||||||
PostMenu,
|
PostMenu,
|
||||||
ThreadFooter,
|
ThreadFooter,
|
||||||
|
@ -18,6 +18,7 @@ export default class ChannelsPage {
|
|||||||
|
|
||||||
readonly findChannelsModal;
|
readonly findChannelsModal;
|
||||||
readonly deletePostModal;
|
readonly deletePostModal;
|
||||||
|
readonly settingsModal;
|
||||||
|
|
||||||
readonly postDotMenu;
|
readonly postDotMenu;
|
||||||
readonly postReminderMenu;
|
readonly postReminderMenu;
|
||||||
@ -37,6 +38,7 @@ export default class ChannelsPage {
|
|||||||
// Modals
|
// Modals
|
||||||
this.findChannelsModal = new components.FindChannelsModal(page.getByRole('dialog', {name: 'Find Channels'}));
|
this.findChannelsModal = new components.FindChannelsModal(page.getByRole('dialog', {name: 'Find Channels'}));
|
||||||
this.deletePostModal = new components.DeletePostModal(page.locator('#deletePostModal'));
|
this.deletePostModal = new components.DeletePostModal(page.locator('#deletePostModal'));
|
||||||
|
this.settingsModal = new components.SettingsModal(page.getByRole('dialog', {name: 'Settings'}));
|
||||||
|
|
||||||
// Menus
|
// Menus
|
||||||
this.postDotMenu = new components.PostDotMenu(page.getByRole('menu', {name: 'Post extra options'}));
|
this.postDotMenu = new components.PostDotMenu(page.getByRole('menu', {name: 'Post extra options'}));
|
||||||
|
@ -0,0 +1,271 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect} from '@playwright/test';
|
||||||
|
|
||||||
|
import {test} from '@e2e-support/test_fixture';
|
||||||
|
import {getRandomId} from '@e2e-support/util';
|
||||||
|
import {createRandomPost} from '@e2e-support/server/post';
|
||||||
|
|
||||||
|
const keywords = [`AB${getRandomId()}`, `CD${getRandomId()}`, `EF${getRandomId()}`, `Highlight me ${getRandomId()}`];
|
||||||
|
|
||||||
|
const highlightWithoutNotificationClass = 'non-notification-highlight';
|
||||||
|
|
||||||
|
test('MM-T5465-1 Should add the keyword when enter, comma or tab is pressed on the textbox', async ({pw, pages}) => {
|
||||||
|
const {user} = await pw.initSetup();
|
||||||
|
|
||||||
|
// # Log in as a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit default channel page
|
||||||
|
const channelPage = new pages.ChannelsPage(page);
|
||||||
|
await channelPage.goto();
|
||||||
|
await channelPage.toBeVisible();
|
||||||
|
|
||||||
|
await channelPage.centerView.postCreate.postMessage('Hello World');
|
||||||
|
|
||||||
|
// # Open settings modal
|
||||||
|
await channelPage.globalHeader.openSettings();
|
||||||
|
await channelPage.settingsModal.toBeVisible();
|
||||||
|
|
||||||
|
// # Open notifications tab
|
||||||
|
await channelPage.settingsModal.openNotificationsTab();
|
||||||
|
|
||||||
|
// # Open keywords that get highlighted section
|
||||||
|
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||||
|
|
||||||
|
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||||
|
|
||||||
|
// # Enter keyword 1
|
||||||
|
await keywordsInput.type(keywords[0]);
|
||||||
|
|
||||||
|
// # Press Comma on the textbox
|
||||||
|
await keywordsInput.press(',');
|
||||||
|
|
||||||
|
// # Enter keyword 2
|
||||||
|
await keywordsInput.type(keywords[1]);
|
||||||
|
|
||||||
|
// # Press Tab on the textbox
|
||||||
|
await keywordsInput.press('Tab');
|
||||||
|
|
||||||
|
// # Enter keyword 3
|
||||||
|
await keywordsInput.type(keywords[2]);
|
||||||
|
|
||||||
|
// # Press Enter on the textbox
|
||||||
|
await keywordsInput.press('Enter');
|
||||||
|
|
||||||
|
// * Verify that the keywords have been added to the collapsed description
|
||||||
|
await expect(channelPage.settingsModal.notificationsSettings.container.getByText(keywords[0])).toBeVisible();
|
||||||
|
await expect(channelPage.settingsModal.notificationsSettings.container.getByText(keywords[1])).toBeVisible();
|
||||||
|
await expect(channelPage.settingsModal.notificationsSettings.container.getByText(keywords[2])).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MM-T5465-2 Should highlight the keywords when a message is sent with the keyword in center', async ({
|
||||||
|
pw,
|
||||||
|
pages,
|
||||||
|
}) => {
|
||||||
|
const {user} = await pw.initSetup();
|
||||||
|
|
||||||
|
// # Log in as a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit default channel page
|
||||||
|
const channelPage = new pages.ChannelsPage(page);
|
||||||
|
await channelPage.goto();
|
||||||
|
await channelPage.toBeVisible();
|
||||||
|
|
||||||
|
// # Open settings modal
|
||||||
|
await channelPage.globalHeader.openSettings();
|
||||||
|
await channelPage.settingsModal.toBeVisible();
|
||||||
|
|
||||||
|
// # Open notifications tab
|
||||||
|
await channelPage.settingsModal.openNotificationsTab();
|
||||||
|
|
||||||
|
// # Open keywords that get highlighted section
|
||||||
|
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||||
|
|
||||||
|
// # Enter the keyword
|
||||||
|
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||||
|
await keywordsInput.type(keywords[3]);
|
||||||
|
await keywordsInput.press('Tab');
|
||||||
|
|
||||||
|
// # Save the keyword
|
||||||
|
await channelPage.settingsModal.notificationsSettings.save();
|
||||||
|
|
||||||
|
// # Close the settings modal
|
||||||
|
await channelPage.settingsModal.closeModal();
|
||||||
|
|
||||||
|
// # Post a message without the keyword
|
||||||
|
const messageWithoutKeyword = 'This message does not contain the keyword';
|
||||||
|
await channelPage.centerView.postCreate.postMessage(messageWithoutKeyword);
|
||||||
|
const lastPostWithoutHighlight = await channelPage.centerView.getLastPost();
|
||||||
|
|
||||||
|
// * Verify that the keywords are not highlighted
|
||||||
|
await expect(lastPostWithoutHighlight.container.getByText(messageWithoutKeyword)).toBeVisible();
|
||||||
|
await expect(lastPostWithoutHighlight.container.getByText(messageWithoutKeyword)).not.toHaveClass(
|
||||||
|
highlightWithoutNotificationClass,
|
||||||
|
);
|
||||||
|
|
||||||
|
// # Post a message with the keyword
|
||||||
|
const messageWithKeyword = `This message contains the keyword ${keywords[3]}`;
|
||||||
|
await channelPage.centerView.postCreate.postMessage(messageWithKeyword);
|
||||||
|
const lastPostWithHighlight = await channelPage.centerView.getLastPost();
|
||||||
|
|
||||||
|
// * Verify that the keywords are highlighted
|
||||||
|
await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible();
|
||||||
|
await expect(lastPostWithHighlight.container.getByText(keywords[3])).toHaveClass(highlightWithoutNotificationClass);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MM-T5465-3 Should highlight the keywords when a message is sent with the keyword in rhs', async ({pw, pages}) => {
|
||||||
|
const {user} = await pw.initSetup();
|
||||||
|
|
||||||
|
// # Log in as a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit default channel page
|
||||||
|
const channelPage = new pages.ChannelsPage(page);
|
||||||
|
await channelPage.goto();
|
||||||
|
await channelPage.toBeVisible();
|
||||||
|
|
||||||
|
// # Open settings modal
|
||||||
|
await channelPage.globalHeader.openSettings();
|
||||||
|
await channelPage.settingsModal.toBeVisible();
|
||||||
|
|
||||||
|
// # Open notifications tab
|
||||||
|
await channelPage.settingsModal.openNotificationsTab();
|
||||||
|
|
||||||
|
// # Open keywords that get highlighted section
|
||||||
|
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||||
|
|
||||||
|
// # Enter the keyword
|
||||||
|
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||||
|
await keywordsInput.type(keywords[3]);
|
||||||
|
await keywordsInput.press('Tab');
|
||||||
|
|
||||||
|
// # Save the keyword
|
||||||
|
await channelPage.settingsModal.notificationsSettings.save();
|
||||||
|
|
||||||
|
// # Close the settings modal
|
||||||
|
await channelPage.settingsModal.closeModal();
|
||||||
|
|
||||||
|
// # Post a message without the keyword
|
||||||
|
const messageWithoutKeyword = 'This message does not contain the keyword';
|
||||||
|
await channelPage.centerView.postCreate.postMessage(messageWithoutKeyword);
|
||||||
|
const lastPostWithoutHighlight = await channelPage.centerView.getLastPost();
|
||||||
|
|
||||||
|
// # Open the message in the RHS
|
||||||
|
await lastPostWithoutHighlight.hover();
|
||||||
|
await lastPostWithoutHighlight.postMenu.toBeVisible();
|
||||||
|
await lastPostWithoutHighlight.postMenu.reply();
|
||||||
|
await channelPage.sidebarRight.toBeVisible();
|
||||||
|
|
||||||
|
// # Post a message with the keyword in the RHS
|
||||||
|
const messageWithKeyword = `This message contains the keyword ${keywords[3]}`;
|
||||||
|
await channelPage.sidebarRight.postCreate.postMessage(messageWithKeyword);
|
||||||
|
|
||||||
|
// * Verify that the keywords are highlighted
|
||||||
|
const lastPostWithHighlightInRHS = await channelPage.sidebarRight.getLastPost();
|
||||||
|
await expect(lastPostWithHighlightInRHS.container.getByText(messageWithKeyword)).toBeVisible();
|
||||||
|
await expect(lastPostWithHighlightInRHS.container.getByText(keywords[3])).toHaveClass(
|
||||||
|
highlightWithoutNotificationClass,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MM-T5465-4 Highlighted keywords should not appear in the Recent Mentions', async ({pw, pages}) => {
|
||||||
|
const {user} = await pw.initSetup();
|
||||||
|
|
||||||
|
// # Log in as a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit default channel page
|
||||||
|
const channelPage = new pages.ChannelsPage(page);
|
||||||
|
await channelPage.goto();
|
||||||
|
await channelPage.toBeVisible();
|
||||||
|
|
||||||
|
// # Open settings modal
|
||||||
|
await channelPage.globalHeader.openSettings();
|
||||||
|
await channelPage.settingsModal.toBeVisible();
|
||||||
|
|
||||||
|
// # Open notifications tab
|
||||||
|
await channelPage.settingsModal.openNotificationsTab();
|
||||||
|
|
||||||
|
// # Open keywords that get highlighted section
|
||||||
|
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||||
|
|
||||||
|
// # Enter the keyword
|
||||||
|
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||||
|
await keywordsInput.type(keywords[0]);
|
||||||
|
await keywordsInput.press('Tab');
|
||||||
|
|
||||||
|
// # Save the keyword
|
||||||
|
await channelPage.settingsModal.notificationsSettings.save();
|
||||||
|
|
||||||
|
// # Close the settings modal
|
||||||
|
await channelPage.settingsModal.closeModal();
|
||||||
|
|
||||||
|
// # Open the recent mentions
|
||||||
|
await channelPage.globalHeader.openRecentMentions();
|
||||||
|
|
||||||
|
// * Verify recent mentions is empty
|
||||||
|
await channelPage.sidebarRight.toBeVisible();
|
||||||
|
await expect(channelPage.sidebarRight.container.getByText('No mentions yet')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MM-T5465-5 Should highlight keywords in message sent from another user', async ({pw, pages}) => {
|
||||||
|
const {adminClient, team, adminUser, user} = await pw.initSetup();
|
||||||
|
|
||||||
|
if (!adminUser) {
|
||||||
|
throw new Error('Failed to create admin user');
|
||||||
|
}
|
||||||
|
|
||||||
|
// # Get the default channel of the team for getting the channel id
|
||||||
|
const channel = await adminClient.getChannelByName(team.id, 'town-square');
|
||||||
|
|
||||||
|
const highlightKeyword = keywords[0];
|
||||||
|
const messageWithKeyword = `This recieved message contains the ${highlightKeyword} keyword `;
|
||||||
|
|
||||||
|
// # Create a post containing the keyword in the channel by admin
|
||||||
|
await adminClient.createPost(
|
||||||
|
createRandomPost({
|
||||||
|
message: messageWithKeyword,
|
||||||
|
channel_id: channel.id,
|
||||||
|
user_id: adminUser.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// # Now log in as a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit default channel page
|
||||||
|
const channelPage = new pages.ChannelsPage(page);
|
||||||
|
await channelPage.goto();
|
||||||
|
await channelPage.toBeVisible();
|
||||||
|
|
||||||
|
// # Open settings modal
|
||||||
|
await channelPage.globalHeader.openSettings();
|
||||||
|
await channelPage.settingsModal.toBeVisible();
|
||||||
|
|
||||||
|
// # Open notifications tab
|
||||||
|
await channelPage.settingsModal.openNotificationsTab();
|
||||||
|
|
||||||
|
// # Open keywords that get highlighted section
|
||||||
|
await channelPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||||
|
|
||||||
|
// # Enter the keyword
|
||||||
|
const keywordsInput = await channelPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||||
|
await keywordsInput.type(keywords[0]);
|
||||||
|
await keywordsInput.press('Tab');
|
||||||
|
|
||||||
|
// # Save the keyword
|
||||||
|
await channelPage.settingsModal.notificationsSettings.save();
|
||||||
|
|
||||||
|
// # Close the settings modal
|
||||||
|
await channelPage.settingsModal.closeModal();
|
||||||
|
|
||||||
|
// * Verify that the keywords are highlighted in the last message recieved
|
||||||
|
const lastPostWithHighlight = await channelPage.centerView.getLastPost();
|
||||||
|
await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible();
|
||||||
|
await expect(lastPostWithHighlight.container.getByText(highlightKeyword)).toHaveClass(
|
||||||
|
highlightWithoutNotificationClass,
|
||||||
|
);
|
||||||
|
});
|
@ -13,17 +13,18 @@ import (
|
|||||||
type MattermostFeature string
|
type MattermostFeature string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PaidFeatureGuestAccounts = MattermostFeature("mattermost.feature.guest_accounts")
|
PaidFeatureGuestAccounts = MattermostFeature("mattermost.feature.guest_accounts")
|
||||||
PaidFeatureCustomUsergroups = MattermostFeature("mattermost.feature.custom_user_groups")
|
PaidFeatureCustomUsergroups = MattermostFeature("mattermost.feature.custom_user_groups")
|
||||||
PaidFeatureCreateMultipleTeams = MattermostFeature("mattermost.feature.create_multiple_teams")
|
PaidFeatureCreateMultipleTeams = MattermostFeature("mattermost.feature.create_multiple_teams")
|
||||||
PaidFeatureStartcall = MattermostFeature("mattermost.feature.start_call")
|
PaidFeatureStartcall = MattermostFeature("mattermost.feature.start_call")
|
||||||
PaidFeaturePlaybooksRetrospective = MattermostFeature("mattermost.feature.playbooks_retro")
|
PaidFeaturePlaybooksRetrospective = MattermostFeature("mattermost.feature.playbooks_retro")
|
||||||
PaidFeatureUnlimitedMessages = MattermostFeature("mattermost.feature.unlimited_messages")
|
PaidFeatureUnlimitedMessages = MattermostFeature("mattermost.feature.unlimited_messages")
|
||||||
PaidFeatureUnlimitedFileStorage = MattermostFeature("mattermost.feature.unlimited_file_storage")
|
PaidFeatureUnlimitedFileStorage = MattermostFeature("mattermost.feature.unlimited_file_storage")
|
||||||
PaidFeatureAllProfessionalfeatures = MattermostFeature("mattermost.feature.all_professional")
|
PaidFeatureAllProfessionalfeatures = MattermostFeature("mattermost.feature.all_professional")
|
||||||
PaidFeatureAllEnterprisefeatures = MattermostFeature("mattermost.feature.all_enterprise")
|
PaidFeatureAllEnterprisefeatures = MattermostFeature("mattermost.feature.all_enterprise")
|
||||||
UpgradeDowngradedWorkspace = MattermostFeature("mattermost.feature.upgrade_downgraded_workspace")
|
UpgradeDowngradedWorkspace = MattermostFeature("mattermost.feature.upgrade_downgraded_workspace")
|
||||||
PluginFeature = MattermostFeature("mattermost.feature.plugin")
|
PluginFeature = MattermostFeature("mattermost.feature.plugin")
|
||||||
|
PaidFeatureHighlightWithoutNotification = MattermostFeature("mattermost.feature.highlight_without_notification")
|
||||||
)
|
)
|
||||||
|
|
||||||
var validSKUs = map[string]struct{}{
|
var validSKUs = map[string]struct{}{
|
||||||
@ -33,16 +34,17 @@ var validSKUs = map[string]struct{}{
|
|||||||
|
|
||||||
// These are the features a non admin would typically ping an admin about
|
// These are the features a non admin would typically ping an admin about
|
||||||
var paidFeatures = map[MattermostFeature]struct{}{
|
var paidFeatures = map[MattermostFeature]struct{}{
|
||||||
PaidFeatureGuestAccounts: {},
|
PaidFeatureGuestAccounts: {},
|
||||||
PaidFeatureCustomUsergroups: {},
|
PaidFeatureCustomUsergroups: {},
|
||||||
PaidFeatureCreateMultipleTeams: {},
|
PaidFeatureCreateMultipleTeams: {},
|
||||||
PaidFeatureStartcall: {},
|
PaidFeatureStartcall: {},
|
||||||
PaidFeaturePlaybooksRetrospective: {},
|
PaidFeaturePlaybooksRetrospective: {},
|
||||||
PaidFeatureUnlimitedMessages: {},
|
PaidFeatureUnlimitedMessages: {},
|
||||||
PaidFeatureUnlimitedFileStorage: {},
|
PaidFeatureUnlimitedFileStorage: {},
|
||||||
PaidFeatureAllProfessionalfeatures: {},
|
PaidFeatureAllProfessionalfeatures: {},
|
||||||
PaidFeatureAllEnterprisefeatures: {},
|
PaidFeatureAllEnterprisefeatures: {},
|
||||||
UpgradeDowngradedWorkspace: {},
|
UpgradeDowngradedWorkspace: {},
|
||||||
|
PaidFeatureHighlightWithoutNotification: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotifyAdminToUpgradeRequest struct {
|
type NotifyAdminToUpgradeRequest struct {
|
||||||
|
@ -36,6 +36,7 @@ const (
|
|||||||
ChannelMentionsNotifyProp = "channel"
|
ChannelMentionsNotifyProp = "channel"
|
||||||
CommentsNotifyProp = "comments"
|
CommentsNotifyProp = "comments"
|
||||||
MentionKeysNotifyProp = "mention_keys"
|
MentionKeysNotifyProp = "mention_keys"
|
||||||
|
HighlightsNotifyProp = "highlight_keys"
|
||||||
CommentsNotifyNever = "never"
|
CommentsNotifyNever = "never"
|
||||||
CommentsNotifyRoot = "root"
|
CommentsNotifyRoot = "root"
|
||||||
CommentsNotifyAny = "any"
|
CommentsNotifyAny = "any"
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`components/SettingItemMin should match snapshot 1`] = `
|
||||||
|
<div
|
||||||
|
className="section-min"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
className="section-min__title"
|
||||||
|
id="sectionTitle"
|
||||||
|
>
|
||||||
|
title
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded={false}
|
||||||
|
aria-labelledby="sectionTitle sectionEdit"
|
||||||
|
className="color--link style--none section-min__edit"
|
||||||
|
id="sectionEdit"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<EditIcon />
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="Edit"
|
||||||
|
id="setting_item_min.edit"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="section-min__describe"
|
||||||
|
id="sectionDesc"
|
||||||
|
>
|
||||||
|
describe
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`components/SettingItemMin should match snapshot, on disableOpen to true 1`] = `
|
||||||
|
<div
|
||||||
|
className="section-min"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
className="section-min__title"
|
||||||
|
id="sectionTitle"
|
||||||
|
>
|
||||||
|
title
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded={false}
|
||||||
|
aria-labelledby="sectionTitle sectionEdit"
|
||||||
|
className="color--link style--none section-min__edit"
|
||||||
|
id="sectionEdit"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<EditIcon />
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="Edit"
|
||||||
|
id="setting_item_min.edit"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="section-min__describe"
|
||||||
|
id="sectionDesc"
|
||||||
|
>
|
||||||
|
describe
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -18,7 +18,6 @@ exports[`components/TextBox should match snapshot with additional, optional prop
|
|||||||
"hideUtilities": true,
|
"hideUtilities": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="some test text"
|
message="some test text"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -147,7 +146,6 @@ exports[`components/TextBox should match snapshot with required props 1`] = `
|
|||||||
"hideUtilities": true,
|
"hideUtilities": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="some test text"
|
message="some test text"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -271,7 +269,6 @@ exports[`components/TextBox should throw error when new property is too long 1`]
|
|||||||
"hideUtilities": true,
|
"hideUtilities": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="some test text that exceeds char limit"
|
message="some test text that exceeds char limit"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -395,7 +392,6 @@ exports[`components/TextBox should throw error when value is too long 1`] = `
|
|||||||
"hideUtilities": true,
|
"hideUtilities": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="some test text that exceeds char limit"
|
message="some test text that exceeds char limit"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,11 +2,6 @@
|
|||||||
|
|
||||||
exports[`components/ToggleModalButton component should match snapshot 1`] = `
|
exports[`components/ToggleModalButton component should match snapshot 1`] = `
|
||||||
<ToggleModalButton
|
<ToggleModalButton
|
||||||
actions={
|
|
||||||
Object {
|
|
||||||
"openModal": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ariaLabel="Delete Channel"
|
ariaLabel="Delete Channel"
|
||||||
dialogType={[Function]}
|
dialogType={[Function]}
|
||||||
id="channelDelete"
|
id="channelDelete"
|
@ -62,6 +62,7 @@ exports[`components/UserList should match default snapshot when there are users
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -122,6 +123,7 @@ exports[`components/UserList should match default snapshot when there are users
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -111,6 +111,7 @@ exports[`components/admin_console/add_users_to_team_modal/AddUsersToTeamModal sh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -151,6 +152,7 @@ exports[`components/admin_console/add_users_to_team_modal/AddUsersToTeamModal sh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -297,6 +299,7 @@ exports[`components/admin_console/add_users_to_team_modal/AddUsersToTeamModal sh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -337,6 +340,7 @@ exports[`components/admin_console/add_users_to_team_modal/AddUsersToTeamModal sh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -59,6 +59,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -106,6 +107,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -153,6 +155,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -200,6 +203,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -247,6 +251,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -294,6 +299,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -341,6 +347,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -388,6 +395,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -435,6 +443,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -482,6 +491,7 @@ exports[`admin_console/team_channel_settings/group/GroupList should match snapsh
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -26,6 +26,7 @@ describe('components/admin_console/reset_password_modal/reset_password_modal.tsx
|
|||||||
first_name: 'true',
|
first_name: 'true',
|
||||||
mark_unread: 'all',
|
mark_unread: 'all',
|
||||||
mention_keys: '',
|
mention_keys: '',
|
||||||
|
highlight_keys: '',
|
||||||
push: 'default',
|
push: 'default',
|
||||||
push_status: 'ooo',
|
push_status: 'ooo',
|
||||||
};
|
};
|
||||||
|
@ -114,6 +114,7 @@ exports[`admin_console/add_users_to_role_modal search should not include bot use
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -359,6 +360,7 @@ exports[`admin_console/add_users_to_role_modal should have single passed value 1
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -503,6 +505,7 @@ exports[`admin_console/add_users_to_role_modal should include additional user 1`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -543,6 +546,7 @@ exports[`admin_console/add_users_to_role_modal should include additional user 1`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -687,6 +691,7 @@ exports[`admin_console/add_users_to_role_modal should include additional user 2`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -727,6 +732,7 @@ exports[`admin_console/add_users_to_role_modal should include additional user 2`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -871,6 +877,7 @@ exports[`admin_console/add_users_to_role_modal should not include bot user 1`] =
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
exports[`admin_console/system_role_users should match snapshot 1`] = `
|
exports[`admin_console/system_role_users should match snapshot 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -32,6 +32,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -72,6 +73,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -119,7 +121,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
defaultMessage="Add People"
|
defaultMessage="Add People"
|
||||||
id="admin.permissions.system_role_users.add_people"
|
id="admin.permissions.system_role_users.add_people"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="SystemRoleUsers"
|
id="SystemRoleUsers"
|
||||||
@ -191,6 +193,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -236,6 +239,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -283,6 +287,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -328,6 +333,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -359,7 +365,7 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
|
|||||||
exports[`admin_console/system_role_users should match snapshot with readOnly true 1`] = `
|
exports[`admin_console/system_role_users should match snapshot with readOnly true 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -388,6 +394,7 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -428,6 +435,7 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -475,7 +483,7 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
|
|||||||
defaultMessage="Add People"
|
defaultMessage="Add People"
|
||||||
id="admin.permissions.system_role_users.add_people"
|
id="admin.permissions.system_role_users.add_people"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="SystemRoleUsers"
|
id="SystemRoleUsers"
|
||||||
@ -547,6 +555,7 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -592,6 +601,7 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -639,6 +649,7 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -684,6 +695,7 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
exports[`admin_console/team_channel_settings/channel/ChannelGroups should match snapshot 1`] = `
|
exports[`admin_console/team_channel_settings/channel/ChannelGroups should match snapshot 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -42,7 +42,7 @@ exports[`admin_console/team_channel_settings/channel/ChannelGroups should match
|
|||||||
defaultMessage="Add Group"
|
defaultMessage="Add Group"
|
||||||
id="admin.channel_settings.channel_details.add_group"
|
id="admin.channel_settings.channel_details.add_group"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="channel_groups"
|
id="channel_groups"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
exports[`admin_console/team_channel_settings/channel/ChannelMembers should match snapshot 1`] = `
|
exports[`admin_console/team_channel_settings/channel/ChannelMembers should match snapshot 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -47,7 +47,7 @@ exports[`admin_console/team_channel_settings/channel/ChannelMembers should match
|
|||||||
defaultMessage="Add Members"
|
defaultMessage="Add Members"
|
||||||
id="admin.team_settings.team_details.add_members"
|
id="admin.team_settings.team_details.add_members"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="channelMembers"
|
id="channelMembers"
|
||||||
@ -215,6 +215,7 @@ exports[`admin_console/team_channel_settings/channel/ChannelMembers should match
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -253,6 +254,7 @@ exports[`admin_console/team_channel_settings/channel/ChannelMembers should match
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -291,6 +293,7 @@ exports[`admin_console/team_channel_settings/channel/ChannelMembers should match
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -314,7 +317,7 @@ exports[`admin_console/team_channel_settings/channel/ChannelMembers should match
|
|||||||
exports[`admin_console/team_channel_settings/channel/ChannelMembers should match snapshot loading no users 1`] = `
|
exports[`admin_console/team_channel_settings/channel/ChannelMembers should match snapshot loading no users 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -358,7 +361,7 @@ exports[`admin_console/team_channel_settings/channel/ChannelMembers should match
|
|||||||
defaultMessage="Add Members"
|
defaultMessage="Add Members"
|
||||||
id="admin.team_settings.team_details.add_members"
|
id="admin.team_settings.team_details.add_members"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="channelMembers"
|
id="channelMembers"
|
||||||
|
@ -17,7 +17,7 @@ exports[`admin_console/team_channel_settings/group/GroupRow should match snapsho
|
|||||||
<span
|
<span
|
||||||
className="group-description row-content"
|
className="group-description row-content"
|
||||||
>
|
>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="color--link"
|
className="color--link"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -41,7 +41,7 @@ exports[`admin_console/team_channel_settings/group/GroupRow should match snapsho
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
className="group-description row-content roles"
|
className="group-description row-content roles"
|
||||||
|
@ -60,6 +60,7 @@ exports[`components/admin_console/team_channel_settings/group/UsersToRemoveRole
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -153,6 +154,7 @@ exports[`components/admin_console/team_channel_settings/group/UsersToRemoveRole
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -246,6 +248,7 @@ exports[`components/admin_console/team_channel_settings/group/UsersToRemoveRole
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -339,6 +342,7 @@ exports[`components/admin_console/team_channel_settings/group/UsersToRemoveRole
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -423,6 +427,7 @@ exports[`components/admin_console/team_channel_settings/group/UsersToRemoveRole
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -507,6 +512,7 @@ exports[`components/admin_console/team_channel_settings/group/UsersToRemoveRole
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
exports[`admin_console/team_channel_settings/team/TeamGroups should match snapshot 1`] = `
|
exports[`admin_console/team_channel_settings/team/TeamGroups should match snapshot 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -61,7 +61,7 @@ exports[`admin_console/team_channel_settings/team/TeamGroups should match snapsh
|
|||||||
defaultMessage="Add Group"
|
defaultMessage="Add Group"
|
||||||
id="admin.team_settings.team_details.add_group"
|
id="admin.team_settings.team_details.add_group"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="team_groups"
|
id="team_groups"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
exports[`admin_console/team_channel_settings/team/TeamMembers should match snapshot 1`] = `
|
exports[`admin_console/team_channel_settings/team/TeamMembers should match snapshot 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -46,7 +46,7 @@ exports[`admin_console/team_channel_settings/team/TeamMembers should match snaps
|
|||||||
defaultMessage="Add Members"
|
defaultMessage="Add Members"
|
||||||
id="admin.team_settings.team_details.add_members"
|
id="admin.team_settings.team_details.add_members"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="teamMembers"
|
id="teamMembers"
|
||||||
@ -187,6 +187,7 @@ exports[`admin_console/team_channel_settings/team/TeamMembers should match snaps
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -225,6 +226,7 @@ exports[`admin_console/team_channel_settings/team/TeamMembers should match snaps
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -263,6 +265,7 @@ exports[`admin_console/team_channel_settings/team/TeamMembers should match snaps
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -286,7 +289,7 @@ exports[`admin_console/team_channel_settings/team/TeamMembers should match snaps
|
|||||||
exports[`admin_console/team_channel_settings/team/TeamMembers should match snapshot loading no users 1`] = `
|
exports[`admin_console/team_channel_settings/team/TeamMembers should match snapshot loading no users 1`] = `
|
||||||
<AdminPanel
|
<AdminPanel
|
||||||
button={
|
button={
|
||||||
<Memo(Connect(ToggleModalButton))
|
<ToggleModalButton
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -329,7 +332,7 @@ exports[`admin_console/team_channel_settings/team/TeamMembers should match snaps
|
|||||||
defaultMessage="Add Members"
|
defaultMessage="Add Members"
|
||||||
id="admin.team_settings.team_details.add_members"
|
id="admin.team_settings.team_details.add_members"
|
||||||
/>
|
/>
|
||||||
</Memo(Connect(ToggleModalButton))>
|
</ToggleModalButton>
|
||||||
}
|
}
|
||||||
className=""
|
className=""
|
||||||
id="teamMembers"
|
id="teamMembers"
|
||||||
|
@ -84,6 +84,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -128,6 +129,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -187,6 +189,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -234,6 +237,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -278,6 +282,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -337,6 +342,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -453,6 +459,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -505,6 +512,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -556,6 +564,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -603,6 +612,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -647,6 +657,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -706,6 +717,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -753,6 +765,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -797,6 +810,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -856,6 +870,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -972,6 +987,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1016,6 +1032,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1075,6 +1092,7 @@ exports[`components/admin_console/user_grid/UserGrid should match snapshot with
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -137,6 +137,7 @@ exports[`components/ChannelHeaderDropdown should match snapshot with no plugin i
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -213,6 +214,7 @@ exports[`components/ChannelHeaderDropdown should match snapshot with no plugin i
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -757,6 +759,7 @@ exports[`components/ChannelHeaderDropdown should match snapshot with no plugin i
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -966,6 +969,7 @@ exports[`components/ChannelHeaderDropdown should match snapshot with plugins 1`]
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1042,6 +1046,7 @@ exports[`components/ChannelHeaderDropdown should match snapshot with plugins 1`]
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1586,6 +1591,7 @@ exports[`components/ChannelHeaderDropdown should match snapshot with plugins 1`]
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`components/channel_notifications_modal/CollapseView should match snapshot, DESKTOP on collapsed view 1`] = `
|
exports[`components/channel_notifications_modal/CollapseView should match snapshot, DESKTOP on collapsed view 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Describe
|
<Describe
|
||||||
globalNotifyLevel="default"
|
globalNotifyLevel="default"
|
||||||
@ -21,7 +21,7 @@ exports[`components/channel_notifications_modal/CollapseView should match snapsh
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/channel_notifications_modal/CollapseView should match snapshot, MARK_UNREAD on collapsed view 1`] = `
|
exports[`components/channel_notifications_modal/CollapseView should match snapshot, MARK_UNREAD on collapsed view 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Describe
|
<Describe
|
||||||
globalNotifyLevel="default"
|
globalNotifyLevel="default"
|
||||||
@ -41,7 +41,7 @@ exports[`components/channel_notifications_modal/CollapseView should match snapsh
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/channel_notifications_modal/CollapseView should match snapshot, PUSH on collapsed view 1`] = `
|
exports[`components/channel_notifications_modal/CollapseView should match snapshot, PUSH on collapsed view 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Describe
|
<Describe
|
||||||
globalNotifyLevel="default"
|
globalNotifyLevel="default"
|
||||||
|
@ -35,8 +35,8 @@ import './feature_restricted_modal.scss';
|
|||||||
type FeatureRestrictedModalProps = {
|
type FeatureRestrictedModalProps = {
|
||||||
titleAdminPreTrial: string;
|
titleAdminPreTrial: string;
|
||||||
messageAdminPreTrial: string;
|
messageAdminPreTrial: string;
|
||||||
titleAdminPostTrial: string;
|
titleAdminPostTrial?: string;
|
||||||
messageAdminPostTrial: string;
|
messageAdminPostTrial?: string;
|
||||||
titleEndUser?: string;
|
titleEndUser?: string;
|
||||||
messageEndUser?: string;
|
messageEndUser?: string;
|
||||||
customSecondaryButton?: {msg: string; action: () => void};
|
customSecondaryButton?: {msg: string; action: () => void};
|
||||||
|
@ -48,6 +48,7 @@ exports[`components/integrations/InstalledOutgoingWebhooks should match snapshot
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -155,6 +156,7 @@ exports[`components/integrations/InstalledOutgoingWebhooks should match snapshot
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -24,7 +24,7 @@ function makeGetChannelNamesMap() {
|
|||||||
return createSelector(
|
return createSelector(
|
||||||
'makeGetChannelNamesMap',
|
'makeGetChannelNamesMap',
|
||||||
getChannelNameToDisplayNameMap,
|
getChannelNameToDisplayNameMap,
|
||||||
(state: GlobalState, props: OwnProps) => props && props.channelNamesMap,
|
(_: GlobalState, props: OwnProps) => props && props.channelNamesMap,
|
||||||
(channelNamesMap, channelMentions) => {
|
(channelNamesMap, channelMentions) => {
|
||||||
if (channelMentions) {
|
if (channelMentions) {
|
||||||
return Object.assign({}, channelMentions, channelNamesMap);
|
return Object.assign({}, channelMentions, channelNamesMap);
|
||||||
@ -63,6 +63,7 @@ function makeMapStateToProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const connector = connect(makeMapStateToProps);
|
const connector = connect(makeMapStateToProps);
|
||||||
|
|
||||||
export type PropsFromRedux = ConnectedProps<typeof connector>;
|
export type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||||
|
|
||||||
export default connector(Markdown);
|
export default connector(Markdown);
|
||||||
|
@ -5,6 +5,8 @@ import React from 'react';
|
|||||||
|
|
||||||
import type {PostImage, PostType} from '@mattermost/types/posts';
|
import type {PostImage, PostType} from '@mattermost/types/posts';
|
||||||
|
|
||||||
|
import type {HighlightWithoutNotificationKey} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import PostEditedIndicator from 'components/post_view/post_edited_indicator';
|
import PostEditedIndicator from 'components/post_view/post_edited_indicator';
|
||||||
|
|
||||||
import type EmojiMap from 'utils/emoji_map';
|
import type EmojiMap from 'utils/emoji_map';
|
||||||
@ -53,6 +55,7 @@ export type OwnProps = {
|
|||||||
* An array of words that can be used to mention a user
|
* An array of words that can be used to mention a user
|
||||||
*/
|
*/
|
||||||
mentionKeys?: MentionKey[];
|
mentionKeys?: MentionKey[];
|
||||||
|
highlightKeys?: HighlightWithoutNotificationKey[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any extra props that should be passed into the image component
|
* Any extra props that should be passed into the image component
|
||||||
@ -92,6 +95,7 @@ function Markdown({
|
|||||||
message = '',
|
message = '',
|
||||||
channelNamesMap,
|
channelNamesMap,
|
||||||
mentionKeys,
|
mentionKeys,
|
||||||
|
highlightKeys,
|
||||||
imageProps,
|
imageProps,
|
||||||
channelId,
|
channelId,
|
||||||
hasPluginTooltips,
|
hasPluginTooltips,
|
||||||
@ -123,6 +127,7 @@ function Markdown({
|
|||||||
autolinkedUrlSchemes,
|
autolinkedUrlSchemes,
|
||||||
siteURL,
|
siteURL,
|
||||||
mentionKeys,
|
mentionKeys,
|
||||||
|
highlightKeys,
|
||||||
atMentions: true,
|
atMentions: true,
|
||||||
channelNamesMap,
|
channelNamesMap,
|
||||||
proxyImages: hasImageProxy && proxyImages,
|
proxyImages: hasImageProxy && proxyImages,
|
||||||
|
@ -95,6 +95,7 @@ exports[`components/MoreDirectChannels should exclude deleted users if there is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -133,6 +134,7 @@ exports[`components/MoreDirectChannels should exclude deleted users if there is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -171,6 +173,7 @@ exports[`components/MoreDirectChannels should exclude deleted users if there is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -209,6 +212,7 @@ exports[`components/MoreDirectChannels should exclude deleted users if there is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -247,6 +251,7 @@ exports[`components/MoreDirectChannels should exclude deleted users if there is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -380,6 +385,7 @@ exports[`components/MoreDirectChannels should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -418,6 +424,7 @@ exports[`components/MoreDirectChannels should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -456,6 +463,7 @@ exports[`components/MoreDirectChannels should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -499,6 +507,7 @@ exports[`components/MoreDirectChannels should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -539,6 +548,7 @@ exports[`components/MoreDirectChannels should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {connect} from 'react-redux';
|
import {type ConnectedProps, connect} from 'react-redux';
|
||||||
|
|
||||||
import type {Channel} from '@mattermost/types/channels';
|
import type {Channel} from '@mattermost/types/channels';
|
||||||
import type {Post} from '@mattermost/types/posts';
|
import type {Post} from '@mattermost/types/posts';
|
||||||
|
|
||||||
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
||||||
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
import {getSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud';
|
||||||
|
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {
|
import {
|
||||||
getMyGroupMentionKeysForChannel,
|
getMyGroupMentionKeysForChannel,
|
||||||
getMyGroupMentionKeys,
|
getMyGroupMentionKeys,
|
||||||
@ -16,15 +17,16 @@ import {
|
|||||||
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
|
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone';
|
import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone';
|
||||||
import {getCurrentUserMentionKeys} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUserMentionKeys, getHighlightWithoutNotificationKeys} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import {canManageMembers} from 'utils/channel_utils';
|
import {canManageMembers} from 'utils/channel_utils';
|
||||||
import {Preferences} from 'utils/constants';
|
import {Preferences} from 'utils/constants';
|
||||||
|
import {isEnterpriseOrCloudOrSKUStarterFree} from 'utils/license_utils';
|
||||||
import type {MentionKey} from 'utils/text_formatting';
|
import type {MentionKey} from 'utils/text_formatting';
|
||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
import type {GlobalState} from 'types/store';
|
||||||
|
|
||||||
import PostMarkdown from './post_markdown';
|
import PostMarkdown, {type OwnProps} from './post_markdown';
|
||||||
|
|
||||||
export function makeGetMentionKeysForPost(): (
|
export function makeGetMentionKeysForPost(): (
|
||||||
state: GlobalState,
|
state: GlobalState,
|
||||||
@ -54,18 +56,19 @@ export function makeGetMentionKeysForPost(): (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type OwnProps = {
|
|
||||||
channelId: string;
|
|
||||||
mentionKeys: MentionKey[];
|
|
||||||
post?: Post;
|
|
||||||
};
|
|
||||||
|
|
||||||
function makeMapStateToProps() {
|
function makeMapStateToProps() {
|
||||||
const getMentionKeysForPost = makeGetMentionKeysForPost();
|
const getMentionKeysForPost = makeGetMentionKeysForPost();
|
||||||
|
|
||||||
return (state: GlobalState, ownProps: OwnProps) => {
|
return (state: GlobalState, ownProps: OwnProps) => {
|
||||||
const channel = getChannel(state, ownProps.channelId);
|
const channel = getChannel(state, ownProps.channelId);
|
||||||
const currentTeam = getCurrentTeam(state) || {};
|
const currentTeam = getCurrentTeam(state) || {};
|
||||||
|
|
||||||
|
const license = getLicense(state);
|
||||||
|
const subscriptionProduct = getSubscriptionProduct(state);
|
||||||
|
|
||||||
|
const config = getConfig(state);
|
||||||
|
const isEnterpriseReady = config.BuildEnterpriseReady === 'true';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channel,
|
channel,
|
||||||
currentTeam,
|
currentTeam,
|
||||||
@ -73,11 +76,18 @@ function makeMapStateToProps() {
|
|||||||
hasPluginTooltips: Boolean(state.plugins.components.LinkTooltip),
|
hasPluginTooltips: Boolean(state.plugins.components.LinkTooltip),
|
||||||
isUserCanManageMembers: channel && canManageMembers(state, channel),
|
isUserCanManageMembers: channel && canManageMembers(state, channel),
|
||||||
mentionKeys: getMentionKeysForPost(state, ownProps.post, channel),
|
mentionKeys: getMentionKeysForPost(state, ownProps.post, channel),
|
||||||
|
highlightKeys: getHighlightWithoutNotificationKeys(state),
|
||||||
isMilitaryTime: getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false),
|
isMilitaryTime: getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false),
|
||||||
timezone: getCurrentTimezone(state),
|
timezone: getCurrentTimezone(state),
|
||||||
hideGuestTags: getConfig(state).HideGuestTags === 'true',
|
hideGuestTags: getConfig(state).HideGuestTags === 'true',
|
||||||
|
isEnterpriseOrCloudOrSKUStarterFree: isEnterpriseOrCloudOrSKUStarterFree(license, subscriptionProduct, isEnterpriseReady),
|
||||||
|
isEnterpriseReady,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(makeMapStateToProps)(PostMarkdown);
|
const connector = connect(makeMapStateToProps);
|
||||||
|
|
||||||
|
export type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||||
|
|
||||||
|
export default connector(PostMarkdown);
|
||||||
|
@ -10,11 +10,14 @@ import {Posts} from 'mattermost-redux/constants';
|
|||||||
import {renderWithContext, screen} from 'tests/react_testing_utils';
|
import {renderWithContext, screen} from 'tests/react_testing_utils';
|
||||||
import {TestHelper} from 'utils/test_helper';
|
import {TestHelper} from 'utils/test_helper';
|
||||||
|
|
||||||
|
import type {PluginComponent} from 'types/store/plugins';
|
||||||
|
|
||||||
import PostMarkdown from './post_markdown';
|
import PostMarkdown from './post_markdown';
|
||||||
|
|
||||||
describe('components/PostMarkdown', () => {
|
describe('components/PostMarkdown', () => {
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
imageProps: {},
|
imageProps: {} as Record<string, unknown>,
|
||||||
|
pluginHooks: [],
|
||||||
message: 'message',
|
message: 'message',
|
||||||
post: TestHelper.getPostMock(),
|
post: TestHelper.getPostMock(),
|
||||||
mentionKeys: [{key: 'a'}, {key: 'b'}, {key: 'c'}],
|
mentionKeys: [{key: 'a'}, {key: 'b'}, {key: 'c'}],
|
||||||
@ -22,6 +25,14 @@ describe('components/PostMarkdown', () => {
|
|||||||
channel: TestHelper.getChannelMock(),
|
channel: TestHelper.getChannelMock(),
|
||||||
currentTeam: TestHelper.getTeamMock(),
|
currentTeam: TestHelper.getTeamMock(),
|
||||||
hideGuestTags: false,
|
hideGuestTags: false,
|
||||||
|
isMilitaryTime: false,
|
||||||
|
timezone: '',
|
||||||
|
highlightKeys: [],
|
||||||
|
hasPluginTooltips: false,
|
||||||
|
isUserCanManageMembers: false,
|
||||||
|
isEnterpriseOrCloudOrSKUStarterFree: true,
|
||||||
|
isEnterpriseReady: false,
|
||||||
|
dispatch: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = {entities: {
|
const state = {entities: {
|
||||||
@ -224,7 +235,7 @@ describe('components/PostMarkdown', () => {
|
|||||||
return updatedMessage + '!';
|
return updatedMessage + '!';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
] as PluginComponent[],
|
||||||
};
|
};
|
||||||
renderWithContext(<PostMarkdown {...props}/>, state);
|
renderWithContext(<PostMarkdown {...props}/>, state);
|
||||||
expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument();
|
expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument();
|
||||||
@ -258,7 +269,7 @@ describe('components/PostMarkdown', () => {
|
|||||||
return post.message + '!';
|
return post.message + '!';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
] as PluginComponent[],
|
||||||
};
|
};
|
||||||
renderWithContext(<PostMarkdown {...props}/>, state);
|
renderWithContext(<PostMarkdown {...props}/>, state);
|
||||||
expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument();
|
expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument();
|
||||||
|
@ -4,65 +4,45 @@
|
|||||||
import memoize from 'memoize-one';
|
import memoize from 'memoize-one';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type {Channel} from '@mattermost/types/channels';
|
|
||||||
import type {Post} from '@mattermost/types/posts';
|
import type {Post} from '@mattermost/types/posts';
|
||||||
import type {Team} from '@mattermost/types/teams';
|
|
||||||
|
|
||||||
import {Posts} from 'mattermost-redux/constants';
|
import {Posts} from 'mattermost-redux/constants';
|
||||||
|
|
||||||
import Markdown from 'components/markdown';
|
import Markdown from 'components/markdown';
|
||||||
|
|
||||||
import type {MentionKey, TextFormattingOptions} from 'utils/text_formatting';
|
import type {TextFormattingOptions} from 'utils/text_formatting';
|
||||||
|
|
||||||
import {renderReminderSystemBotMessage, renderSystemMessage} from './system_message_helpers';
|
import {renderReminderSystemBotMessage, renderSystemMessage} from './system_message_helpers';
|
||||||
|
|
||||||
type Props = {
|
import {type PropsFromRedux} from './index';
|
||||||
|
|
||||||
/*
|
export type OwnProps = {
|
||||||
|
|
||||||
|
/**
|
||||||
* Any extra props that should be passed into the image component
|
* Any extra props that should be passed into the image component
|
||||||
*/
|
*/
|
||||||
imageProps?: Record<string, any>;
|
imageProps?: Record<string, unknown>;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* The post text to be rendered
|
* The post text to be rendered
|
||||||
*/
|
*/
|
||||||
message: string;
|
message: string;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* The optional post for which this message is being rendered
|
* The optional post for which this message is being rendered
|
||||||
*/
|
*/
|
||||||
post?: Post;
|
post?: Post;
|
||||||
|
channelId: string;
|
||||||
/*
|
|
||||||
* The id of the channel that this post is being rendered in
|
|
||||||
*/
|
|
||||||
channelId?: string;
|
|
||||||
channel: Channel;
|
|
||||||
currentTeam: Team;
|
|
||||||
options?: TextFormattingOptions;
|
|
||||||
pluginHooks?: Array<Record<string, any>>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to place the LinkTooltip component inside links
|
|
||||||
*/
|
|
||||||
hasPluginTooltips?: boolean;
|
|
||||||
isUserCanManageMembers?: boolean;
|
|
||||||
mentionKeys: MentionKey[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not to render the post edited indicator
|
* Whether or not to render the post edited indicator
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
showPostEditedIndicator?: boolean;
|
showPostEditedIndicator?: boolean;
|
||||||
|
options?: TextFormattingOptions;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
type Props = PropsFromRedux & OwnProps;
|
||||||
* Whether the user prefers Military time
|
|
||||||
*/
|
|
||||||
isMilitaryTime?: boolean;
|
|
||||||
timezone?: string;
|
|
||||||
|
|
||||||
hideGuestTags: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class PostMarkdown extends React.PureComponent<Props> {
|
export default class PostMarkdown extends React.PureComponent<Props> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -82,11 +62,10 @@ export default class PostMarkdown extends React.PureComponent<Props> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let {message} = this.props;
|
let message = this.props.message;
|
||||||
const {post, mentionKeys} = this.props;
|
|
||||||
|
|
||||||
if (post) {
|
if (this.props.post) {
|
||||||
const renderedSystemMessage = renderSystemMessage(post,
|
const renderedSystemMessage = renderSystemMessage(this.props.post,
|
||||||
this.props.currentTeam,
|
this.props.currentTeam,
|
||||||
this.props.channel,
|
this.props.channel,
|
||||||
this.props.hideGuestTags,
|
this.props.hideGuestTags,
|
||||||
@ -98,39 +77,45 @@ export default class PostMarkdown extends React.PureComponent<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post && post.type === Posts.POST_TYPES.REMINDER) {
|
if (this.props.post && this.props.post.type === Posts.POST_TYPES.REMINDER) {
|
||||||
const renderedSystemBotMessage = renderReminderSystemBotMessage(post, this.props.currentTeam);
|
const renderedSystemBotMessage = renderReminderSystemBotMessage(this.props.post, this.props.currentTeam);
|
||||||
return <div>{renderedSystemBotMessage}</div>;
|
return <div>{renderedSystemBotMessage}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proxy images if we have an image proxy and the server hasn't already rewritten the post's image URLs.
|
// Proxy images if we have an image proxy and the server hasn't already rewritten the this.props.post's image URLs.
|
||||||
const proxyImages = !post || !post.message_source || post.message === post.message_source;
|
const proxyImages = !this.props.post || !this.props.post.message_source || this.props.post.message === this.props.post.message_source;
|
||||||
const channelNamesMap = post && post.props && post.props.channel_mentions;
|
const channelNamesMap = this.props.post && this.props.post.props && this.props.post.props.channel_mentions;
|
||||||
|
|
||||||
this.props.pluginHooks?.forEach((o) => {
|
this.props.pluginHooks?.forEach((o) => {
|
||||||
if (o && o.hook && post) {
|
if (o && o.hook && this.props.post) {
|
||||||
message = o.hook(post, message);
|
message = o.hook(this.props.post, message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mentionHighlight = this.props.options?.mentionHighlight;
|
let mentionHighlight = this.props.options?.mentionHighlight;
|
||||||
if (post && post.props) {
|
if (this.props.post && this.props.post.props) {
|
||||||
mentionHighlight = !post.props.mentionHighlightDisabled;
|
mentionHighlight = !this.props.post.props.mentionHighlightDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = this.getOptions(
|
const options = this.getOptions(
|
||||||
this.props.options,
|
this.props.options,
|
||||||
post?.props?.disable_group_highlight === true,
|
this.props.post?.props?.disable_group_highlight === true,
|
||||||
mentionHighlight,
|
mentionHighlight,
|
||||||
post?.edit_at,
|
this.props.post?.edit_at,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let highlightKeys;
|
||||||
|
if (!this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady) {
|
||||||
|
highlightKeys = this.props.highlightKeys;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Markdown
|
<Markdown
|
||||||
imageProps={this.props.imageProps}
|
imageProps={this.props.imageProps}
|
||||||
message={message}
|
message={message}
|
||||||
proxyImages={proxyImages}
|
proxyImages={proxyImages}
|
||||||
mentionKeys={mentionKeys}
|
mentionKeys={this.props.mentionKeys}
|
||||||
|
highlightKeys={highlightKeys}
|
||||||
options={options}
|
options={options}
|
||||||
channelNamesMap={channelNamesMap}
|
channelNamesMap={channelNamesMap}
|
||||||
hasPluginTooltips={this.props.hasPluginTooltips}
|
hasPluginTooltips={this.props.hasPluginTooltips}
|
||||||
|
@ -19,7 +19,6 @@ exports[`components/post_view/PostAttachment should match snapshot 1`] = `
|
|||||||
"onImageLoaded": [Function],
|
"onImageLoaded": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="post message"
|
message="post message"
|
||||||
options={Object {}}
|
options={Object {}}
|
||||||
post={
|
post={
|
||||||
@ -57,7 +56,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on Show Less
|
|||||||
"onImageLoaded": [Function],
|
"onImageLoaded": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="post message"
|
message="post message"
|
||||||
options={Object {}}
|
options={Object {}}
|
||||||
post={
|
post={
|
||||||
@ -95,7 +93,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on Show More
|
|||||||
"onImageLoaded": [Function],
|
"onImageLoaded": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="post message"
|
message="post message"
|
||||||
options={Object {}}
|
options={Object {}}
|
||||||
post={
|
post={
|
||||||
@ -151,7 +148,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on edited po
|
|||||||
"onImageLoaded": [Function],
|
"onImageLoaded": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="post message"
|
message="post message"
|
||||||
options={Object {}}
|
options={Object {}}
|
||||||
post={
|
post={
|
||||||
@ -190,7 +186,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on ephemeral
|
|||||||
"onImageLoaded": [Function],
|
"onImageLoaded": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="post message"
|
message="post message"
|
||||||
options={Object {}}
|
options={Object {}}
|
||||||
post={
|
post={
|
||||||
|
@ -158,7 +158,6 @@ export default class PostMessageView extends React.PureComponent<Props, State> {
|
|||||||
options={options}
|
options={options}
|
||||||
post={post}
|
post={post}
|
||||||
channelId={post.channel_id}
|
channelId={post.channel_id}
|
||||||
mentionKeys={[]}
|
|
||||||
showPostEditedIndicator={this.props.showPostEditedIndicator}
|
showPostEditedIndicator={this.props.showPostEditedIndicator}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -139,6 +139,7 @@ exports[`components/ProfilePopover should disable start call button when user is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -197,7 +198,7 @@ exports[`components/ProfilePopover should disable start call button when user is
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -227,6 +228,7 @@ exports[`components/ProfilePopover should disable start call button when user is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -259,7 +261,7 @@ exports[`components/ProfilePopover should disable start call button when user is
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
@ -324,6 +326,7 @@ exports[`components/ProfilePopover should disable start call button when user is
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -487,6 +490,7 @@ exports[`components/ProfilePopover should hide add-to-channel option if not on t
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -592,6 +596,7 @@ exports[`components/ProfilePopover should hide add-to-channel option if not on t
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -755,6 +760,7 @@ exports[`components/ProfilePopover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -813,7 +819,7 @@ exports[`components/ProfilePopover should match snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -843,6 +849,7 @@ exports[`components/ProfilePopover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -875,7 +882,7 @@ exports[`components/ProfilePopover should match snapshot 1`] = `
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Connect(ProfilePopoverCallButton)
|
<Connect(ProfilePopoverCallButton)
|
||||||
@ -944,6 +951,7 @@ exports[`components/ProfilePopover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1122,6 +1130,7 @@ exports[`components/ProfilePopover should match snapshot for shared user 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1181,7 +1190,7 @@ exports[`components/ProfilePopover should match snapshot for shared user 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -1211,6 +1220,7 @@ exports[`components/ProfilePopover should match snapshot for shared user 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1244,7 +1254,7 @@ exports[`components/ProfilePopover should match snapshot for shared user 1`] = `
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Connect(ProfilePopoverCallButton)
|
<Connect(ProfilePopoverCallButton)
|
||||||
@ -1313,6 +1323,7 @@ exports[`components/ProfilePopover should match snapshot for shared user 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1477,6 +1488,7 @@ exports[`components/ProfilePopover should match snapshot when calls are disabled
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1535,7 +1547,7 @@ exports[`components/ProfilePopover should match snapshot when calls are disabled
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -1565,6 +1577,7 @@ exports[`components/ProfilePopover should match snapshot when calls are disabled
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1597,7 +1610,7 @@ exports[`components/ProfilePopover should match snapshot when calls are disabled
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
</div>
|
</div>
|
||||||
@ -1632,6 +1645,7 @@ exports[`components/ProfilePopover should match snapshot when calls are disabled
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1802,6 +1816,7 @@ exports[`components/ProfilePopover should match snapshot with custom status 1`]
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1898,7 +1913,7 @@ exports[`components/ProfilePopover should match snapshot with custom status 1`]
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -1928,6 +1943,7 @@ exports[`components/ProfilePopover should match snapshot with custom status 1`]
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -1960,7 +1976,7 @@ exports[`components/ProfilePopover should match snapshot with custom status 1`]
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Connect(ProfilePopoverCallButton)
|
<Connect(ProfilePopoverCallButton)
|
||||||
@ -2029,6 +2045,7 @@ exports[`components/ProfilePopover should match snapshot with custom status 1`]
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2199,6 +2216,7 @@ exports[`components/ProfilePopover should match snapshot with custom status expi
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2257,7 +2275,7 @@ exports[`components/ProfilePopover should match snapshot with custom status expi
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -2287,6 +2305,7 @@ exports[`components/ProfilePopover should match snapshot with custom status expi
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2319,7 +2338,7 @@ exports[`components/ProfilePopover should match snapshot with custom status expi
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Connect(ProfilePopoverCallButton)
|
<Connect(ProfilePopoverCallButton)
|
||||||
@ -2388,6 +2407,7 @@ exports[`components/ProfilePopover should match snapshot with custom status expi
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2551,6 +2571,7 @@ exports[`components/ProfilePopover should match snapshot with custom status not
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2676,6 +2697,7 @@ exports[`components/ProfilePopover should match snapshot with custom status not
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2839,6 +2861,7 @@ exports[`components/ProfilePopover should match snapshot with last active displa
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2897,7 +2920,7 @@ exports[`components/ProfilePopover should match snapshot with last active displa
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -2927,6 +2950,7 @@ exports[`components/ProfilePopover should match snapshot with last active displa
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -2959,7 +2983,7 @@ exports[`components/ProfilePopover should match snapshot with last active displa
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Connect(ProfilePopoverCallButton)
|
<Connect(ProfilePopoverCallButton)
|
||||||
@ -3028,6 +3052,7 @@ exports[`components/ProfilePopover should match snapshot with last active displa
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -3166,6 +3191,7 @@ exports[`components/ProfilePopover should match snapshot with no last active dis
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -3224,7 +3250,7 @@ exports[`components/ProfilePopover should match snapshot with no last active dis
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -3254,6 +3280,7 @@ exports[`components/ProfilePopover should match snapshot with no last active dis
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -3286,7 +3313,7 @@ exports[`components/ProfilePopover should match snapshot with no last active dis
|
|||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Connect(ProfilePopoverCallButton)
|
<Connect(ProfilePopoverCallButton)
|
||||||
@ -3355,6 +3382,7 @@ exports[`components/ProfilePopover should match snapshot with no last active dis
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -3468,6 +3496,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -3602,6 +3631,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -3946,6 +3976,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -4027,6 +4058,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -4167,7 +4199,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
onMouseOut={[Function]}
|
onMouseOut={[Function]}
|
||||||
onMouseOver={[Function]}
|
onMouseOver={[Function]}
|
||||||
>
|
>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Add to a Channel"
|
ariaLabel="Add to a Channel"
|
||||||
className="btn icon-btn"
|
className="btn icon-btn"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
@ -4197,6 +4229,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -4225,90 +4258,27 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
modalId="add_user_to_channel"
|
modalId="add_user_to_channel"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<ToggleModalButton
|
<button
|
||||||
actions={
|
aria-label="Add to a Channel dialog"
|
||||||
Object {
|
className="style--none btn icon-btn"
|
||||||
"openModal": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ariaLabel="Add to a Channel"
|
|
||||||
className="btn icon-btn"
|
|
||||||
dialogProps={
|
|
||||||
Object {
|
|
||||||
"onExited": [Function],
|
|
||||||
"user": Object {
|
|
||||||
"auth_service": "",
|
|
||||||
"bot_description": "",
|
|
||||||
"create_at": 0,
|
|
||||||
"delete_at": 0,
|
|
||||||
"email": "",
|
|
||||||
"first_name": "",
|
|
||||||
"id": "user_id",
|
|
||||||
"is_bot": false,
|
|
||||||
"last_activity_at": 0,
|
|
||||||
"last_name": "",
|
|
||||||
"last_password_update": 0,
|
|
||||||
"last_picture_update": 0,
|
|
||||||
"locale": "",
|
|
||||||
"mfa_active": false,
|
|
||||||
"nickname": "",
|
|
||||||
"notify_props": Object {
|
|
||||||
"calls_desktop_sound": "true",
|
|
||||||
"channel": "false",
|
|
||||||
"comments": "never",
|
|
||||||
"desktop": "default",
|
|
||||||
"desktop_sound": "false",
|
|
||||||
"email": "false",
|
|
||||||
"first_name": "false",
|
|
||||||
"mark_unread": "mention",
|
|
||||||
"mention_keys": "",
|
|
||||||
"push": "none",
|
|
||||||
"push_status": "offline",
|
|
||||||
},
|
|
||||||
"password": "",
|
|
||||||
"position": "",
|
|
||||||
"props": Object {},
|
|
||||||
"roles": "",
|
|
||||||
"terms_of_service_create_at": 0,
|
|
||||||
"terms_of_service_id": "",
|
|
||||||
"update_at": 0,
|
|
||||||
"username": "some_username",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dialogType={
|
|
||||||
Object {
|
|
||||||
"$$typeof": Symbol(react.memo),
|
|
||||||
"WrappedComponent": [Function],
|
|
||||||
"compare": null,
|
|
||||||
"type": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
id="addToChannelButton"
|
id="addToChannelButton"
|
||||||
modalId="add_user_to_channel"
|
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<button
|
<AccountPlusOutlineIcon
|
||||||
aria-label="Add to a Channel dialog"
|
aria-label="Add User to Channel Icon"
|
||||||
className="style--none btn icon-btn"
|
size={18}
|
||||||
id="addToChannelButton"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
>
|
||||||
<AccountPlusOutlineIcon
|
<svg
|
||||||
aria-label="Add User to Channel Icon"
|
aria-label="Add User to Channel Icon"
|
||||||
size={18}
|
fill="currentColor"
|
||||||
|
height={18}
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width={18}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<svg
|
<path
|
||||||
aria-label="Add User to Channel Icon"
|
d="M5.033,19C4.463,19,4,18.528,4,17.945c0-0.105,0.015-0.208,0.044-0.306c0.058-0.195,0.171-0.37,0.324-0.501c0.076-0.066,0.163-0.121,0.258-0.162l3.093-1.857C8.387,15.52,9.151,15.75,10,15.75s1.613-0.23,2.28-0.631l0.352,0.211
|
||||||
fill="currentColor"
|
|
||||||
height={18}
|
|
||||||
version="1.1"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width={18}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M5.033,19C4.463,19,4,18.528,4,17.945c0-0.105,0.015-0.208,0.044-0.306c0.058-0.195,0.171-0.37,0.324-0.501c0.076-0.066,0.163-0.121,0.258-0.162l3.093-1.857C8.387,15.52,9.151,15.75,10,15.75s1.613-0.23,2.28-0.631l0.352,0.211
|
|
||||||
c0.302-0.606,0.701-1.156,1.181-1.624l-0.006-0.004c1.045-1.391,1.622-3.311,1.622-5.203C15.429,5.21,13.247,3,10,3
|
c0.302-0.606,0.701-1.156,1.181-1.624l-0.006-0.004c1.045-1.391,1.622-3.311,1.622-5.203C15.429,5.21,13.247,3,10,3
|
||||||
S4.571,5.21,4.571,8.5c0,1.891,0.577,3.812,1.622,5.203l-2.515,1.51C2.653,15.727,2,16.783,2,17.945C2,19.63,3.361,21,5.033,21
|
S4.571,5.21,4.571,8.5c0,1.891,0.577,3.812,1.622,5.203l-2.515,1.51C2.653,15.727,2,16.783,2,17.945C2,19.63,3.361,21,5.033,21
|
||||||
h7.776c-0.352-0.608-0.599-1.282-0.719-2H5.033z M10,5c1.894,0,3.429,1.084,3.429,3.5c0,1.482-0.485,3.117-1.353,4.163
|
h7.776c-0.352-0.608-0.599-1.282-0.719-2H5.033z M10,5c1.894,0,3.429,1.084,3.429,3.5c0,1.482-0.485,3.117-1.353,4.163
|
||||||
@ -4316,12 +4286,11 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
c-0.226-0.119-0.437-0.272-0.633-0.453c-0.116-0.108-0.225-0.229-0.331-0.356c-0.072-0.086-0.143-0.174-0.209-0.268
|
c-0.226-0.119-0.437-0.272-0.633-0.453c-0.116-0.108-0.225-0.229-0.331-0.356c-0.072-0.086-0.143-0.174-0.209-0.268
|
||||||
C7.55,12.164,7.403,11.91,7.272,11.64c-0.194-0.406-0.351-0.846-0.466-1.3C6.729,10.037,6.67,9.728,6.631,9.419
|
C7.55,12.164,7.403,11.91,7.272,11.64c-0.194-0.406-0.351-0.846-0.466-1.3C6.729,10.037,6.67,9.728,6.631,9.419
|
||||||
c-0.04-0.308-0.06-0.617-0.06-0.919C6.571,6.084,8.106,5,10,5z M17,14h2v3h3v2h-3v3h-2v-3h-3v-2h3V14"
|
c-0.04-0.308-0.06-0.617-0.06-0.919C6.571,6.084,8.106,5,10,5z M17,14h2v3h3v2h-3v3h-2v-3h-3v-2h3V14"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</AccountPlusOutlineIcon>
|
</AccountPlusOutlineIcon>
|
||||||
</button>
|
</button>
|
||||||
</ToggleModalButton>
|
</ToggleModalButton>
|
||||||
</Connect(ToggleModalButton)>
|
|
||||||
</div>
|
</div>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
@ -4430,6 +4399,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -4511,6 +4481,7 @@ exports[`components/ProfilePopover should show the start call button when isCall
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||||||
import type {ReactNode, RefObject} from 'react';
|
import type {ReactNode, RefObject} from 'react';
|
||||||
|
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
@ -27,36 +27,33 @@ type Props = {
|
|||||||
/**
|
/**
|
||||||
* The setting UI when it is maximized (open)
|
* The setting UI when it is maximized (open)
|
||||||
*/
|
*/
|
||||||
max: ReactNode | null;
|
max: ReactNode;
|
||||||
|
|
||||||
// Props to pass through for SettingItemMin
|
// Props to pass through for SettingItemMin
|
||||||
updateSection: (section: string) => void;
|
updateSection: (section: string) => void;
|
||||||
title?: ReactNode;
|
title?: ReactNode;
|
||||||
disableOpen?: boolean;
|
isDisabled?: boolean;
|
||||||
describe?: ReactNode;
|
describe?: ReactNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement in place of edit button when the setting (in collapsed mode) is disabled
|
||||||
|
*/
|
||||||
|
collapsedEditButtonWhenDisabled?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class SettingItem extends React.PureComponent<Props> {
|
export default class SettingItem extends React.PureComponent<Props> {
|
||||||
minRef: RefObject<SettingItemMinComponent>;
|
minRef: RefObject<SettingItemMinComponent>;
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
infoPosition: 'bottom',
|
|
||||||
saving: false,
|
|
||||||
section: '',
|
|
||||||
containerStyle: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.minRef = React.createRef();
|
this.minRef = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
focusEditButton(): void {
|
|
||||||
this.minRef.current?.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps: Props) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
if (prevProps.active && !this.props.active && this.props.areAllSectionsInactive) {
|
// We want to bring back focus to the edit button when the section is opened and then closed along with all sections are closed
|
||||||
this.focusEditButton();
|
if (!this.props.active && prevProps.active && this.props.areAllSectionsInactive) {
|
||||||
|
this.minRef.current?.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,12 +64,13 @@ export default class SettingItem extends React.PureComponent<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItemMin
|
<SettingItemMin
|
||||||
|
ref={this.minRef}
|
||||||
title={this.props.title}
|
title={this.props.title}
|
||||||
updateSection={this.props.updateSection}
|
updateSection={this.props.updateSection}
|
||||||
describe={this.props.describe}
|
describe={this.props.describe}
|
||||||
section={this.props.section}
|
section={this.props.section}
|
||||||
disableOpen={this.props.disableOpen}
|
isDisabled={this.props.isDisabled}
|
||||||
ref={this.minRef}
|
collapsedEditButtonWhenDisabled={this.props.collapsedEditButtonWhenDisabled}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -36,26 +36,26 @@ describe('components/SettingItemMin', () => {
|
|||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should have called updateSection on handleUpdateSection with section', () => {
|
test('should have called updateSection on handleClick with section', () => {
|
||||||
const updateSection = jest.fn();
|
const updateSection = jest.fn();
|
||||||
const props = {...baseProps, updateSection};
|
const props = {...baseProps, updateSection};
|
||||||
const wrapper = shallow<SettingItemMin>(
|
const wrapper = shallow<SettingItemMin>(
|
||||||
<SettingItemMin {...props}/>,
|
<SettingItemMin {...props}/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
wrapper.instance().handleUpdateSection({preventDefault: jest.fn()} as any);
|
wrapper.instance().handleClick({preventDefault: jest.fn()} as any);
|
||||||
expect(updateSection).toHaveBeenCalled();
|
expect(updateSection).toHaveBeenCalled();
|
||||||
expect(updateSection).toHaveBeenCalledWith('section');
|
expect(updateSection).toHaveBeenCalledWith('section');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should have called updateSection on handleUpdateSection with empty string', () => {
|
test('should have called updateSection on handleClick with empty string', () => {
|
||||||
const updateSection = jest.fn();
|
const updateSection = jest.fn();
|
||||||
const props = {...baseProps, updateSection, section: ''};
|
const props = {...baseProps, updateSection, section: ''};
|
||||||
const wrapper = shallow<SettingItemMin>(
|
const wrapper = shallow<SettingItemMin>(
|
||||||
<SettingItemMin {...props}/>,
|
<SettingItemMin {...props}/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
wrapper.instance().handleUpdateSection({preventDefault: jest.fn()} as any);
|
wrapper.instance().handleClick({preventDefault: jest.fn()} as any);
|
||||||
expect(updateSection).toHaveBeenCalled();
|
expect(updateSection).toHaveBeenCalled();
|
||||||
expect(updateSection).toHaveBeenCalledWith('');
|
expect(updateSection).toHaveBeenCalledWith('');
|
||||||
});
|
});
|
118
webapp/channels/src/components/setting_item_min.tsx
Normal file
118
webapp/channels/src/components/setting_item_min.tsx
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import React, {type ReactNode, type MouseEvent} from 'react';
|
||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
|
import EditIcon from 'components/widgets/icons/fa_edit_icon';
|
||||||
|
|
||||||
|
import {a11yFocus} from 'utils/utils';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings title
|
||||||
|
*/
|
||||||
|
title: ReactNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Option to disable opening the setting
|
||||||
|
*/
|
||||||
|
isDisabled?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings or tab section
|
||||||
|
*/
|
||||||
|
section: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to update section
|
||||||
|
*/
|
||||||
|
updateSection: (section: string) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings description
|
||||||
|
*/
|
||||||
|
describe?: ReactNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement in place of edit button when the setting (in collapsed mode) is disabled
|
||||||
|
*/
|
||||||
|
collapsedEditButtonWhenDisabled?: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class SettingItemMin extends React.PureComponent<Props> {
|
||||||
|
private edit: HTMLButtonElement | null = null;
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
a11yFocus(this.edit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEdit = (node: HTMLButtonElement) => {
|
||||||
|
this.edit = node;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClick = (e: MouseEvent<HTMLDivElement | HTMLButtonElement>) => {
|
||||||
|
if (this.props.isDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.updateSection(this.props.section);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let editButtonComponent: ReactNode;
|
||||||
|
|
||||||
|
if (this.props.isDisabled) {
|
||||||
|
if (this.props.collapsedEditButtonWhenDisabled) {
|
||||||
|
editButtonComponent = this.props.collapsedEditButtonWhenDisabled;
|
||||||
|
} else {
|
||||||
|
editButtonComponent = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
editButtonComponent = (
|
||||||
|
<button
|
||||||
|
ref={this.getEdit}
|
||||||
|
id={this.props.section + 'Edit'}
|
||||||
|
className='color--link style--none section-min__edit'
|
||||||
|
onClick={this.handleClick}
|
||||||
|
aria-labelledby={this.props.section + 'Title ' + this.props.section + 'Edit'}
|
||||||
|
aria-expanded={false}
|
||||||
|
>
|
||||||
|
<EditIcon/>
|
||||||
|
<FormattedMessage
|
||||||
|
id='setting_item_min.edit'
|
||||||
|
defaultMessage='Edit'
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('section-min', {isDisabled: this.props.isDisabled})}
|
||||||
|
onClick={this.handleClick}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className='secion-min__header'
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
id={this.props.section + 'Title'}
|
||||||
|
className={classNames('section-min__title', {isDisabled: this.props.isDisabled})}
|
||||||
|
>
|
||||||
|
{this.props.title}
|
||||||
|
</h4>
|
||||||
|
{editButtonComponent}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id={this.props.section + 'Desc'}
|
||||||
|
className={classNames('section-min__describe', {isDisabled: this.props.isDisabled})}
|
||||||
|
>
|
||||||
|
{this.props.describe}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,60 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`components/SettingItemMin should match snapshot 1`] = `
|
|
||||||
<div
|
|
||||||
className="section-min"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="d-flex"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
className="section-min__title"
|
|
||||||
id="sectionTitle"
|
|
||||||
>
|
|
||||||
title
|
|
||||||
</h4>
|
|
||||||
<div
|
|
||||||
className="section-min__edit"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
aria-expanded={false}
|
|
||||||
aria-labelledby="sectionTitle sectionEdit"
|
|
||||||
className="color--link cursor--pointer style--none text-left"
|
|
||||||
id="sectionEdit"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<EditIcon />
|
|
||||||
<MemoizedFormattedMessage
|
|
||||||
defaultMessage="Edit"
|
|
||||||
id="setting_item_min.edit"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="section-min__describe"
|
|
||||||
id="sectionDesc"
|
|
||||||
>
|
|
||||||
describe
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`components/SettingItemMin should match snapshot, on disableOpen to true 1`] = `
|
|
||||||
<div
|
|
||||||
className="section-min"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="d-flex"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
className="section-min__title"
|
|
||||||
id="sectionTitle"
|
|
||||||
>
|
|
||||||
title
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import {connect} from 'react-redux';
|
|
||||||
|
|
||||||
import {getIsMobileView} from 'selectors/views/browser';
|
|
||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
|
||||||
|
|
||||||
import SettingItemMin from './setting_item_min';
|
|
||||||
|
|
||||||
function mapStateToProps(state: GlobalState) {
|
|
||||||
return {
|
|
||||||
isMobileView: getIsMobileView(state),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, null, null, {forwardRef: true})(SettingItemMin);
|
|
@ -1,131 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import type {ReactNode} from 'react';
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
|
||||||
|
|
||||||
import EditIcon from 'components/widgets/icons/fa_edit_icon';
|
|
||||||
|
|
||||||
import {a11yFocus} from 'utils/utils';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings title
|
|
||||||
*/
|
|
||||||
title: ReactNode | string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Option to disable opening the setting
|
|
||||||
*/
|
|
||||||
disableOpen?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings or tab section
|
|
||||||
*/
|
|
||||||
section: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to update section
|
|
||||||
*/
|
|
||||||
updateSection: (section: string) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings description
|
|
||||||
*/
|
|
||||||
describe?: ReactNode;
|
|
||||||
|
|
||||||
isMobileView: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class SettingItemMin extends React.PureComponent<Props> {
|
|
||||||
private edit: HTMLButtonElement | null = null;
|
|
||||||
|
|
||||||
focus(): void {
|
|
||||||
a11yFocus(this.edit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getEdit = (node: HTMLButtonElement) => {
|
|
||||||
this.edit = node;
|
|
||||||
};
|
|
||||||
|
|
||||||
handleUpdateSection = (e: React.MouseEvent<HTMLElement>) => {
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.updateSection(this.props.section);
|
|
||||||
};
|
|
||||||
|
|
||||||
render(): JSX.Element {
|
|
||||||
let editButton = null;
|
|
||||||
let describeSection = null;
|
|
||||||
|
|
||||||
if (!this.props.disableOpen && this.props.isMobileView) {
|
|
||||||
editButton = (
|
|
||||||
<div className='section-min__edit'>
|
|
||||||
<button
|
|
||||||
id={this.props.section + 'Edit'}
|
|
||||||
className='color--link cursor--pointer style--none'
|
|
||||||
onClick={this.handleUpdateSection}
|
|
||||||
ref={this.getEdit}
|
|
||||||
aria-labelledby={this.props.section + 'Title ' + this.props.section + 'Edit'}
|
|
||||||
aria-expanded={false}
|
|
||||||
>
|
|
||||||
{this.props.describe ? this.props.describe : (
|
|
||||||
<FormattedMessage
|
|
||||||
id='setting_item_min.edit'
|
|
||||||
defaultMessage='Edit'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<i className='icon icon-chevron-down'/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (!this.props.disableOpen) {
|
|
||||||
editButton = (
|
|
||||||
<div className='section-min__edit'>
|
|
||||||
<button
|
|
||||||
id={this.props.section + 'Edit'}
|
|
||||||
className='color--link cursor--pointer style--none text-left'
|
|
||||||
onClick={this.handleUpdateSection}
|
|
||||||
ref={this.getEdit}
|
|
||||||
aria-labelledby={this.props.section + 'Title ' + this.props.section + 'Edit'}
|
|
||||||
aria-expanded={false}
|
|
||||||
>
|
|
||||||
<EditIcon/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='setting_item_min.edit'
|
|
||||||
defaultMessage='Edit'
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
describeSection = (
|
|
||||||
<div
|
|
||||||
id={this.props.section + 'Desc'}
|
|
||||||
className='section-min__describe'
|
|
||||||
>
|
|
||||||
{this.props.describe}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='section-min'
|
|
||||||
onClick={this.handleUpdateSection}
|
|
||||||
>
|
|
||||||
<div className='d-flex'>
|
|
||||||
<h4
|
|
||||||
id={this.props.section + 'Title'}
|
|
||||||
className='section-min__title'
|
|
||||||
>
|
|
||||||
{this.props.title}
|
|
||||||
</h4>
|
|
||||||
{editButton}
|
|
||||||
</div>
|
|
||||||
{describeSection}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -37,7 +37,7 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
teamId="team_id2sss"
|
teamId="team_id2sss"
|
||||||
>
|
>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
ariaLabel="Invite Members"
|
ariaLabel="Invite Members"
|
||||||
className="intro-links color--link cursor--pointer"
|
className="intro-links color--link cursor--pointer"
|
||||||
dialogType={
|
dialogType={
|
||||||
@ -52,51 +52,30 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
modalId="invitation"
|
modalId="invitation"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<ToggleModalButton
|
<button
|
||||||
actions={
|
aria-label="Invite Members dialog"
|
||||||
Object {
|
className="style--none intro-links color--link cursor--pointer"
|
||||||
"openModal": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ariaLabel="Invite Members"
|
|
||||||
className="intro-links color--link cursor--pointer"
|
|
||||||
dialogType={
|
|
||||||
Object {
|
|
||||||
"$$typeof": Symbol(react.memo),
|
|
||||||
"WrappedComponent": [Function],
|
|
||||||
"compare": null,
|
|
||||||
"type": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
id="inviteMembersButton"
|
id="inviteMembersButton"
|
||||||
modalId="invitation"
|
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<button
|
<div
|
||||||
aria-label="Invite Members dialog"
|
aria-label="Invite Members"
|
||||||
className="style--none intro-links color--link cursor--pointer"
|
className="SidebarChannelNavigator__inviteMembersLhsButton"
|
||||||
id="inviteMembersButton"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
>
|
||||||
<div
|
<i
|
||||||
aria-label="Invite Members"
|
className="icon-plus-box"
|
||||||
className="SidebarChannelNavigator__inviteMembersLhsButton"
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Invite Members"
|
||||||
|
id="sidebar_left.inviteMembers"
|
||||||
>
|
>
|
||||||
<i
|
<span>
|
||||||
className="icon-plus-box"
|
Invite Members
|
||||||
/>
|
</span>
|
||||||
<FormattedMessage
|
</FormattedMessage>
|
||||||
defaultMessage="Invite Members"
|
</div>
|
||||||
id="sidebar_left.inviteMembers"
|
</button>
|
||||||
>
|
</ToggleModalButton>
|
||||||
<span>
|
|
||||||
Invite Members
|
|
||||||
</span>
|
|
||||||
</FormattedMessage>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</ToggleModalButton>
|
|
||||||
</Connect(ToggleModalButton)>
|
|
||||||
</TeamPermissionGate>
|
</TeamPermissionGate>
|
||||||
</Connect(TeamPermissionGate)>
|
</Connect(TeamPermissionGate)>
|
||||||
</InviteMembersButton>
|
</InviteMembersButton>
|
||||||
|
@ -102,7 +102,7 @@ exports[`components/TeamSettings/OpenInvite should match snapshot on active with
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/TeamSettings/OpenInvite should match snapshot on non active allowing open invite 1`] = `
|
exports[`components/TeamSettings/OpenInvite should match snapshot on non active allowing open invite 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="Yes"
|
describe="Yes"
|
||||||
section="open_invite"
|
section="open_invite"
|
||||||
title="Allow any user with an account on this server to join this team"
|
title="Allow any user with an account on this server to join this team"
|
||||||
@ -111,7 +111,7 @@ exports[`components/TeamSettings/OpenInvite should match snapshot on non active
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/TeamSettings/OpenInvite should match snapshot on non active with groupConstrained 1`] = `
|
exports[`components/TeamSettings/OpenInvite should match snapshot on non active with groupConstrained 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="No, members of this team are added and removed by linked groups."
|
describe="No, members of this team are added and removed by linked groups."
|
||||||
section="open_invite"
|
section="open_invite"
|
||||||
title="Allow any user with an account on this server to join this team"
|
title="Allow any user with an account on this server to join this team"
|
||||||
@ -120,7 +120,7 @@ exports[`components/TeamSettings/OpenInvite should match snapshot on non active
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/TeamSettings/OpenInvite should match snapshot on non active without groupConstrained 1`] = `
|
exports[`components/TeamSettings/OpenInvite should match snapshot on non active without groupConstrained 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="No"
|
describe="No"
|
||||||
section="open_invite"
|
section="open_invite"
|
||||||
title="Allow any user with an account on this server to join this team"
|
title="Allow any user with an account on this server to join this team"
|
||||||
|
@ -51,7 +51,7 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
|
|||||||
<div
|
<div
|
||||||
className="divider-dark first"
|
className="divider-dark first"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="name"
|
describe="name"
|
||||||
section="name"
|
section="name"
|
||||||
title="Team Name"
|
title="Team Name"
|
||||||
@ -60,7 +60,7 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
|
|||||||
<div
|
<div
|
||||||
className="divider-light"
|
className="divider-light"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe=""
|
describe=""
|
||||||
section="description"
|
section="description"
|
||||||
title="Team Description"
|
title="Team Description"
|
||||||
@ -92,7 +92,7 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
|
|||||||
<div
|
<div
|
||||||
className="divider-light"
|
className="divider-light"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe=""
|
describe=""
|
||||||
section="allowed_domains"
|
section="allowed_domains"
|
||||||
title="allowedDomains"
|
title="allowedDomains"
|
||||||
@ -112,7 +112,7 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
|
|||||||
<div
|
<div
|
||||||
className="divider-light"
|
className="divider-light"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="Click 'Edit' to regenerate Invite Code."
|
describe="Click 'Edit' to regenerate Invite Code."
|
||||||
section="invite_id"
|
section="invite_id"
|
||||||
title="Invite Code"
|
title="Invite Code"
|
||||||
@ -176,7 +176,7 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
|
|||||||
<div
|
<div
|
||||||
className="divider-dark first"
|
className="divider-dark first"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="name"
|
describe="name"
|
||||||
section="name"
|
section="name"
|
||||||
title="Team Name"
|
title="Team Name"
|
||||||
@ -185,7 +185,7 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
|
|||||||
<div
|
<div
|
||||||
className="divider-light"
|
className="divider-light"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe=""
|
describe=""
|
||||||
section="description"
|
section="description"
|
||||||
title="Team Description"
|
title="Team Description"
|
||||||
@ -217,7 +217,7 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
|
|||||||
<div
|
<div
|
||||||
className="divider-light"
|
className="divider-light"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe=""
|
describe=""
|
||||||
section="allowed_domains"
|
section="allowed_domains"
|
||||||
title="allowedDomains"
|
title="allowedDomains"
|
||||||
@ -295,7 +295,7 @@ exports[`components/TeamSettings should match snapshot when team is group constr
|
|||||||
<div
|
<div
|
||||||
className="divider-dark first"
|
className="divider-dark first"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="TestTeam"
|
describe="TestTeam"
|
||||||
section="name"
|
section="name"
|
||||||
title="Team Name"
|
title="Team Name"
|
||||||
@ -304,7 +304,7 @@ exports[`components/TeamSettings should match snapshot when team is group constr
|
|||||||
<div
|
<div
|
||||||
className="divider-light"
|
className="divider-light"
|
||||||
/>
|
/>
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe="The Test Team"
|
describe="The Test Team"
|
||||||
section="description"
|
section="description"
|
||||||
title="Team Description"
|
title="Team Description"
|
||||||
|
@ -289,7 +289,6 @@ export default class Textbox extends React.PureComponent<Props> {
|
|||||||
>
|
>
|
||||||
<PostMarkdown
|
<PostMarkdown
|
||||||
message={this.props.value}
|
message={this.props.value}
|
||||||
mentionKeys={[]}
|
|
||||||
channelId={this.props.channelId}
|
channelId={this.props.channelId}
|
||||||
imageProps={{hideUtilities: true}}
|
imageProps={{hideUtilities: true}}
|
||||||
/>
|
/>
|
||||||
|
@ -10,6 +10,11 @@ import {ModalIdentifiers} from 'utils/constants';
|
|||||||
|
|
||||||
import ToggleModalButton from './toggle_modal_button';
|
import ToggleModalButton from './toggle_modal_button';
|
||||||
|
|
||||||
|
jest.mock('react-redux', () => ({
|
||||||
|
...jest.requireActual('react-redux') as typeof import('react-redux'),
|
||||||
|
useDispatch: () => jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
class TestModal extends React.PureComponent {
|
class TestModal extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -33,7 +38,6 @@ describe('components/ToggleModalButton', () => {
|
|||||||
role='menuitem'
|
role='menuitem'
|
||||||
modalId={ModalIdentifiers.DELETE_CHANNEL}
|
modalId={ModalIdentifiers.DELETE_CHANNEL}
|
||||||
dialogType={TestModal}
|
dialogType={TestModal}
|
||||||
actions={{openModal: () => true}}
|
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='channel_header.delete'
|
id='channel_header.delete'
|
@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React, {type ComponentType, type MouseEvent, type ReactNode} from 'react';
|
||||||
import type {ComponentType, MouseEvent, ReactNode} from 'react';
|
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
|
import {useDispatch} from 'react-redux';
|
||||||
|
|
||||||
import type {ModalData} from 'types/actions';
|
import {openModal} from 'actions/views/modals';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
ariaLabel?: string;
|
ariaLabel?: string;
|
||||||
@ -19,14 +19,25 @@ type Props = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
id?: string;
|
id?: string;
|
||||||
role?: string;
|
role?: string;
|
||||||
actions: {
|
|
||||||
openModal: <P>(modalData: ModalData<P>) => void;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ToggleModalButton = ({ariaLabel, children, modalId, dialogType, dialogProps = {}, onClick, className = '', showUnread, disabled, id, actions, role}: Props) => {
|
const ToggleModalButton = ({
|
||||||
|
ariaLabel,
|
||||||
|
children,
|
||||||
|
modalId,
|
||||||
|
dialogType,
|
||||||
|
dialogProps = {},
|
||||||
|
onClick,
|
||||||
|
className = '',
|
||||||
|
showUnread,
|
||||||
|
disabled,
|
||||||
|
id,
|
||||||
|
role,
|
||||||
|
}: Props) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const show = (e: MouseEvent<HTMLButtonElement>) => {
|
const show = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -38,7 +49,7 @@ const ToggleModalButton = ({ariaLabel, children, modalId, dialogType, dialogProp
|
|||||||
dialogType,
|
dialogType,
|
||||||
};
|
};
|
||||||
|
|
||||||
actions.openModal(modalData);
|
dispatch(openModal(modalData));
|
||||||
};
|
};
|
||||||
|
|
||||||
const ariaLabelElement = ariaLabel ? intl.formatMessage({
|
const ariaLabelElement = ariaLabel ? intl.formatMessage({
|
@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import {connect} from 'react-redux';
|
|
||||||
import {bindActionCreators} from 'redux';
|
|
||||||
import type {Dispatch} from 'redux';
|
|
||||||
|
|
||||||
import {openModal} from 'actions/views/modals';
|
|
||||||
|
|
||||||
import ToggleModalButton from './toggle_modal_button';
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch: Dispatch) {
|
|
||||||
return {
|
|
||||||
actions: bindActionCreators({
|
|
||||||
openModal,
|
|
||||||
}, dispatch),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps)(ToggleModalButton);
|
|
@ -400,6 +400,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -441,6 +442,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -482,6 +484,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -523,6 +526,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -564,6 +568,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -605,6 +610,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -646,6 +652,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -687,6 +694,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -728,6 +736,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -769,6 +778,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -810,6 +820,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -851,6 +862,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -892,6 +904,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -933,6 +946,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -974,6 +988,7 @@ exports[`component/user_group_popover should match snapshot 1`] = `
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -91,6 +91,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -132,6 +133,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -173,6 +175,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -214,6 +217,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
@ -255,6 +259,7 @@ exports[`component/user_group_popover/group_member_list should match snapshot 1`
|
|||||||
"desktop_sound": "false",
|
"desktop_sound": "false",
|
||||||
"email": "false",
|
"email": "false",
|
||||||
"first_name": "false",
|
"first_name": "false",
|
||||||
|
"highlight_keys": "",
|
||||||
"mark_unread": "mention",
|
"mark_unread": "mention",
|
||||||
"mention_keys": "",
|
"mention_keys": "",
|
||||||
"push": "none",
|
"push": "none",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`components/user_settings/advanced/JoinLeaveSection should match snapshot 1`] = `
|
exports[`components/user_settings/advanced/JoinLeaveSection should match snapshot 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
section="joinLeave"
|
section="joinLeave"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
@ -11,7 +11,7 @@ import {Preferences} from 'mattermost-redux/constants';
|
|||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
import {AdvancedSections} from 'utils/constants';
|
import {AdvancedSections} from 'utils/constants';
|
||||||
import {a11yFocus} from 'utils/utils';
|
import {a11yFocus} from 'utils/utils';
|
||||||
|
@ -8,7 +8,7 @@ import {Preferences} from 'mattermost-redux/constants';
|
|||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
import {AdvancedSections} from 'utils/constants';
|
import {AdvancedSections} from 'utils/constants';
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`components/user_settings/display/user_settings_theme/user_settings_theme.jsx should match snapshot 1`] = `
|
exports[`components/user_settings/display/user_settings_theme/user_settings_theme.jsx should match snapshot 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Open to manage your theme"
|
defaultMessage="Open to manage your theme"
|
||||||
|
@ -10,7 +10,7 @@ import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
|
|||||||
import ExternalLink from 'components/external_link';
|
import ExternalLink from 'components/external_link';
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
import ImportThemeModal from 'components/user_settings/import_theme_modal';
|
import ImportThemeModal from 'components/user_settings/import_theme_modal';
|
||||||
|
|
||||||
import {Constants, ModalIdentifiers} from 'utils/constants';
|
import {Constants, ModalIdentifiers} from 'utils/constants';
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -150,7 +150,12 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -247,13 +252,18 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/user_settings/notifications/DesktopNotificationSettings should match snapshot, on buildMinimizedSetting 1`] = `
|
exports[`components/user_settings/notifications/DesktopNotificationSettings should match snapshot, on buildMinimizedSetting 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="For mentions and direct messages, without sound"
|
defaultMessage="For mentions and direct messages, without sound"
|
||||||
@ -261,13 +271,18 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
section="desktop"
|
section="desktop"
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/user_settings/notifications/DesktopNotificationSettings should match snapshot, on buildMinimizedSetting 2`] = `
|
exports[`components/user_settings/notifications/DesktopNotificationSettings should match snapshot, on buildMinimizedSetting 2`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Off"
|
defaultMessage="Off"
|
||||||
@ -275,7 +290,12 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
section="desktop"
|
section="desktop"
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -430,7 +450,12 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -638,7 +663,12 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -892,7 +922,12 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -1101,13 +1136,18 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/user_settings/notifications/DesktopNotificationSettings should match snapshot, on min setting 1`] = `
|
exports[`components/user_settings/notifications/DesktopNotificationSettings should match snapshot, on min setting 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="For mentions and direct messages, without sound"
|
defaultMessage="For mentions and direct messages, without sound"
|
||||||
@ -1115,7 +1155,12 @@ exports[`components/user_settings/notifications/DesktopNotificationSettings shou
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
section="desktop"
|
section="desktop"
|
||||||
title="Desktop Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Desktop Notifications"
|
||||||
|
id="user.settings.notifications.desktop.title"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
@ -19,21 +19,21 @@ jest.mock('utils/notification_sounds', () => {
|
|||||||
|
|
||||||
describe('components/user_settings/notifications/DesktopNotificationSettings', () => {
|
describe('components/user_settings/notifications/DesktopNotificationSettings', () => {
|
||||||
const baseProps: ComponentProps<typeof DesktopNotificationSettings> = {
|
const baseProps: ComponentProps<typeof DesktopNotificationSettings> = {
|
||||||
activity: NotificationLevels.MENTION,
|
|
||||||
sound: 'false',
|
|
||||||
updateSection: jest.fn(),
|
|
||||||
setParentState: jest.fn(),
|
|
||||||
submit: jest.fn(),
|
|
||||||
cancel: jest.fn(),
|
|
||||||
error: '',
|
|
||||||
active: true,
|
active: true,
|
||||||
areAllSectionsInactive: false,
|
updateSection: jest.fn(),
|
||||||
|
onSubmit: jest.fn(),
|
||||||
|
onCancel: jest.fn(),
|
||||||
saving: false,
|
saving: false,
|
||||||
selectedSound: 'Bing',
|
error: '',
|
||||||
|
setParentState: jest.fn(),
|
||||||
|
areAllSectionsInactive: false,
|
||||||
isCollapsedThreadsEnabled: false,
|
isCollapsedThreadsEnabled: false,
|
||||||
|
activity: NotificationLevels.MENTION,
|
||||||
threads: NotificationLevels.ALL,
|
threads: NotificationLevels.ALL,
|
||||||
callsSelectedSound: 'Dynamic',
|
sound: 'false',
|
||||||
callsSound: 'false',
|
callsSound: 'false',
|
||||||
|
selectedSound: 'Bing',
|
||||||
|
callsSelectedSound: 'Dynamic',
|
||||||
isCallsRingingEnabled: false,
|
isCallsRingingEnabled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,8 +81,8 @@ describe('components/user_settings/notifications/DesktopNotificationSettings', (
|
|||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should call props.updateSection and props.cancel on handleMinUpdateSection', () => {
|
test('should call props.updateSection and props.onCancel on handleMinUpdateSection', () => {
|
||||||
const props = {...baseProps, updateSection: jest.fn(), cancel: jest.fn()};
|
const props = {...baseProps, updateSection: jest.fn(), onCancel: jest.fn()};
|
||||||
const wrapper = shallow<DesktopNotificationSettings>(
|
const wrapper = shallow<DesktopNotificationSettings>(
|
||||||
<DesktopNotificationSettings {...props}/>,
|
<DesktopNotificationSettings {...props}/>,
|
||||||
);
|
);
|
||||||
@ -90,14 +90,14 @@ describe('components/user_settings/notifications/DesktopNotificationSettings', (
|
|||||||
wrapper.instance().handleMinUpdateSection('');
|
wrapper.instance().handleMinUpdateSection('');
|
||||||
expect(props.updateSection).toHaveBeenCalledTimes(1);
|
expect(props.updateSection).toHaveBeenCalledTimes(1);
|
||||||
expect(props.updateSection).toHaveBeenCalledWith('');
|
expect(props.updateSection).toHaveBeenCalledWith('');
|
||||||
expect(props.cancel).toHaveBeenCalledTimes(1);
|
expect(props.onCancel).toHaveBeenCalledTimes(1);
|
||||||
expect(props.cancel).toHaveBeenCalledWith();
|
expect(props.onCancel).toHaveBeenCalledWith();
|
||||||
|
|
||||||
wrapper.instance().handleMinUpdateSection('desktop');
|
wrapper.instance().handleMinUpdateSection('desktop');
|
||||||
expect(props.updateSection).toHaveBeenCalledTimes(2);
|
expect(props.updateSection).toHaveBeenCalledTimes(2);
|
||||||
expect(props.updateSection).toHaveBeenCalledWith('desktop');
|
expect(props.updateSection).toHaveBeenCalledWith('desktop');
|
||||||
expect(props.cancel).toHaveBeenCalledTimes(2);
|
expect(props.onCancel).toHaveBeenCalledTimes(2);
|
||||||
expect(props.cancel).toHaveBeenCalledWith();
|
expect(props.onCancel).toHaveBeenCalledWith();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should call props.updateSection on handleMaxUpdateSection', () => {
|
test('should call props.updateSection on handleMaxUpdateSection', () => {
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React, {type ChangeEvent, type RefObject, type ReactNode} from 'react';
|
||||||
import type {ChangeEvent, RefObject} from 'react';
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
import ReactSelect from 'react-select';
|
import ReactSelect, {type ValueType} from 'react-select';
|
||||||
import type {ValueType} from 'react-select';
|
|
||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
import {NotificationLevels} from 'utils/constants';
|
import {NotificationLevels} from 'utils/constants';
|
||||||
import {t} from 'utils/i18n';
|
|
||||||
import * as NotificationSounds from 'utils/notification_sounds';
|
import * as NotificationSounds from 'utils/notification_sounds';
|
||||||
import * as Utils from 'utils/utils';
|
import {a11yFocus} from 'utils/utils';
|
||||||
|
|
||||||
type SelectedOption = {
|
type SelectedOption = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -22,21 +19,21 @@ type SelectedOption = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
active: boolean;
|
||||||
|
updateSection: (section: string) => void;
|
||||||
|
onSubmit: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
saving: boolean;
|
||||||
|
error: string;
|
||||||
|
setParentState: (key: string, value: string | boolean) => void;
|
||||||
|
areAllSectionsInactive: boolean;
|
||||||
|
isCollapsedThreadsEnabled: boolean;
|
||||||
activity: string;
|
activity: string;
|
||||||
threads?: string;
|
threads?: string;
|
||||||
sound: string;
|
sound: string;
|
||||||
callsSound: string;
|
callsSound: string;
|
||||||
updateSection: (section: string) => void;
|
|
||||||
setParentState: (key: string, value: string | boolean) => void;
|
|
||||||
submit: () => void;
|
|
||||||
cancel: () => void;
|
|
||||||
error: string;
|
|
||||||
active: boolean;
|
|
||||||
areAllSectionsInactive: boolean;
|
|
||||||
saving: boolean;
|
|
||||||
selectedSound: string;
|
selectedSound: string;
|
||||||
callsSelectedSound: string;
|
callsSelectedSound: string;
|
||||||
isCollapsedThreadsEnabled: boolean;
|
|
||||||
isCallsRingingEnabled: boolean;
|
isCallsRingingEnabled: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,27 +46,29 @@ type State = {
|
|||||||
export default class DesktopNotificationSettings extends React.PureComponent<Props, State> {
|
export default class DesktopNotificationSettings extends React.PureComponent<Props, State> {
|
||||||
dropdownSoundRef: RefObject<ReactSelect>;
|
dropdownSoundRef: RefObject<ReactSelect>;
|
||||||
callsDropdownRef: RefObject<ReactSelect>;
|
callsDropdownRef: RefObject<ReactSelect>;
|
||||||
minRef: RefObject<SettingItemMinComponent>;
|
editButtonRef: RefObject<SettingItemMinComponent>;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
selectedOption: {value: props.selectedSound, label: props.selectedSound},
|
selectedOption: {value: props.selectedSound, label: props.selectedSound},
|
||||||
callsSelectedOption: {value: props.callsSelectedSound, label: props.callsSelectedSound},
|
callsSelectedOption: {value: props.callsSelectedSound, label: props.callsSelectedSound},
|
||||||
blurDropdown: false,
|
blurDropdown: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dropdownSoundRef = React.createRef();
|
this.dropdownSoundRef = React.createRef();
|
||||||
this.callsDropdownRef = React.createRef();
|
this.callsDropdownRef = React.createRef();
|
||||||
this.minRef = React.createRef();
|
this.editButtonRef = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
focusEditButton(): void {
|
focusEditButton(): void {
|
||||||
this.minRef.current?.focus();
|
this.editButtonRef.current?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMinUpdateSection = (section: string): void => {
|
handleMinUpdateSection = (section: string): void => {
|
||||||
this.props.updateSection(section);
|
this.props.updateSection(section);
|
||||||
this.props.cancel();
|
this.props.onCancel();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMaxUpdateSection = (section: string): void => this.props.updateSection(section);
|
handleMaxUpdateSection = (section: string): void => this.props.updateSection(section);
|
||||||
@ -79,7 +78,7 @@ export default class DesktopNotificationSettings extends React.PureComponent<Pro
|
|||||||
const value = e.currentTarget.getAttribute('data-value');
|
const value = e.currentTarget.getAttribute('data-value');
|
||||||
if (key && value) {
|
if (key && value) {
|
||||||
this.props.setParentState(key, value);
|
this.props.setParentState(key, value);
|
||||||
Utils.a11yFocus(e.currentTarget);
|
a11yFocus(e.currentTarget);
|
||||||
}
|
}
|
||||||
if (key === 'callsDesktopSound' && value === 'false') {
|
if (key === 'callsDesktopSound' && value === 'false') {
|
||||||
NotificationSounds.stopTryNotificationRing();
|
NotificationSounds.stopTryNotificationRing();
|
||||||
@ -435,9 +434,14 @@ export default class DesktopNotificationSettings extends React.PureComponent<Pro
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={Utils.localizeMessage('user.settings.notifications.desktop.title', 'Desktop Notifications')}
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id={'user.settings.notifications.desktop.title'}
|
||||||
|
defaultMessage={'Desktop Notifications'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.props.submit}
|
submit={this.props.onSubmit}
|
||||||
saving={this.props.saving}
|
saving={this.props.saving}
|
||||||
serverError={this.props.error}
|
serverError={this.props.error}
|
||||||
updateSection={this.handleMaxUpdateSection}
|
updateSection={this.handleMaxUpdateSection}
|
||||||
@ -446,56 +450,76 @@ export default class DesktopNotificationSettings extends React.PureComponent<Pro
|
|||||||
};
|
};
|
||||||
|
|
||||||
buildMinimizedSetting = () => {
|
buildMinimizedSetting = () => {
|
||||||
let formattedMessageProps;
|
|
||||||
const hasSoundOption = NotificationSounds.hasSoundOptions();
|
const hasSoundOption = NotificationSounds.hasSoundOptions();
|
||||||
|
let collapsedDescription: ReactNode = null;
|
||||||
|
|
||||||
if (this.props.activity === NotificationLevels.MENTION) {
|
if (this.props.activity === NotificationLevels.MENTION) {
|
||||||
if (hasSoundOption && this.props.sound !== 'false') {
|
if (hasSoundOption && this.props.sound !== 'false') {
|
||||||
formattedMessageProps = {
|
collapsedDescription = (
|
||||||
id: t('user.settings.notifications.desktop.mentionsSound'),
|
<FormattedMessage
|
||||||
defaultMessage: 'For mentions and direct messages, with sound',
|
id='user.settings.notifications.desktop.mentionsSound'
|
||||||
};
|
defaultMessage='For mentions and direct messages, with sound'
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else if (hasSoundOption && this.props.sound === 'false') {
|
} else if (hasSoundOption && this.props.sound === 'false') {
|
||||||
formattedMessageProps = {
|
collapsedDescription = (
|
||||||
id: t('user.settings.notifications.desktop.mentionsNoSound'),
|
<FormattedMessage
|
||||||
defaultMessage: 'For mentions and direct messages, without sound',
|
id='user.settings.notifications.desktop.mentionsNoSound'
|
||||||
};
|
defaultMessage='For mentions and direct messages, without sound'
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
formattedMessageProps = {
|
collapsedDescription = (
|
||||||
id: t('user.settings.notifications.desktop.mentionsSoundHidden'),
|
<FormattedMessage
|
||||||
defaultMessage: 'For mentions and direct messages',
|
id='user.settings.notifications.desktop.mentionsSoundHidden'
|
||||||
};
|
defaultMessage='For mentions and direct messages'
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (this.props.activity === NotificationLevels.NONE) {
|
} else if (this.props.activity === NotificationLevels.NONE) {
|
||||||
formattedMessageProps = {
|
collapsedDescription = (
|
||||||
id: t('user.settings.notifications.off'),
|
<FormattedMessage
|
||||||
defaultMessage: 'Off',
|
id='user.settings.notifications.off'
|
||||||
};
|
defaultMessage='Off'
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if (hasSoundOption && this.props.sound !== 'false') { //eslint-disable-line no-lonely-if
|
if (hasSoundOption && this.props.sound !== 'false') { //eslint-disable-line no-lonely-if
|
||||||
formattedMessageProps = {
|
collapsedDescription = (
|
||||||
id: t('user.settings.notifications.desktop.allSound'),
|
<FormattedMessage
|
||||||
defaultMessage: 'For all activity, with sound',
|
id='user.settings.notifications.desktop.allSound'
|
||||||
};
|
defaultMessage='For all activity, with sound'
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else if (hasSoundOption && this.props.sound === 'false') {
|
} else if (hasSoundOption && this.props.sound === 'false') {
|
||||||
formattedMessageProps = {
|
collapsedDescription = (
|
||||||
id: t('user.settings.notifications.desktop.allNoSound'),
|
<FormattedMessage
|
||||||
defaultMessage: 'For all activity, without sound',
|
id='user.settings.notifications.desktop.allNoSound'
|
||||||
};
|
defaultMessage='For all activity, without sound'
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
formattedMessageProps = {
|
collapsedDescription = (
|
||||||
id: t('user.settings.notifications.desktop.allSoundHidden'),
|
<FormattedMessage
|
||||||
defaultMessage: 'For all activity',
|
id='user.settings.notifications.desktop.allSoundHidden'
|
||||||
};
|
defaultMessage='For all activity'
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItemMin
|
<SettingItemMin
|
||||||
title={Utils.localizeMessage('user.settings.notifications.desktop.title', 'Desktop Notifications')}
|
ref={this.editButtonRef}
|
||||||
describe={<FormattedMessage {...formattedMessageProps}/>}
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id={'user.settings.notifications.desktop.title'}
|
||||||
|
defaultMessage={'Desktop Notifications'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
describe={collapsedDescription}
|
||||||
section={'desktop'}
|
section={'desktop'}
|
||||||
updateSection={this.handleMinUpdateSection}
|
updateSection={this.handleMinUpdateSection}
|
||||||
ref={this.minRef}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -7,18 +7,19 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
"savePreferences": [MockFunction],
|
"savePreferences": [MockFunction],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activeSection="email"
|
active={true}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
currentUserId="current_user_id"
|
currentUserId="current_user_id"
|
||||||
emailInterval={0}
|
emailInterval={0}
|
||||||
enableEmail={false}
|
enableEmail={false}
|
||||||
enableEmailBatching={false}
|
enableEmailBatching={false}
|
||||||
|
error=""
|
||||||
isCollapsedThreadsEnabled={false}
|
isCollapsedThreadsEnabled={false}
|
||||||
onCancel={[MockFunction]}
|
onCancel={[MockFunction]}
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
onSubmit={[MockFunction]}
|
onSubmit={[MockFunction]}
|
||||||
saving={false}
|
saving={false}
|
||||||
sendEmailNotifications={true}
|
sendEmailNotifications={true}
|
||||||
serverError=""
|
|
||||||
setParentState={[MockFunction]}
|
setParentState={[MockFunction]}
|
||||||
threads="all"
|
threads="all"
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
@ -92,7 +93,12 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
@ -102,7 +108,14 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
className="col-sm-12 section-title"
|
className="col-sm-12 section-title"
|
||||||
id="settingTitle"
|
id="settingTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
<FormattedMessage
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Email Notifications
|
||||||
|
</span>
|
||||||
|
</FormattedMessage>
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-9 col-sm-offset-3"
|
className="col-sm-9 col-sm-offset-3"
|
||||||
@ -266,7 +279,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/user_settings/notifications/EmailNotificationSetting should match snapshot, active section != email and SendEmailNotifications !== true 1`] = `
|
exports[`components/user_settings/notifications/EmailNotificationSetting should match snapshot, active section != email and SendEmailNotifications !== true 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email notifications are not enabled"
|
defaultMessage="Email notifications are not enabled"
|
||||||
@ -274,13 +287,18 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
section="email"
|
section="email"
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/user_settings/notifications/EmailNotificationSetting should match snapshot, active section != email and SendEmailNotifications = true 1`] = `
|
exports[`components/user_settings/notifications/EmailNotificationSetting should match snapshot, active section != email and SendEmailNotifications = true 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Never"
|
defaultMessage="Never"
|
||||||
@ -288,13 +306,18 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
section="email"
|
section="email"
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`components/user_settings/notifications/EmailNotificationSetting should match snapshot, active section != email, SendEmailNotifications = true and enableEmail = true 1`] = `
|
exports[`components/user_settings/notifications/EmailNotificationSetting should match snapshot, active section != email, SendEmailNotifications = true and enableEmail = true 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Immediately"
|
defaultMessage="Immediately"
|
||||||
@ -302,7 +325,12 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
section="email"
|
section="email"
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -314,18 +342,19 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
"savePreferences": [MockFunction],
|
"savePreferences": [MockFunction],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activeSection="email"
|
active={true}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
currentUserId="current_user_id"
|
currentUserId="current_user_id"
|
||||||
emailInterval={0}
|
emailInterval={0}
|
||||||
enableEmail={false}
|
enableEmail={false}
|
||||||
enableEmailBatching={true}
|
enableEmailBatching={true}
|
||||||
|
error=""
|
||||||
isCollapsedThreadsEnabled={false}
|
isCollapsedThreadsEnabled={false}
|
||||||
onCancel={[MockFunction]}
|
onCancel={[MockFunction]}
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
onSubmit={[MockFunction]}
|
onSubmit={[MockFunction]}
|
||||||
saving={false}
|
saving={false}
|
||||||
sendEmailNotifications={true}
|
sendEmailNotifications={true}
|
||||||
serverError=""
|
|
||||||
setParentState={[MockFunction]}
|
setParentState={[MockFunction]}
|
||||||
threads="all"
|
threads="all"
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
@ -448,7 +477,12 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
@ -458,7 +492,14 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
className="col-sm-12 section-title"
|
className="col-sm-12 section-title"
|
||||||
id="settingTitle"
|
id="settingTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
<FormattedMessage
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Email Notifications
|
||||||
|
</span>
|
||||||
|
</FormattedMessage>
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-9 col-sm-offset-3"
|
className="col-sm-9 col-sm-offset-3"
|
||||||
@ -701,7 +742,12 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
saving={false}
|
saving={false}
|
||||||
section="email"
|
section="email"
|
||||||
serverError=""
|
serverError=""
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -776,7 +822,12 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section=""
|
section=""
|
||||||
serverError="serverError"
|
serverError="serverError"
|
||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -889,7 +940,12 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@ -964,7 +1020,12 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section=""
|
section=""
|
||||||
serverError=""
|
serverError=""
|
||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title="Email Notifications"
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Email Notifications"
|
||||||
|
id="user.settings.notifications.emailNotifications"
|
||||||
|
/>
|
||||||
|
}
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
@ -12,24 +12,25 @@ import {Preferences, NotificationLevels} from 'utils/constants';
|
|||||||
|
|
||||||
describe('components/user_settings/notifications/EmailNotificationSetting', () => {
|
describe('components/user_settings/notifications/EmailNotificationSetting', () => {
|
||||||
const requiredProps: ComponentProps<typeof EmailNotificationSetting> = {
|
const requiredProps: ComponentProps<typeof EmailNotificationSetting> = {
|
||||||
currentUserId: 'current_user_id',
|
active: true,
|
||||||
activeSection: 'email',
|
|
||||||
updateSection: jest.fn(),
|
updateSection: jest.fn(),
|
||||||
enableEmail: false,
|
|
||||||
emailInterval: Preferences.INTERVAL_NEVER,
|
|
||||||
onSubmit: jest.fn(),
|
onSubmit: jest.fn(),
|
||||||
onCancel: jest.fn(),
|
onCancel: jest.fn(),
|
||||||
onChange: jest.fn(),
|
|
||||||
serverError: '',
|
|
||||||
saving: false,
|
saving: false,
|
||||||
|
error: '',
|
||||||
|
setParentState: jest.fn(),
|
||||||
|
areAllSectionsInactive: false,
|
||||||
|
isCollapsedThreadsEnabled: false,
|
||||||
|
enableEmail: false,
|
||||||
|
onChange: jest.fn(),
|
||||||
|
threads: NotificationLevels.ALL,
|
||||||
|
currentUserId: 'current_user_id',
|
||||||
|
emailInterval: Preferences.INTERVAL_NEVER,
|
||||||
sendEmailNotifications: true,
|
sendEmailNotifications: true,
|
||||||
enableEmailBatching: false,
|
enableEmailBatching: false,
|
||||||
actions: {
|
actions: {
|
||||||
savePreferences: jest.fn(),
|
savePreferences: jest.fn(),
|
||||||
},
|
},
|
||||||
isCollapsedThreadsEnabled: false,
|
|
||||||
threads: NotificationLevels.ALL,
|
|
||||||
setParentState: jest.fn(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should match snapshot', () => {
|
test('should match snapshot', () => {
|
||||||
@ -68,7 +69,7 @@ describe('components/user_settings/notifications/EmailNotificationSetting', () =
|
|||||||
const props = {
|
const props = {
|
||||||
...requiredProps,
|
...requiredProps,
|
||||||
sendEmailNotifications: false,
|
sendEmailNotifications: false,
|
||||||
activeSection: '',
|
active: false,
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ describe('components/user_settings/notifications/EmailNotificationSetting', () =
|
|||||||
const props = {
|
const props = {
|
||||||
...requiredProps,
|
...requiredProps,
|
||||||
sendEmailNotifications: true,
|
sendEmailNotifications: true,
|
||||||
activeSection: '',
|
active: false,
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ describe('components/user_settings/notifications/EmailNotificationSetting', () =
|
|||||||
const props = {
|
const props = {
|
||||||
...requiredProps,
|
...requiredProps,
|
||||||
sendEmailNotifications: true,
|
sendEmailNotifications: true,
|
||||||
activeSection: '',
|
active: false,
|
||||||
enableEmail: true,
|
enableEmail: true,
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
||||||
@ -100,7 +101,7 @@ describe('components/user_settings/notifications/EmailNotificationSetting', () =
|
|||||||
|
|
||||||
test('should match snapshot, on serverError', () => {
|
test('should match snapshot, on serverError', () => {
|
||||||
const newServerError = 'serverError';
|
const newServerError = 'serverError';
|
||||||
const props = {...requiredProps, serverError: newServerError};
|
const props = {...requiredProps, error: newServerError};
|
||||||
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
const wrapper = shallow(<EmailNotificationSetting {...props}/>);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React, {type RefObject} from 'react';
|
||||||
import type {RefObject} from 'react';
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
import type {PreferenceType} from '@mattermost/types/preferences';
|
import type {PreferenceType} from '@mattermost/types/preferences';
|
||||||
@ -12,37 +11,38 @@ import {getEmailInterval} from 'mattermost-redux/utils/notify_props';
|
|||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
import {Preferences, NotificationLevels} from 'utils/constants';
|
import {Preferences, NotificationLevels} from 'utils/constants';
|
||||||
import {a11yFocus, localizeMessage} from 'utils/utils';
|
import {a11yFocus} from 'utils/utils';
|
||||||
|
|
||||||
const SECONDS_PER_MINUTE = 60;
|
const SECONDS_PER_MINUTE = 60;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentUserId: string;
|
active: boolean;
|
||||||
activeSection: string;
|
|
||||||
updateSection: (section: string) => void;
|
updateSection: (section: string) => void;
|
||||||
enableEmail: boolean;
|
|
||||||
emailInterval: number;
|
|
||||||
onSubmit: () => void;
|
onSubmit: () => void;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onChange: (enableEmail: UserNotifyProps['email']) => void;
|
|
||||||
serverError?: string;
|
|
||||||
saving?: boolean;
|
saving?: boolean;
|
||||||
|
error?: string;
|
||||||
|
setParentState: (key: string, value: any) => void;
|
||||||
|
areAllSectionsInactive: boolean;
|
||||||
|
isCollapsedThreadsEnabled: boolean;
|
||||||
|
enableEmail: boolean;
|
||||||
|
onChange: (enableEmail: UserNotifyProps['email']) => void;
|
||||||
|
threads: string;
|
||||||
|
currentUserId: string;
|
||||||
|
emailInterval: number;
|
||||||
sendEmailNotifications: boolean;
|
sendEmailNotifications: boolean;
|
||||||
enableEmailBatching: boolean;
|
enableEmailBatching: boolean;
|
||||||
actions: {
|
actions: {
|
||||||
savePreferences: (currentUserId: string, emailIntervalPreference: PreferenceType[]) =>
|
savePreferences: (currentUserId: string, emailIntervalPreference: PreferenceType[]) =>
|
||||||
Promise<{data: boolean}>;
|
Promise<{data: boolean}>;
|
||||||
};
|
};
|
||||||
isCollapsedThreadsEnabled: boolean;
|
|
||||||
threads: string;
|
|
||||||
setParentState: (key: string, value: any) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
activeSection: string;
|
active: boolean;
|
||||||
emailInterval: number;
|
emailInterval: number;
|
||||||
enableEmail: boolean;
|
enableEmail: boolean;
|
||||||
enableEmailBatching: boolean;
|
enableEmailBatching: boolean;
|
||||||
@ -51,7 +51,7 @@ type State = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default class EmailNotificationSetting extends React.PureComponent<Props, State> {
|
export default class EmailNotificationSetting extends React.PureComponent<Props, State> {
|
||||||
minRef: RefObject<SettingItemMinComponent>;
|
editButtonRef: RefObject<SettingItemMinComponent>;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -61,11 +61,11 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
enableEmail,
|
enableEmail,
|
||||||
enableEmailBatching,
|
enableEmailBatching,
|
||||||
sendEmailNotifications,
|
sendEmailNotifications,
|
||||||
activeSection,
|
active,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
activeSection,
|
active,
|
||||||
emailInterval,
|
emailInterval,
|
||||||
enableEmail,
|
enableEmail,
|
||||||
enableEmailBatching,
|
enableEmailBatching,
|
||||||
@ -73,7 +73,7 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
newInterval: getEmailInterval(enableEmail && sendEmailNotifications, enableEmailBatching, emailInterval),
|
newInterval: getEmailInterval(enableEmail && sendEmailNotifications, enableEmailBatching, emailInterval),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.minRef = React.createRef();
|
this.editButtonRef = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||||
@ -82,13 +82,13 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
enableEmail,
|
enableEmail,
|
||||||
enableEmailBatching,
|
enableEmailBatching,
|
||||||
sendEmailNotifications,
|
sendEmailNotifications,
|
||||||
activeSection,
|
active,
|
||||||
} = nextProps;
|
} = nextProps;
|
||||||
|
|
||||||
// If we're re-opening this section, reset to defaults from props
|
// If we're re-opening this section, reset to defaults from props
|
||||||
if (activeSection === 'email' && prevState.activeSection !== 'email') {
|
if (active && !prevState.active) {
|
||||||
return {
|
return {
|
||||||
activeSection,
|
active,
|
||||||
emailInterval,
|
emailInterval,
|
||||||
enableEmail,
|
enableEmail,
|
||||||
enableEmailBatching,
|
enableEmailBatching,
|
||||||
@ -100,10 +100,10 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
if (sendEmailNotifications !== prevState.sendEmailNotifications ||
|
if (sendEmailNotifications !== prevState.sendEmailNotifications ||
|
||||||
enableEmailBatching !== prevState.enableEmailBatching ||
|
enableEmailBatching !== prevState.enableEmailBatching ||
|
||||||
emailInterval !== prevState.emailInterval ||
|
emailInterval !== prevState.emailInterval ||
|
||||||
activeSection !== prevState.activeSection
|
active !== prevState.active
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
activeSection,
|
active,
|
||||||
emailInterval,
|
emailInterval,
|
||||||
enableEmail,
|
enableEmail,
|
||||||
enableEmailBatching,
|
enableEmailBatching,
|
||||||
@ -116,7 +116,7 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
}
|
}
|
||||||
|
|
||||||
focusEditButton(): void {
|
focusEditButton(): void {
|
||||||
this.minRef.current?.focus();
|
this.editButtonRef.current?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@ -234,11 +234,16 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItemMin
|
<SettingItemMin
|
||||||
title={localizeMessage('user.settings.notifications.emailNotifications', 'Email Notifications')}
|
ref={this.editButtonRef}
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id={'user.settings.notifications.emailNotifications'}
|
||||||
|
defaultMessage={'Email Notifications'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
describe={description}
|
describe={description}
|
||||||
section={'email'}
|
section={'email'}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
ref={this.minRef}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -247,7 +252,12 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
if (!this.props.sendEmailNotifications) {
|
if (!this.props.sendEmailNotifications) {
|
||||||
return (
|
return (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={localizeMessage('user.settings.notifications.emailNotifications', 'Email Notifications')}
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id={'user.settings.notifications.emailNotifications'}
|
||||||
|
defaultMessage={'Email Notifications'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
inputs={[
|
inputs={[
|
||||||
<div
|
<div
|
||||||
key='oauthEmailInfo'
|
key='oauthEmailInfo'
|
||||||
@ -259,7 +269,7 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
/>
|
/>
|
||||||
</div>,
|
</div>,
|
||||||
]}
|
]}
|
||||||
serverError={this.props.serverError}
|
serverError={this.props.error}
|
||||||
section={'email'}
|
section={'email'}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
/>
|
/>
|
||||||
@ -359,7 +369,12 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={localizeMessage('user.settings.notifications.emailNotifications', 'Email Notifications')}
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id={'user.settings.notifications.emailNotifications'}
|
||||||
|
defaultMessage={'Email Notifications'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
inputs={[
|
inputs={[
|
||||||
<fieldset key='userNotificationEmailOptions'>
|
<fieldset key='userNotificationEmailOptions'>
|
||||||
<legend className='form-legend'>
|
<legend className='form-legend'>
|
||||||
@ -416,23 +431,23 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
]}
|
]}
|
||||||
submit={this.handleSubmit}
|
submit={this.handleSubmit}
|
||||||
saving={this.props.saving}
|
saving={this.props.saving}
|
||||||
serverError={this.props.serverError}
|
serverError={this.props.error}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate(prevProps: Props) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
if (prevProps.activeSection === 'email' && this.props.activeSection === '') {
|
if (prevProps.active && !this.props.active && this.props.areAllSectionsInactive) {
|
||||||
this.focusEditButton();
|
this.focusEditButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.activeSection !== 'email') {
|
if (this.props.active) {
|
||||||
return this.renderMinSettingView();
|
return this.renderMaxSettingView();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.renderMaxSettingView();
|
return this.renderMinSettingView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,14 @@
|
|||||||
import {connect, type ConnectedProps} from 'react-redux';
|
import {connect, type ConnectedProps} from 'react-redux';
|
||||||
|
|
||||||
import {updateMe} from 'mattermost-redux/actions/users';
|
import {updateMe} from 'mattermost-redux/actions/users';
|
||||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
import {getSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud';
|
||||||
|
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
|
import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
|
|
||||||
import {isCallsEnabled, isCallsRingingEnabledOnServer} from 'selectors/calls';
|
import {isCallsEnabled, isCallsRingingEnabledOnServer} from 'selectors/calls';
|
||||||
|
|
||||||
|
import {isEnterpriseOrCloudOrSKUStarterFree} from 'utils/license_utils';
|
||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
import type {GlobalState} from 'types/store';
|
||||||
|
|
||||||
import UserSettingsNotifications from './user_settings_notifications';
|
import UserSettingsNotifications from './user_settings_notifications';
|
||||||
@ -18,11 +21,20 @@ const mapStateToProps = (state: GlobalState) => {
|
|||||||
|
|
||||||
const sendPushNotifications = config.SendPushNotifications === 'true';
|
const sendPushNotifications = config.SendPushNotifications === 'true';
|
||||||
const enableAutoResponder = config.ExperimentalEnableAutomaticReplies === 'true';
|
const enableAutoResponder = config.ExperimentalEnableAutomaticReplies === 'true';
|
||||||
|
|
||||||
|
const license = getLicense(state);
|
||||||
|
const subscriptionProduct = getSubscriptionProduct(state);
|
||||||
|
|
||||||
|
const isEnterpriseReady = config.BuildEnterpriseReady === 'true';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sendPushNotifications,
|
sendPushNotifications,
|
||||||
enableAutoResponder,
|
enableAutoResponder,
|
||||||
isCollapsedThreadsEnabled: isCollapsedThreadsEnabled(state),
|
isCollapsedThreadsEnabled: isCollapsedThreadsEnabled(state),
|
||||||
isCallsRingingEnabled: isCallsEnabled(state, '0.17.0') && isCallsRingingEnabledOnServer(state),
|
isCallsRingingEnabled: isCallsEnabled(state, '0.17.0') && isCallsRingingEnabledOnServer(state),
|
||||||
|
isEnterpriseOrCloudOrSKUStarterFree: isEnterpriseOrCloudOrSKUStarterFree(license, subscriptionProduct, isEnterpriseReady),
|
||||||
|
isEnterpriseReady,
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,4 +46,4 @@ const connector = connect(mapStateToProps, mapDispatchToProps);
|
|||||||
|
|
||||||
export type PropsFromRedux = ConnectedProps<typeof connector>;
|
export type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserSettingsNotifications);
|
export default connector(UserSettingsNotifications);
|
||||||
|
@ -22,6 +22,8 @@ describe('components/user_settings/display/UserSettingsDisplay', () => {
|
|||||||
enableAutoResponder: false,
|
enableAutoResponder: false,
|
||||||
isCallsRingingEnabled: true,
|
isCallsRingingEnabled: true,
|
||||||
intl: {} as IntlShape,
|
intl: {} as IntlShape,
|
||||||
|
isEnterpriseOrCloudOrSKUStarterFree: false,
|
||||||
|
isEnterpriseReady: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should match snapshot', () => {
|
test('should match snapshot', () => {
|
||||||
@ -32,6 +34,26 @@ describe('components/user_settings/display/UserSettingsDisplay', () => {
|
|||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should match snapshot when its a starter free', () => {
|
||||||
|
const props = {...defaultProps, isEnterpriseOrCloudOrSKUStarterFree: true};
|
||||||
|
|
||||||
|
const wrapper = renderWithContext(
|
||||||
|
<UserSettingsNotifications {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should match snapshot when its team edition', () => {
|
||||||
|
const props = {...defaultProps, isEnterpriseReady: false};
|
||||||
|
|
||||||
|
const wrapper = renderWithContext(
|
||||||
|
<UserSettingsNotifications {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
test('should show reply notifications section when CRT off', () => {
|
test('should show reply notifications section when CRT off', () => {
|
||||||
const props = {...defaultProps, isCollapsedThreadsEnabled: false};
|
const props = {...defaultProps, isCollapsedThreadsEnabled: false};
|
||||||
|
|
||||||
|
@ -19,8 +19,9 @@ import type {ActionResult} from 'mattermost-redux/types/actions';
|
|||||||
import ExternalLink from 'components/external_link';
|
import ExternalLink from 'components/external_link';
|
||||||
import SettingItem from 'components/setting_item';
|
import SettingItem from 'components/setting_item';
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
|
import RestrictedIndicator from 'components/widgets/menu/menu_items/restricted_indicator';
|
||||||
|
|
||||||
import Constants, {NotificationLevels} from 'utils/constants';
|
import Constants, {NotificationLevels, MattermostFeatures, LicenseSkus} from 'utils/constants';
|
||||||
import {stopTryNotificationRing} from 'utils/notification_sounds';
|
import {stopTryNotificationRing} from 'utils/notification_sounds';
|
||||||
import {a11yFocus} from 'utils/utils';
|
import {a11yFocus} from 'utils/utils';
|
||||||
|
|
||||||
@ -65,6 +66,8 @@ type State = {
|
|||||||
isCustomKeysWithNotificationInputChecked: boolean;
|
isCustomKeysWithNotificationInputChecked: boolean;
|
||||||
customKeysWithNotification: MultiInputValue[];
|
customKeysWithNotification: MultiInputValue[];
|
||||||
customKeysWithNotificationInputValue: string;
|
customKeysWithNotificationInputValue: string;
|
||||||
|
customKeysWithHighlight: MultiInputValue[];
|
||||||
|
customKeysWithHighlightInputValue: string;
|
||||||
firstNameKey: boolean;
|
firstNameKey: boolean;
|
||||||
channelKey: boolean;
|
channelKey: boolean;
|
||||||
autoResponderActive: boolean;
|
autoResponderActive: boolean;
|
||||||
@ -145,9 +148,10 @@ function getDefaultStateFromProps(props: Props): State {
|
|||||||
let channelKey = false;
|
let channelKey = false;
|
||||||
let isCustomKeysWithNotificationInputChecked = false;
|
let isCustomKeysWithNotificationInputChecked = false;
|
||||||
const customKeysWithNotification: MultiInputValue[] = [];
|
const customKeysWithNotification: MultiInputValue[] = [];
|
||||||
|
const customKeysWithHighlight: MultiInputValue[] = [];
|
||||||
|
|
||||||
if (props.user.notify_props) {
|
if (props.user.notify_props) {
|
||||||
if (props.user.notify_props.mention_keys) {
|
if (props.user.notify_props?.mention_keys?.length > 0) {
|
||||||
const mentionKeys = props.user.notify_props.mention_keys.split(',').filter((key) => key.length > 0);
|
const mentionKeys = props.user.notify_props.mention_keys.split(',').filter((key) => key.length > 0);
|
||||||
mentionKeys.forEach((mentionKey) => {
|
mentionKeys.forEach((mentionKey) => {
|
||||||
// Remove username(s) from list of keys
|
// Remove username(s) from list of keys
|
||||||
@ -166,6 +170,16 @@ function getDefaultStateFromProps(props: Props): State {
|
|||||||
isCustomKeysWithNotificationInputChecked = customKeysWithNotification.length > 0;
|
isCustomKeysWithNotificationInputChecked = customKeysWithNotification.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.user.notify_props?.highlight_keys?.length > 0) {
|
||||||
|
const highlightKeys = props.user.notify_props.highlight_keys.split(',').filter((key) => key.length > 0);
|
||||||
|
highlightKeys.forEach((highlightKey) => {
|
||||||
|
customKeysWithHighlight.push({
|
||||||
|
label: highlightKey,
|
||||||
|
value: highlightKey,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
firstNameKey = props.user.notify_props?.first_name === 'true';
|
firstNameKey = props.user.notify_props?.first_name === 'true';
|
||||||
channelKey = props.user.notify_props?.channel === 'true';
|
channelKey = props.user.notify_props?.channel === 'true';
|
||||||
}
|
}
|
||||||
@ -186,6 +200,8 @@ function getDefaultStateFromProps(props: Props): State {
|
|||||||
customKeysWithNotification,
|
customKeysWithNotification,
|
||||||
isCustomKeysWithNotificationInputChecked,
|
isCustomKeysWithNotificationInputChecked,
|
||||||
customKeysWithNotificationInputValue: '',
|
customKeysWithNotificationInputValue: '',
|
||||||
|
customKeysWithHighlight,
|
||||||
|
customKeysWithHighlightInputValue: '',
|
||||||
firstNameKey,
|
firstNameKey,
|
||||||
channelKey,
|
channelKey,
|
||||||
autoResponderActive,
|
autoResponderActive,
|
||||||
@ -249,6 +265,14 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
data.mention_keys = mentionKeys.join(',');
|
data.mention_keys = mentionKeys.join(',');
|
||||||
|
|
||||||
|
const highlightKeys: string[] = [];
|
||||||
|
if (this.state.customKeysWithHighlight.length > 0) {
|
||||||
|
this.state.customKeysWithHighlight.forEach((key) => {
|
||||||
|
highlightKeys.push(key.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
data.highlight_keys = highlightKeys.join(',');
|
||||||
|
|
||||||
this.setState({isSaving: true});
|
this.setState({isSaving: true});
|
||||||
stopTryNotificationRing();
|
stopTryNotificationRing();
|
||||||
|
|
||||||
@ -394,6 +418,61 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleChangeForCustomKeysWithHightlightInput = (values: ValueType<{ value: string }>) => {
|
||||||
|
if (values && Array.isArray(values) && values.length > 0) {
|
||||||
|
const customKeysWithHighlight = values.
|
||||||
|
map((value: MultiInputValue) => {
|
||||||
|
const formattedValue = value.value.trim();
|
||||||
|
return {value: formattedValue, label: formattedValue};
|
||||||
|
}).
|
||||||
|
filter((value) => value.value.length > 0);
|
||||||
|
this.setState({customKeysWithHighlight});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
customKeysWithHighlight: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChangeForCustomKeysWithHighlightInputValue = (value: string) => {
|
||||||
|
if (!value.includes(Constants.KeyCodes.COMMA[0])) {
|
||||||
|
this.setState({customKeysWithHighlightInputValue: value});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateCustomKeysWithHighlightWithInputValue = (newValue: State['customKeysWithHighlightInputValue']) => {
|
||||||
|
const unsavedCustomKeyWithHighlight = newValue?.trim()?.replace(COMMA_REGEX, '') ?? '';
|
||||||
|
|
||||||
|
if (unsavedCustomKeyWithHighlight.length > 0) {
|
||||||
|
const customKeysWithHighlight = [
|
||||||
|
...this.state.customKeysWithHighlight,
|
||||||
|
{
|
||||||
|
value: unsavedCustomKeyWithHighlight,
|
||||||
|
label: unsavedCustomKeyWithHighlight,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
customKeysWithHighlight,
|
||||||
|
customKeysWithHighlightInputValue: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleBlurForCustomKeysWithHighlightInput = () => {
|
||||||
|
this.updateCustomKeysWithHighlightWithInputValue(this.state.customKeysWithHighlightInputValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleOnKeydownForCustomKeysWithHighlightInput = (event: React.KeyboardEvent) => {
|
||||||
|
if (event.key === Constants.KeyCodes.COMMA[0] || event.key === Constants.KeyCodes.TAB[0]) {
|
||||||
|
this.updateCustomKeysWithHighlightWithInputValue(this.state.customKeysWithHighlightInputValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCloseSettingsModal = () => {
|
||||||
|
this.props.closeModal();
|
||||||
|
};
|
||||||
|
|
||||||
createPushNotificationSection = () => {
|
createPushNotificationSection = () => {
|
||||||
const active = this.props.activeSection === 'push';
|
const active = this.props.activeSection === 'push';
|
||||||
const inputs = [];
|
const inputs = [];
|
||||||
@ -824,7 +903,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
expandedSection = (
|
expandedSection = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords that trigger Notifications'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords That Trigger Notifications'})}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.handleSubmit}
|
submit={this.handleSubmit}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
@ -855,7 +934,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords that trigger Notifications'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords That Trigger Notifications'})}
|
||||||
section='keysWithNotification'
|
section='keysWithNotification'
|
||||||
active={isSectionExpanded}
|
active={isSectionExpanded}
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
@ -865,6 +944,140 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
/>);
|
/>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
createKeywordsWithHighlightSection = () => {
|
||||||
|
const isSectionExpanded = this.props.activeSection === 'keysWithHighlight';
|
||||||
|
|
||||||
|
let expandedSection = null;
|
||||||
|
if (isSectionExpanded) {
|
||||||
|
const inputs = [(
|
||||||
|
<div
|
||||||
|
key='userNotificationHighlightOption'
|
||||||
|
className='customKeywordsWithNotificationSubsection'
|
||||||
|
>
|
||||||
|
<label htmlFor='mentionKeysWithHighlightInput'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.keywordsWithHighlight.inputTitle'
|
||||||
|
defaultMessage='Enter non case-sensitive keywords, press Tab or use commas to separate them:'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<CreatableReactSelect
|
||||||
|
inputId='mentionKeysWithHighlightInput'
|
||||||
|
autoFocus={true}
|
||||||
|
isClearable={false}
|
||||||
|
isMulti={true}
|
||||||
|
styles={customKeywordsWithNotificationStyles}
|
||||||
|
className='multiInput'
|
||||||
|
placeholder=''
|
||||||
|
components={{
|
||||||
|
DropdownIndicator: () => null,
|
||||||
|
Menu: () => null,
|
||||||
|
MenuList: () => null,
|
||||||
|
}}
|
||||||
|
aria-labelledby='mentionKeysWithHighlightInput'
|
||||||
|
onChange={this.handleChangeForCustomKeysWithHightlightInput}
|
||||||
|
value={this.state.customKeysWithHighlight}
|
||||||
|
inputValue={this.state.customKeysWithHighlightInputValue}
|
||||||
|
onInputChange={this.handleChangeForCustomKeysWithHighlightInputValue}
|
||||||
|
onBlur={this.handleBlurForCustomKeysWithHighlightInput}
|
||||||
|
onKeyDown={this.handleOnKeydownForCustomKeysWithHighlightInput}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)];
|
||||||
|
|
||||||
|
const extraInfo = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.keywordsWithHighlight.extraInfo'
|
||||||
|
defaultMessage='These keywords will be shown to you with a highlight when anyone sends a message that includes them.'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expandedSection = (
|
||||||
|
<SettingItemMax
|
||||||
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithHighlight.title', defaultMessage: 'Keywords That Get Highlighted (Without Notifications)'})}
|
||||||
|
inputs={inputs}
|
||||||
|
submit={this.handleSubmit}
|
||||||
|
saving={this.state.isSaving}
|
||||||
|
serverError={this.state.serverError}
|
||||||
|
extraInfo={extraInfo}
|
||||||
|
updateSection={this.handleUpdateSection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let collapsedDescription = this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithHighlight.none', defaultMessage: 'None'});
|
||||||
|
if (!this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady && this.state.customKeysWithHighlight.length > 0) {
|
||||||
|
const customKeysWithHighlightStringArray = this.state.customKeysWithHighlight.map((key) => key.value);
|
||||||
|
collapsedDescription = customKeysWithHighlightStringArray.map((key) => `"${key}"`).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
const collapsedEditButtonWhenDisabled = (
|
||||||
|
<RestrictedIndicator
|
||||||
|
blocked={this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady}
|
||||||
|
feature={MattermostFeatures.HIGHLIGHT_WITHOUT_NOTIFICATION}
|
||||||
|
minimumPlanRequiredForFeature={LicenseSkus.Professional}
|
||||||
|
tooltipTitle={this.props.intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.disabledTooltipTitle',
|
||||||
|
defaultMessage: 'Professional feature',
|
||||||
|
})}
|
||||||
|
tooltipMessageBlocked={this.props.intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.disabledTooltipMessage',
|
||||||
|
defaultMessage:
|
||||||
|
'This feature is available on the Professional plan',
|
||||||
|
})}
|
||||||
|
titleAdminPreTrial={this.props.intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.userModal.titleAdminPreTrial',
|
||||||
|
defaultMessage: 'Highlight keywords without notifications with Mattermost Professional',
|
||||||
|
})}
|
||||||
|
messageAdminPreTrial={this.props.intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPreTrial',
|
||||||
|
defaultMessage: 'Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.',
|
||||||
|
})}
|
||||||
|
titleAdminPostTrial={this.props.intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.userModal.titleAdminPostTrial',
|
||||||
|
defaultMessage: 'Highlight keywords without notifications with Mattermost Professional',
|
||||||
|
})}
|
||||||
|
messageAdminPostTrial={this.props.intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPostTrial',
|
||||||
|
defaultMessage: 'Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.',
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
titleEndUser={this.props.intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.userModal.titleEndUser',
|
||||||
|
defaultMessage: 'Highlight keywords without notifications with Mattermost Professional',
|
||||||
|
})}
|
||||||
|
messageEndUser={this.props.intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'user.settings.notifications.keywordsWithHighlight.userModal.messageEndUser',
|
||||||
|
defaultMessage: 'Get the ability to passively highlight keywords that you care about.{br}{br}Request your admin to upgrade to Mattermost Professional to access this feature.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
br: <br/>,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
ctaExtraContent={
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.keywordsWithHighlight.professional'
|
||||||
|
defaultMessage='Professional'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
clickCallback={this.handleCloseSettingsModal}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingItem
|
||||||
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithHighlight.title', defaultMessage: 'Keywords That Get Highlighted (Without Notifications)'})}
|
||||||
|
section='keysWithHighlight'
|
||||||
|
active={isSectionExpanded}
|
||||||
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
|
describe={collapsedDescription}
|
||||||
|
updateSection={this.handleUpdateSection}
|
||||||
|
max={expandedSection}
|
||||||
|
isDisabled={this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady}
|
||||||
|
collapsedEditButtonWhenDisabled={collapsedEditButtonWhenDisabled}
|
||||||
|
/>);
|
||||||
|
};
|
||||||
|
|
||||||
createCommentsSection = () => {
|
createCommentsSection = () => {
|
||||||
const serverError = this.state.serverError;
|
const serverError = this.state.serverError;
|
||||||
|
|
||||||
@ -887,7 +1100,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
<legend className='form-legend hidden-label'>
|
<legend className='form-legend hidden-label'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.notifications.comments'
|
id='user.settings.notifications.comments'
|
||||||
defaultMessage='Reply notifications'
|
defaultMessage='Reply Notifications'
|
||||||
/>
|
/>
|
||||||
</legend>
|
</legend>
|
||||||
<div className='radio'>
|
<div className='radio'>
|
||||||
@ -951,7 +1164,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
max = (
|
max = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.comments', defaultMessage: 'Reply notifications'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.comments', defaultMessage: 'Reply Notifications'})}
|
||||||
extraInfo={extraInfo}
|
extraInfo={extraInfo}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.handleSubmit}
|
submit={this.handleSubmit}
|
||||||
@ -1046,6 +1259,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
const pushNotificationSection = this.createPushNotificationSection();
|
const pushNotificationSection = this.createPushNotificationSection();
|
||||||
const keywordsWithNotificationSection = this.createKeywordsWithNotificationSection();
|
const keywordsWithNotificationSection = this.createKeywordsWithNotificationSection();
|
||||||
|
const keywordsWithHighlightSection = this.createKeywordsWithHighlightSection();
|
||||||
const commentsSection = this.createCommentsSection();
|
const commentsSection = this.createCommentsSection();
|
||||||
const autoResponderSection = this.createAutoResponderSection();
|
const autoResponderSection = this.createAutoResponderSection();
|
||||||
|
|
||||||
@ -1110,50 +1324,68 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
<div className='divider-dark first'/>
|
<div className='divider-dark first'/>
|
||||||
<DesktopNotificationSettings
|
<DesktopNotificationSettings
|
||||||
|
active={this.props.activeSection === 'desktop'}
|
||||||
|
updateSection={this.handleUpdateSection}
|
||||||
|
onSubmit={this.handleSubmit}
|
||||||
|
onCancel={this.handleCancel}
|
||||||
|
saving={this.state.isSaving}
|
||||||
|
error={this.state.serverError}
|
||||||
|
setParentState={this.setStateValue}
|
||||||
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
|
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
||||||
activity={this.state.desktopActivity}
|
activity={this.state.desktopActivity}
|
||||||
threads={this.state.desktopThreads}
|
threads={this.state.desktopThreads}
|
||||||
sound={this.state.desktopSound}
|
sound={this.state.desktopSound}
|
||||||
callsSound={this.state.callsDesktopSound}
|
callsSound={this.state.callsDesktopSound}
|
||||||
updateSection={this.handleUpdateSection}
|
|
||||||
setParentState={this.setStateValue}
|
|
||||||
submit={this.handleSubmit}
|
|
||||||
saving={this.state.isSaving}
|
|
||||||
cancel={this.handleCancel}
|
|
||||||
error={this.state.serverError}
|
|
||||||
active={this.props.activeSection === 'desktop'}
|
|
||||||
selectedSound={this.state.desktopNotificationSound || 'default'}
|
selectedSound={this.state.desktopNotificationSound || 'default'}
|
||||||
callsSelectedSound={this.state.callsNotificationSound || 'default'}
|
callsSelectedSound={this.state.callsNotificationSound || 'default'}
|
||||||
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
|
||||||
isCallsRingingEnabled={this.props.isCallsRingingEnabled}
|
isCallsRingingEnabled={this.props.isCallsRingingEnabled}
|
||||||
/>
|
/>
|
||||||
<div className='divider-light'/>
|
<div className='divider-light'/>
|
||||||
<EmailNotificationSetting
|
<EmailNotificationSetting
|
||||||
activeSection={this.props.activeSection}
|
active={this.props.activeSection === 'email'}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
enableEmail={this.state.enableEmail === 'true'}
|
|
||||||
onSubmit={this.handleSubmit}
|
onSubmit={this.handleSubmit}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
onChange={this.handleEmailRadio}
|
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
serverError={this.state.serverError}
|
error={this.state.serverError}
|
||||||
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
|
||||||
setParentState={this.setStateValue}
|
setParentState={this.setStateValue}
|
||||||
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
|
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
||||||
|
enableEmail={this.state.enableEmail === 'true'}
|
||||||
|
onChange={this.handleEmailRadio}
|
||||||
threads={this.state.emailThreads || ''}
|
threads={this.state.emailThreads || ''}
|
||||||
/>
|
/>
|
||||||
<div className='divider-light'/>
|
<div className='divider-light'/>
|
||||||
{pushNotificationSection}
|
{pushNotificationSection}
|
||||||
<div className='divider-light'/>
|
<div className='divider-light'/>
|
||||||
{keywordsWithNotificationSection}
|
{keywordsWithNotificationSection}
|
||||||
|
{(!this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady) && (
|
||||||
|
<>
|
||||||
|
<div className='divider-light'/>
|
||||||
|
{keywordsWithHighlightSection}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className='divider-light'/>
|
<div className='divider-light'/>
|
||||||
{!this.props.isCollapsedThreadsEnabled && (
|
{!this.props.isCollapsedThreadsEnabled && (
|
||||||
<>
|
<>
|
||||||
{commentsSection}
|
|
||||||
<div className='divider-light'/>
|
<div className='divider-light'/>
|
||||||
|
{commentsSection}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{this.props.enableAutoResponder && (
|
{this.props.enableAutoResponder && (
|
||||||
autoResponderSection
|
<>
|
||||||
|
<div className='divider-light'/>
|
||||||
|
{autoResponderSection}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* We placed the disabled items in the last */}
|
||||||
|
{(this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady) && (
|
||||||
|
<>
|
||||||
|
<div className='divider-light'/>
|
||||||
|
{keywordsWithHighlightSection}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<div className='divider-dark'/>
|
<div className='divider-dark'/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,10 +53,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="password"
|
section="password"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
@ -97,16 +94,13 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email and Password"
|
defaultMessage="Email and Password"
|
||||||
id="user.settings.security.emailPwd"
|
id="user.settings.security.emailPwd"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="signin"
|
section="signin"
|
||||||
title="Sign-in Method"
|
title="Sign-in Method"
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
@ -115,7 +109,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link"
|
className="security-links color--link"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -140,8 +134,8 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View Access History"
|
defaultMessage="View Access History"
|
||||||
id="user.settings.security.viewHistory"
|
id="user.settings.security.viewHistory"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link mt-2"
|
className="security-links color--link mt-2"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -162,7 +156,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View and Log Out of Active Sessions"
|
defaultMessage="View and Log Out of Active Sessions"
|
||||||
id="user.settings.security.logoutActiveSessions"
|
id="user.settings.security.logoutActiveSessions"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -220,10 +214,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="password"
|
section="password"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
@ -264,16 +255,13 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email and Password"
|
defaultMessage="Email and Password"
|
||||||
id="user.settings.security.emailPwd"
|
id="user.settings.security.emailPwd"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="signin"
|
section="signin"
|
||||||
title="Sign-in Method"
|
title="Sign-in Method"
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
@ -282,7 +270,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link"
|
className="security-links color--link"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -307,8 +295,8 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View Access History"
|
defaultMessage="View Access History"
|
||||||
id="user.settings.security.viewHistory"
|
id="user.settings.security.viewHistory"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link mt-2"
|
className="security-links color--link mt-2"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -329,7 +317,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View and Log Out of Active Sessions"
|
defaultMessage="View and Log Out of Active Sessions"
|
||||||
id="user.settings.security.logoutActiveSessions"
|
id="user.settings.security.logoutActiveSessions"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -387,10 +375,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="password"
|
section="password"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
@ -431,16 +416,13 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email and Password"
|
defaultMessage="Email and Password"
|
||||||
id="user.settings.security.emailPwd"
|
id="user.settings.security.emailPwd"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="signin"
|
section="signin"
|
||||||
title="Sign-in Method"
|
title="Sign-in Method"
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
@ -449,7 +431,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link"
|
className="security-links color--link"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -474,8 +456,8 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View Access History"
|
defaultMessage="View Access History"
|
||||||
id="user.settings.security.viewHistory"
|
id="user.settings.security.viewHistory"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link mt-2"
|
className="security-links color--link mt-2"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -496,7 +478,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View and Log Out of Active Sessions"
|
defaultMessage="View and Log Out of Active Sessions"
|
||||||
id="user.settings.security.logoutActiveSessions"
|
id="user.settings.security.logoutActiveSessions"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -554,10 +536,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="password"
|
section="password"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
@ -598,16 +577,13 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
active={false}
|
active={false}
|
||||||
areAllSectionsInactive={false}
|
areAllSectionsInactive={false}
|
||||||
containerStyle=""
|
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email and Password"
|
defaultMessage="Email and Password"
|
||||||
id="user.settings.security.emailPwd"
|
id="user.settings.security.emailPwd"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
infoPosition="bottom"
|
|
||||||
max={null}
|
max={null}
|
||||||
saving={false}
|
|
||||||
section="signin"
|
section="signin"
|
||||||
title="Sign-in Method"
|
title="Sign-in Method"
|
||||||
updateSection={[Function]}
|
updateSection={[Function]}
|
||||||
@ -616,7 +592,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link"
|
className="security-links color--link"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -641,8 +617,8 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View Access History"
|
defaultMessage="View Access History"
|
||||||
id="user.settings.security.viewHistory"
|
id="user.settings.security.viewHistory"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="security-links color--link mt-2"
|
className="security-links color--link mt-2"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@ -663,7 +639,7 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
defaultMessage="View and Log Out of Active Sessions"
|
defaultMessage="View and Log Out of Active Sessions"
|
||||||
id="user.settings.security.logoutActiveSessions"
|
id="user.settings.security.logoutActiveSessions"
|
||||||
/>
|
/>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
exports[`MfaSection rendering should render nothing when MFA is not available 1`] = `""`;
|
exports[`MfaSection rendering should render nothing when MFA is not available 1`] = `""`;
|
||||||
|
|
||||||
exports[`MfaSection rendering when section is collapsed and MFA is active 1`] = `
|
exports[`MfaSection rendering when section is collapsed and MFA is active 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Active"
|
defaultMessage="Active"
|
||||||
@ -22,7 +22,7 @@ exports[`MfaSection rendering when section is collapsed and MFA is active 1`] =
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`MfaSection rendering when section is collapsed and MFA is not active 1`] = `
|
exports[`MfaSection rendering when section is collapsed and MFA is not active 1`] = `
|
||||||
<Connect(SettingItemMin)
|
<SettingItemMin
|
||||||
describe={
|
describe={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Inactive"
|
defaultMessage="Inactive"
|
||||||
|
@ -7,7 +7,7 @@ import {FormattedMessage} from 'react-intl';
|
|||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
import {getHistory} from 'utils/browser_history';
|
import {getHistory} from 'utils/browser_history';
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import FormattedMarkdownMessage from 'components/formatted_markdown_message';
|
|||||||
import SaveButton from 'components/save_button';
|
import SaveButton from 'components/save_button';
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
import WarningIcon from 'components/widgets/icons/fa_warning_icon';
|
import WarningIcon from 'components/widgets/icons/fa_warning_icon';
|
||||||
|
|
||||||
import {Constants, DeveloperLinks} from 'utils/constants';
|
import {Constants, DeveloperLinks} from 'utils/constants';
|
||||||
|
@ -13,7 +13,7 @@ import {Preferences} from 'mattermost-redux/constants';
|
|||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
import {localizeMessage} from 'utils/utils';
|
import {localizeMessage} from 'utils/utils';
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import {Preferences} from 'mattermost-redux/constants';
|
|||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min/setting_item_min';
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
import {a11yFocus} from 'utils/utils';
|
import {a11yFocus} from 'utils/utils';
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
exports[`components/MenuItemToggleModalRedux should match snapshot with extra text 1`] = `
|
exports[`components/MenuItemToggleModalRedux should match snapshot with extra text 1`] = `
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className="MenuItem__with-help"
|
className="MenuItem__with-help"
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -22,6 +22,6 @@ exports[`components/MenuItemToggleModalRedux should match snapshot with extra te
|
|||||||
>
|
>
|
||||||
Extra text
|
Extra text
|
||||||
</span>
|
</span>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
`;
|
`;
|
||||||
|
@ -19,7 +19,7 @@ describe('components/MenuItemToggleModalRedux', () => {
|
|||||||
|
|
||||||
expect(wrapper).toMatchInlineSnapshot(`
|
expect(wrapper).toMatchInlineSnapshot(`
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Connect(ToggleModalButton)
|
<ToggleModalButton
|
||||||
className=""
|
className=""
|
||||||
dialogProps={
|
dialogProps={
|
||||||
Object {
|
Object {
|
||||||
@ -34,7 +34,7 @@ describe('components/MenuItemToggleModalRedux', () => {
|
|||||||
>
|
>
|
||||||
Whatever
|
Whatever
|
||||||
</span>
|
</span>
|
||||||
</Connect(ToggleModalButton)>
|
</ToggleModalButton>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
|
||||||
.RestrictedIndicator__button {
|
.RestrictedIndicator__button {
|
||||||
padding: 0 !important;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.RestrictedIndicator__icon-tooltip {
|
.RestrictedIndicator__icon-tooltip {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, {useCallback} from 'react';
|
import React, {useCallback, type ReactNode} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import type {MessageDescriptor} from 'react-intl';
|
import type {MessageDescriptor} from 'react-intl';
|
||||||
|
|
||||||
@ -16,27 +16,27 @@ import {Constants, LicenseSkus, ModalIdentifiers} from 'utils/constants';
|
|||||||
|
|
||||||
import './restricted_indicator.scss';
|
import './restricted_indicator.scss';
|
||||||
|
|
||||||
type RestrictedIndicatorProps = {
|
type Props = {
|
||||||
useModal?: boolean;
|
useModal?: boolean;
|
||||||
titleAdminPreTrial?: string;
|
|
||||||
messageAdminPreTrial?: string | React.ReactNode;
|
|
||||||
titleAdminPostTrial?: string;
|
|
||||||
messageAdminPostTrial?: string | React.ReactNode;
|
|
||||||
titleEndUser?: string;
|
|
||||||
messageEndUser?: string | React.ReactNode;
|
|
||||||
blocked?: boolean;
|
blocked?: boolean;
|
||||||
tooltipTitle?: string;
|
|
||||||
tooltipMessage?: string;
|
|
||||||
tooltipMessageBlocked?: string | MessageDescriptor;
|
|
||||||
ctaExtraContent?: React.ReactNode;
|
|
||||||
clickCallback?: () => void;
|
|
||||||
customSecondaryButtonInModal?: {msg: string; action: () => void};
|
|
||||||
feature?: string;
|
feature?: string;
|
||||||
minimumPlanRequiredForFeature?: string;
|
minimumPlanRequiredForFeature?: string;
|
||||||
|
tooltipTitle?: ReactNode;
|
||||||
|
tooltipMessage?: ReactNode;
|
||||||
|
tooltipMessageBlocked?: string | MessageDescriptor;
|
||||||
|
titleAdminPreTrial?: ReactNode;
|
||||||
|
messageAdminPreTrial?: ReactNode;
|
||||||
|
titleAdminPostTrial?: ReactNode;
|
||||||
|
messageAdminPostTrial?: ReactNode;
|
||||||
|
titleEndUser?: ReactNode;
|
||||||
|
messageEndUser?: ReactNode;
|
||||||
|
ctaExtraContent?: ReactNode;
|
||||||
|
clickCallback?: () => void;
|
||||||
|
customSecondaryButtonInModal?: {msg: string; action: () => void};
|
||||||
}
|
}
|
||||||
|
|
||||||
function capitalizeFirstLetter(s: string) {
|
function capitalizeFirstLetter(s: string) {
|
||||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
return s?.charAt(0)?.toUpperCase() + s?.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RestrictedIndicator = ({
|
const RestrictedIndicator = ({
|
||||||
@ -56,7 +56,7 @@ const RestrictedIndicator = ({
|
|||||||
customSecondaryButtonInModal,
|
customSecondaryButtonInModal,
|
||||||
feature,
|
feature,
|
||||||
minimumPlanRequiredForFeature,
|
minimumPlanRequiredForFeature,
|
||||||
}: RestrictedIndicatorProps) => {
|
}: Props) => {
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
|
|
||||||
const getTooltipMessageBlocked = useCallback(() => {
|
const getTooltipMessageBlocked = useCallback(() => {
|
||||||
@ -92,7 +92,10 @@ const RestrictedIndicator = ({
|
|||||||
delayShow={Constants.OVERLAY_TIME_DELAY}
|
delayShow={Constants.OVERLAY_TIME_DELAY}
|
||||||
placement='right'
|
placement='right'
|
||||||
overlay={(
|
overlay={(
|
||||||
<Tooltip className='RestrictedIndicator__icon-tooltip'>
|
<Tooltip
|
||||||
|
id={`${feature}-tooltip`}
|
||||||
|
className='RestrictedIndicator__icon-tooltip'
|
||||||
|
>
|
||||||
<span className='title'>
|
<span className='title'>
|
||||||
{tooltipTitle || formatMessage({id: 'restricted_indicator.tooltip.title', defaultMessage: '{minimumPlanRequiredForFeature} feature'}, {minimumPlanRequiredForFeature: capitalizeFirstLetter(minimumPlanRequiredForFeature!)})}
|
{tooltipTitle || formatMessage({id: 'restricted_indicator.tooltip.title', defaultMessage: '{minimumPlanRequiredForFeature} feature'}, {minimumPlanRequiredForFeature: capitalizeFirstLetter(minimumPlanRequiredForFeature!)})}
|
||||||
</span>
|
</span>
|
||||||
@ -107,27 +110,29 @@ const RestrictedIndicator = ({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{useModal && blocked ? (
|
{useModal && blocked ? (
|
||||||
<ToggleModalButton
|
<span>
|
||||||
id={`${feature}-restricted-indicator`.replaceAll('.', '_')}
|
<ToggleModalButton
|
||||||
className='RestrictedIndicator__button'
|
id={`${feature}-restricted-indicator`?.replaceAll('.', '_')}
|
||||||
modalId={ModalIdentifiers.FEATURE_RESTRICTED_MODAL}
|
className='RestrictedIndicator__button'
|
||||||
dialogType={FeatureRestrictedModal}
|
modalId={ModalIdentifiers.FEATURE_RESTRICTED_MODAL}
|
||||||
onClick={handleClickCallback}
|
dialogType={FeatureRestrictedModal}
|
||||||
dialogProps={{
|
onClick={handleClickCallback}
|
||||||
titleAdminPreTrial,
|
dialogProps={{
|
||||||
messageAdminPreTrial,
|
titleAdminPreTrial,
|
||||||
titleAdminPostTrial,
|
messageAdminPreTrial,
|
||||||
messageAdminPostTrial,
|
titleAdminPostTrial,
|
||||||
titleEndUser,
|
messageAdminPostTrial,
|
||||||
messageEndUser,
|
titleEndUser,
|
||||||
customSecondaryButton: customSecondaryButtonInModal,
|
messageEndUser,
|
||||||
feature,
|
customSecondaryButton: customSecondaryButtonInModal,
|
||||||
minimumPlanRequiredForFeature,
|
feature,
|
||||||
}}
|
minimumPlanRequiredForFeature,
|
||||||
>
|
}}
|
||||||
{icon}
|
>
|
||||||
{ctaExtraContent}
|
{icon}
|
||||||
</ToggleModalButton>
|
{ctaExtraContent}
|
||||||
|
</ToggleModalButton>
|
||||||
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<div className='RestrictedIndicator__content'>
|
<div className='RestrictedIndicator__content'>
|
||||||
{icon}
|
{icon}
|
||||||
|
@ -5428,7 +5428,7 @@
|
|||||||
"user.settings.notifications.autoResponderHint": "Set a custom message that will be automatically sent in response to Direct Messages. Mentions in Public and Private Channels will not trigger the automated reply. Enabling Automatic Replies sets your status to Out of Office and disables email and push notifications.",
|
"user.settings.notifications.autoResponderHint": "Set a custom message that will be automatically sent in response to Direct Messages. Mentions in Public and Private Channels will not trigger the automated reply. Enabling Automatic Replies sets your status to Out of Office and disables email and push notifications.",
|
||||||
"user.settings.notifications.autoResponderPlaceholder": "Message",
|
"user.settings.notifications.autoResponderPlaceholder": "Message",
|
||||||
"user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\", \"@all\", \"@here\"",
|
"user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\", \"@all\", \"@here\"",
|
||||||
"user.settings.notifications.comments": "Reply notifications",
|
"user.settings.notifications.comments": "Reply Notifications",
|
||||||
"user.settings.notifications.commentsAny": "Trigger notifications on messages in reply threads that I start or participate in",
|
"user.settings.notifications.commentsAny": "Trigger notifications on messages in reply threads that I start or participate in",
|
||||||
"user.settings.notifications.commentsInfo": "In addition to notifications for when you're mentioned, select if you would like to receive notifications on reply threads.",
|
"user.settings.notifications.commentsInfo": "In addition to notifications for when you're mentioned, select if you would like to receive notifications on reply threads.",
|
||||||
"user.settings.notifications.commentsNever": "Do not trigger notifications on messages in reply threads unless I'm mentioned",
|
"user.settings.notifications.commentsNever": "Do not trigger notifications on messages in reply threads unless I'm mentioned",
|
||||||
@ -5457,8 +5457,21 @@
|
|||||||
"user.settings.notifications.header": "Notifications",
|
"user.settings.notifications.header": "Notifications",
|
||||||
"user.settings.notifications.icon": "Notification Settings Icon",
|
"user.settings.notifications.icon": "Notification Settings Icon",
|
||||||
"user.settings.notifications.info": "Desktop notifications are available on Edge, Firefox, Safari, Chrome and Mattermost Desktop Apps.",
|
"user.settings.notifications.info": "Desktop notifications are available on Edge, Firefox, Safari, Chrome and Mattermost Desktop Apps.",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.disabledTooltipMessage": "This feature is available on the Professional plan",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.disabledTooltipTitle": "Professional feature",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.extraInfo": "These keywords will be shown to you with a highlight when anyone sends a message that includes them.",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.inputTitle": "Enter non case-sensitive keywords, press Tab or use commas to separate them:",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.none": "None",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.professional": "Professional",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.title": "Keywords That Get Highlighted (Without Notifications)",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPostTrial": "Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPreTrial": "Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.userModal.messageEndUser": "Get the ability to passively highlight keywords that you care about.{br}{br}Request your admin to upgrade to Mattermost Professional to access this feature.",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.userModal.titleAdminPostTrial": "Highlight keywords without notifications with Mattermost Professional",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.userModal.titleAdminPreTrial": "Highlight keywords without notifications with Mattermost Professional",
|
||||||
|
"user.settings.notifications.keywordsWithHighlight.userModal.titleEndUser": "Highlight keywords without notifications with Mattermost Professional",
|
||||||
"user.settings.notifications.keywordsWithNotification.extraInfo": "Notifications are triggered when someone sends a message that includes your username (\"@{username}\") or any of the options selected above.",
|
"user.settings.notifications.keywordsWithNotification.extraInfo": "Notifications are triggered when someone sends a message that includes your username (\"@{username}\") or any of the options selected above.",
|
||||||
"user.settings.notifications.keywordsWithNotification.title": "Keywords that trigger Notifications",
|
"user.settings.notifications.keywordsWithNotification.title": "Keywords That Trigger Notifications",
|
||||||
"user.settings.notifications.learnMore": "<a>Learn more about notifications</a>",
|
"user.settings.notifications.learnMore": "<a>Learn more about notifications</a>",
|
||||||
"user.settings.notifications.never": "Never",
|
"user.settings.notifications.never": "Never",
|
||||||
"user.settings.notifications.off": "Off",
|
"user.settings.notifications.off": "Off",
|
||||||
@ -5637,6 +5650,7 @@
|
|||||||
"webapp.mattermost.feature.create_multiple_teams": "Create Multiple Teams",
|
"webapp.mattermost.feature.create_multiple_teams": "Create Multiple Teams",
|
||||||
"webapp.mattermost.feature.custom_user_groups": "Custom User groups",
|
"webapp.mattermost.feature.custom_user_groups": "Custom User groups",
|
||||||
"webapp.mattermost.feature.guest_accounts": "Guest Accounts",
|
"webapp.mattermost.feature.guest_accounts": "Guest Accounts",
|
||||||
|
"webapp.mattermost.feature.highlight_without_notification": "Keywords Highlight Without Notification",
|
||||||
"webapp.mattermost.feature.playbooks_retro": "Playbooks Retrospective",
|
"webapp.mattermost.feature.playbooks_retro": "Playbooks Retrospective",
|
||||||
"webapp.mattermost.feature.start_call": "Start call",
|
"webapp.mattermost.feature.start_call": "Start call",
|
||||||
"webapp.mattermost.feature.unlimited_file_storage": "Unlimited File Storage",
|
"webapp.mattermost.feature.unlimited_file_storage": "Unlimited File Storage",
|
||||||
|
@ -224,6 +224,26 @@ export const getCurrentUserMentionKeys: (state: GlobalState) => UserMentionKey[]
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export type HighlightWithoutNotificationKey = {
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHighlightWithoutNotificationKeys: (state: GlobalState) => HighlightWithoutNotificationKey[] = createSelector(
|
||||||
|
'getHighlightWithoutNotificationKeys',
|
||||||
|
getCurrentUser,
|
||||||
|
(user: UserProfile) => {
|
||||||
|
const highlightKeys: HighlightWithoutNotificationKey[] = [];
|
||||||
|
|
||||||
|
if (user?.notify_props?.highlight_keys?.length > 0) {
|
||||||
|
user.notify_props.highlight_keys.split(',').forEach((key) => {
|
||||||
|
highlightKeys.push({key});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return highlightKeys;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const getProfileSetInCurrentChannel: (state: GlobalState) => Set<UserProfile['id']> = createSelector(
|
export const getProfileSetInCurrentChannel: (state: GlobalState) => Set<UserProfile['id']> = createSelector(
|
||||||
'getProfileSetInCurrentChannel',
|
'getProfileSetInCurrentChannel',
|
||||||
getCurrentChannelId,
|
getCurrentChannelId,
|
||||||
|
@ -102,6 +102,7 @@ class TestHelper {
|
|||||||
email: 'false',
|
email: 'false',
|
||||||
first_name: 'false',
|
first_name: 'false',
|
||||||
mark_unread: 'mention',
|
mark_unread: 'mention',
|
||||||
|
highlight_keys: '',
|
||||||
mention_keys: '',
|
mention_keys: '',
|
||||||
push: 'none',
|
push: 'none',
|
||||||
push_status: 'offline',
|
push_status: 'offline',
|
||||||
@ -144,6 +145,7 @@ class TestHelper {
|
|||||||
first_name: 'false',
|
first_name: 'false',
|
||||||
mark_unread: 'mention',
|
mark_unread: 'mention',
|
||||||
mention_keys: '',
|
mention_keys: '',
|
||||||
|
highlight_keys: '',
|
||||||
push: 'none',
|
push: 'none',
|
||||||
push_status: 'offline',
|
push_status: 'offline',
|
||||||
},
|
},
|
||||||
@ -472,6 +474,7 @@ class TestHelper {
|
|||||||
first_name: 'true',
|
first_name: 'true',
|
||||||
channel: 'true',
|
channel: 'true',
|
||||||
mention_keys: '',
|
mention_keys: '',
|
||||||
|
highlight_keys: '',
|
||||||
...override,
|
...override,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -134,7 +134,6 @@ exports[`plugins/PostMessageView should match snapshot with no extended post typ
|
|||||||
"onImageLoaded": [Function],
|
"onImageLoaded": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mentionKeys={Array []}
|
|
||||||
message="this is some text"
|
message="this is some text"
|
||||||
options={Object {}}
|
options={Object {}}
|
||||||
post={
|
post={
|
||||||
|
@ -54,6 +54,13 @@ del .group-mention-link:focus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.non-notification-highlight {
|
||||||
|
padding: 0 1px;
|
||||||
|
background-color: var(--mention-highlight-bg);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--mention-highlight-link);
|
||||||
|
}
|
||||||
|
|
||||||
.group-mention-link {
|
.group-mention-link {
|
||||||
color: var(--link-color);
|
color: var(--link-color);
|
||||||
}
|
}
|
||||||
|
@ -194,13 +194,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.section-min__edit {
|
.section-min__edit {
|
||||||
position: relative;
|
span {
|
||||||
top: 0;
|
display: none;
|
||||||
right: 0;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
button {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,23 +294,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings-content {
|
.settings-content {
|
||||||
.section-min__edit {
|
|
||||||
text-align: left;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
button {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
align-items: center;
|
|
||||||
color: rgba(var(--center-channel-color-rgb), 0.75);
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fa {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.minimize-settings {
|
&.minimize-settings {
|
||||||
display: none;
|
display: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -658,9 +658,42 @@
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d-flex {
|
> .secion-min__header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.isDisabled {
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RestrictedIndicator__icon-tooltip-container {
|
||||||
|
flex: unset;
|
||||||
|
align-self: flex-start;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 6px;
|
||||||
|
background-color: rgba(var(--button-bg-rgb), 0.08);
|
||||||
|
border-radius: 12px;
|
||||||
|
color: var(--button-bg);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-min__title {
|
.section-min__title {
|
||||||
@ -669,18 +702,15 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
|
||||||
|
&.isDisabled {
|
||||||
|
color: rgba(var(--center-channel-color-rgb), 0.64);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-min__edit {
|
.section-min__edit {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
.fa {
|
|
||||||
display: none;
|
|
||||||
margin-right: 5px;
|
|
||||||
font-size: 12px;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-min__describe {
|
.section-min__describe {
|
||||||
@ -689,4 +719,8 @@
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
|
||||||
|
&.isDisabled {
|
||||||
|
color: rgba(var(--center-channel-color-rgb), 0.4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ export type PluginComponent = {
|
|||||||
filter?: (id: string) => boolean;
|
filter?: (id: string) => boolean;
|
||||||
action?: (...args: any) => void; // TODO Add more concrete types?
|
action?: (...args: any) => void; // TODO Add more concrete types?
|
||||||
shouldRender?: (state: GlobalState) => boolean;
|
shouldRender?: (state: GlobalState) => boolean;
|
||||||
|
hook?: (post: Post, message?: string) => string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AppBarComponent = PluginComponent & {
|
export type AppBarComponent = PluginComponent & {
|
||||||
|
@ -507,6 +507,7 @@ export const MattermostFeatures = {
|
|||||||
ALL_ENTERPRISE_FEATURES: 'mattermost.feature.all_enterprise',
|
ALL_ENTERPRISE_FEATURES: 'mattermost.feature.all_enterprise',
|
||||||
UPGRADE_DOWNGRADED_WORKSPACE: 'mattermost.feature.upgrade_downgraded_workspace',
|
UPGRADE_DOWNGRADED_WORKSPACE: 'mattermost.feature.upgrade_downgraded_workspace',
|
||||||
PLUGIN_FEATURE: 'mattermost.feature.plugin',
|
PLUGIN_FEATURE: 'mattermost.feature.plugin',
|
||||||
|
HIGHLIGHT_WITHOUT_NOTIFICATION: 'mattermost.feature.highlight_without_notification',
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum LicenseSkus {
|
export enum LicenseSkus {
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
|
import type {Product} from '@mattermost/types/cloud';
|
||||||
import type {ClientLicense} from '@mattermost/types/config';
|
import type {ClientLicense} from '@mattermost/types/config';
|
||||||
|
|
||||||
import {LicenseSkus} from 'utils/constants';
|
import {CloudProducts, LicenseSkus, SelfHostedProducts} from 'utils/constants';
|
||||||
|
|
||||||
const LICENSE_EXPIRY_NOTIFICATION = 1000 * 60 * 60 * 24 * 60; // 60 days
|
const LICENSE_EXPIRY_NOTIFICATION = 1000 * 60 * 60 * 24 * 60; // 60 days
|
||||||
const LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 10; // 10 days
|
const LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 10; // 10 days
|
||||||
@ -103,3 +104,14 @@ export const licenseSKUWithFirstLetterCapitalized = (license: ClientLicense) =>
|
|||||||
const sku = license.SkuShortName;
|
const sku = license.SkuShortName;
|
||||||
return sku.charAt(0).toUpperCase() + sku.slice(1);
|
return sku.charAt(0).toUpperCase() + sku.slice(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function isEnterpriseOrCloudOrSKUStarterFree(license: ClientLicense, subscriptionProduct: Product | undefined, isEnterpriseReady: boolean) {
|
||||||
|
const isCloud = license?.Cloud === 'true';
|
||||||
|
const isCloudStarterFree = isCloud && subscriptionProduct?.sku === CloudProducts.STARTER;
|
||||||
|
|
||||||
|
const isSelfHostedStarter = isEnterpriseReady && (license.IsLicensed === 'false');
|
||||||
|
|
||||||
|
const isStarterSKULicense = license.IsLicensed === 'true' && license.SelfHostedProducts === SelfHostedProducts.STARTER;
|
||||||
|
|
||||||
|
return isCloudStarterFree || isSelfHostedStarter || isStarterSKULicense;
|
||||||
|
}
|
||||||
|
@ -26,6 +26,8 @@ export function mapFeatureIdToTranslation(id: string, formatMessage: Function):
|
|||||||
return formatMessage({id: 'webapp.mattermost.feature.all_enterprise', defaultMessage: 'All Enterprise features'});
|
return formatMessage({id: 'webapp.mattermost.feature.all_enterprise', defaultMessage: 'All Enterprise features'});
|
||||||
case MattermostFeatures.UPGRADE_DOWNGRADED_WORKSPACE:
|
case MattermostFeatures.UPGRADE_DOWNGRADED_WORKSPACE:
|
||||||
return formatMessage({id: 'webapp.mattermost.feature.upgrade_downgraded_workspace', defaultMessage: 'Revert the workspace to a paid plan'});
|
return formatMessage({id: 'webapp.mattermost.feature.upgrade_downgraded_workspace', defaultMessage: 'Revert the workspace to a paid plan'});
|
||||||
|
case MattermostFeatures.HIGHLIGHT_WITHOUT_NOTIFICATION:
|
||||||
|
return formatMessage({id: 'webapp.mattermost.feature.highlight_without_notification', defaultMessage: 'Keywords Highlight Without Notification'});
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,9 @@ describe('Utils.Route', () => {
|
|||||||
comments: 'never',
|
comments: 'never',
|
||||||
first_name: 'true',
|
first_name: 'true',
|
||||||
channel: 'true',
|
channel: 'true',
|
||||||
mention_keys: ''},
|
mention_keys: '',
|
||||||
|
highlight_keys: '',
|
||||||
|
},
|
||||||
last_password_update: 0,
|
last_password_update: 0,
|
||||||
last_picture_update: 0,
|
last_picture_update: 0,
|
||||||
locale: '',
|
locale: '',
|
||||||
@ -83,7 +85,8 @@ describe('Utils.Route', () => {
|
|||||||
position: '',
|
position: '',
|
||||||
roles: '',
|
roles: '',
|
||||||
props: {userid: '121'},
|
props: {userid: '121'},
|
||||||
notify_props: {desktop: 'default',
|
notify_props: {
|
||||||
|
desktop: 'default',
|
||||||
desktop_sound: 'false',
|
desktop_sound: 'false',
|
||||||
calls_desktop_sound: 'true',
|
calls_desktop_sound: 'true',
|
||||||
email: 'true',
|
email: 'true',
|
||||||
@ -93,7 +96,9 @@ describe('Utils.Route', () => {
|
|||||||
comments: 'never',
|
comments: 'never',
|
||||||
first_name: 'true',
|
first_name: 'true',
|
||||||
channel: 'true',
|
channel: 'true',
|
||||||
mention_keys: ''},
|
mention_keys: '',
|
||||||
|
highlight_keys: '',
|
||||||
|
},
|
||||||
last_password_update: 0,
|
last_password_update: 0,
|
||||||
last_picture_update: 0,
|
last_picture_update: 0,
|
||||||
locale: '',
|
locale: '',
|
||||||
|
@ -68,6 +68,7 @@ export class TestHelper {
|
|||||||
first_name: 'false',
|
first_name: 'false',
|
||||||
mark_unread: 'mention',
|
mark_unread: 'mention',
|
||||||
mention_keys: '',
|
mention_keys: '',
|
||||||
|
highlight_keys: '',
|
||||||
push: 'none',
|
push: 'none',
|
||||||
push_status: 'offline',
|
push_status: 'offline',
|
||||||
},
|
},
|
||||||
|
@ -14,7 +14,9 @@ import {
|
|||||||
highlightSearchTerms,
|
highlightSearchTerms,
|
||||||
handleUnicodeEmoji,
|
handleUnicodeEmoji,
|
||||||
highlightCurrentMentions,
|
highlightCurrentMentions,
|
||||||
parseSearchTerms, autolinkChannelMentions,
|
highlightWithoutNotificationKeywords,
|
||||||
|
parseSearchTerms,
|
||||||
|
autolinkChannelMentions,
|
||||||
} from 'utils/text_formatting';
|
} from 'utils/text_formatting';
|
||||||
import type {ChannelNamesMap} from 'utils/text_formatting';
|
import type {ChannelNamesMap} from 'utils/text_formatting';
|
||||||
|
|
||||||
@ -304,6 +306,101 @@ describe('highlightCurrentMentions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('highlightWithoutNotificationKeywords', () => {
|
||||||
|
test('should replace highlight keywords with tokens', () => {
|
||||||
|
const text = 'This is a test message with some keywords';
|
||||||
|
const tokens = new Map();
|
||||||
|
const highlightKeys = [
|
||||||
|
{key: 'test message'},
|
||||||
|
{key: 'keywords'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const expectedOutput = 'This is a $MM_HIGHLIGHTKEYWORD0$ with some $MM_HIGHLIGHTKEYWORD1$';
|
||||||
|
const expectedTokens = new Map([
|
||||||
|
['$MM_HIGHLIGHTKEYWORD0$', {
|
||||||
|
value: '<span class="non-notification-highlight">test message</span>',
|
||||||
|
originalText: 'test message',
|
||||||
|
}],
|
||||||
|
['$MM_HIGHLIGHTKEYWORD1$', {
|
||||||
|
value: '<span class="non-notification-highlight">keywords</span>',
|
||||||
|
originalText: 'keywords',
|
||||||
|
}],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const output = highlightWithoutNotificationKeywords(text, tokens, highlightKeys);
|
||||||
|
|
||||||
|
expect(output).toBe(expectedOutput);
|
||||||
|
expect(tokens).toEqual(expectedTokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty highlightKeys array', () => {
|
||||||
|
const text = 'This is a test message';
|
||||||
|
const tokens = new Map();
|
||||||
|
const highlightKeys = [] as Array<{key: string}>;
|
||||||
|
|
||||||
|
const expectedOutput = 'This is a test message';
|
||||||
|
const expectedTokens = new Map();
|
||||||
|
|
||||||
|
const output = highlightWithoutNotificationKeywords(text, tokens, highlightKeys);
|
||||||
|
|
||||||
|
expect(output).toBe(expectedOutput);
|
||||||
|
expect(tokens).toEqual(expectedTokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty text', () => {
|
||||||
|
const text = '';
|
||||||
|
const tokens = new Map();
|
||||||
|
const highlightKeys = [
|
||||||
|
{key: 'test'},
|
||||||
|
{key: 'keywords'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const expectedOutput = '';
|
||||||
|
const expectedTokens = new Map();
|
||||||
|
|
||||||
|
const output = highlightWithoutNotificationKeywords(text, tokens, highlightKeys);
|
||||||
|
|
||||||
|
expect(output).toBe(expectedOutput);
|
||||||
|
expect(tokens).toEqual(expectedTokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle Chinese, Korean, Russian, and Japanese words', () => {
|
||||||
|
const text = 'This is a test message with some keywords: привет, こんにちは, 안녕하세요, 你好';
|
||||||
|
const tokens = new Map();
|
||||||
|
const highlightKeys = [
|
||||||
|
{key: 'こんにちは'}, // Japanese hello
|
||||||
|
{key: '안녕하세요'}, // Korean hello
|
||||||
|
{key: 'привет'}, // Russian hello
|
||||||
|
{key: '你好'}, // Chinese hello
|
||||||
|
];
|
||||||
|
|
||||||
|
const expectedOutput = 'This is a test message with some keywords: $MM_HIGHLIGHTKEYWORD0$, $MM_HIGHLIGHTKEYWORD1$, $MM_HIGHLIGHTKEYWORD2$, $MM_HIGHLIGHTKEYWORD3$';
|
||||||
|
const expectedTokens = new Map([
|
||||||
|
['$MM_HIGHLIGHTKEYWORD0$', {
|
||||||
|
value: '<span class="non-notification-highlight">привет</span>',
|
||||||
|
originalText: 'привет',
|
||||||
|
}],
|
||||||
|
['$MM_HIGHLIGHTKEYWORD1$', {
|
||||||
|
value: '<span class="non-notification-highlight">こんにちは</span>',
|
||||||
|
originalText: 'こんにちは',
|
||||||
|
}],
|
||||||
|
['$MM_HIGHLIGHTKEYWORD2$', {
|
||||||
|
value: '<span class="non-notification-highlight">안녕하세요</span>',
|
||||||
|
originalText: '안녕하세요',
|
||||||
|
}],
|
||||||
|
['$MM_HIGHLIGHTKEYWORD3$', {
|
||||||
|
value: '<span class="non-notification-highlight">你好</span>',
|
||||||
|
originalText: '你好',
|
||||||
|
}],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const output = highlightWithoutNotificationKeywords(text, tokens, highlightKeys);
|
||||||
|
|
||||||
|
expect(output).toBe(expectedOutput);
|
||||||
|
expect(tokens).toEqual(expectedTokens);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('parseSearchTerms', () => {
|
describe('parseSearchTerms', () => {
|
||||||
const tests = [
|
const tests = [
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,8 @@ import type {Renderer} from 'marked';
|
|||||||
|
|
||||||
import type {SystemEmoji} from '@mattermost/types/emojis';
|
import type {SystemEmoji} from '@mattermost/types/emojis';
|
||||||
|
|
||||||
|
import type {HighlightWithoutNotificationKey} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import {formatWithRenderer} from 'utils/markdown';
|
import {formatWithRenderer} from 'utils/markdown';
|
||||||
|
|
||||||
import Constants from './constants';
|
import Constants from './constants';
|
||||||
@ -88,6 +90,11 @@ interface TextFormattingOptionsBase {
|
|||||||
*/
|
*/
|
||||||
mentionKeys: MentionKey[];
|
mentionKeys: MentionKey[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of highlight keys for the current user to highlight without notification.
|
||||||
|
*/
|
||||||
|
highlightKeys: HighlightWithoutNotificationKey[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether or not to remove newlines.
|
* Specifies whether or not to remove newlines.
|
||||||
*
|
*
|
||||||
@ -360,6 +367,10 @@ export function doFormatText(text: string, options: TextFormattingOptions, emoji
|
|||||||
output = highlightCurrentMentions(output, tokens, options.mentionKeys);
|
output = highlightCurrentMentions(output, tokens, options.mentionKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.highlightKeys && options.highlightKeys.length > 0) {
|
||||||
|
output = highlightWithoutNotificationKeywords(output, tokens, options.highlightKeys);
|
||||||
|
}
|
||||||
|
|
||||||
if (!('emoticons' in options) || options.emoticons) {
|
if (!('emoticons' in options) || options.emoticons) {
|
||||||
output = handleUnicodeEmoji(output, emojiMap, UNICODE_EMOJI_REGEX);
|
output = handleUnicodeEmoji(output, emojiMap, UNICODE_EMOJI_REGEX);
|
||||||
}
|
}
|
||||||
@ -704,6 +715,79 @@ export function highlightCurrentMentions(
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function highlightWithoutNotificationKeywords(
|
||||||
|
text: string,
|
||||||
|
tokens: Tokens,
|
||||||
|
highlightKeys: HighlightWithoutNotificationKey[] = [],
|
||||||
|
) {
|
||||||
|
let output = text;
|
||||||
|
|
||||||
|
// Store the new tokens in a separate map since we can't add objects to a map during iteration
|
||||||
|
const newTokens = new Map();
|
||||||
|
|
||||||
|
// Look for highlighting keywords in the tokens
|
||||||
|
tokens.forEach((token, alias) => {
|
||||||
|
const tokenOriginalText = token.originalText.toLowerCase();
|
||||||
|
|
||||||
|
if (highlightKeys.findIndex((highlightKey) => highlightKey.key.toLowerCase() === tokenOriginalText) !== -1) {
|
||||||
|
const newIndex = tokens.size + newTokens.size;
|
||||||
|
const newAlias = `$MM_HIGHLIGHTKEYWORD${newIndex}$`;
|
||||||
|
|
||||||
|
newTokens.set(newAlias, {
|
||||||
|
value: `<span class="non-notification-highlight">${alias}</span>`,
|
||||||
|
originalText: token.originalText,
|
||||||
|
});
|
||||||
|
output = output.replace(alias, newAlias);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy the new tokens to the tokens map
|
||||||
|
newTokens.forEach((newToken, newAlias) => {
|
||||||
|
tokens.set(newAlias, newToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Look for highlighting keywords in the text
|
||||||
|
function replaceHighlightKeywordsWithToken(
|
||||||
|
_: string,
|
||||||
|
prefix: string,
|
||||||
|
highlightKey: string,
|
||||||
|
suffix = '',
|
||||||
|
) {
|
||||||
|
const index = tokens.size;
|
||||||
|
const alias = `$MM_HIGHLIGHTKEYWORD${index}$`;
|
||||||
|
|
||||||
|
// Set the token map with the replacement value so that it can be replaced back later
|
||||||
|
tokens.set(alias, {
|
||||||
|
value: `<span class="non-notification-highlight">${highlightKey}</span>`,
|
||||||
|
originalText: highlightKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
return prefix + alias + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightKeys.
|
||||||
|
sort((a, b) => b.key.length - a.key.length).
|
||||||
|
forEach(({key}) => {
|
||||||
|
if (!key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pattern;
|
||||||
|
if (cjkrPattern.test(key)) {
|
||||||
|
// If the key contains Chinese, Japanese, Korean or Russian characters, don't mark word boundaries
|
||||||
|
pattern = new RegExp(`()(${escapeRegex(key)})()`, 'gi');
|
||||||
|
} else {
|
||||||
|
// If the key contains only English characters, mark word boundaries
|
||||||
|
pattern = new RegExp(`(^|\\W)(${escapeRegex(key)})(\\b|_+\\b)`, 'gi');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the key with the token for each occurrence of the key
|
||||||
|
output = output.replace(pattern, replaceHighlightKeywordsWithToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
const hashtagRegex = /(^|\W)(#\p{L}[\p{L}\d\-_.]*[\p{L}\d])/gu;
|
const hashtagRegex = /(^|\W)(#\p{L}[\p{L}\d\-_.]*[\p{L}\d])/gu;
|
||||||
|
|
||||||
function autolinkHashtags(
|
function autolinkHashtags(
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user