[MM-51680] : Revert New Browse Channels UI modal changes (https://github.com/mattermost/mattermost-webapp/pull/11262) (#22613)
* Revert https://github.com/mattermost/mattermost-webapp/pull/11262 * fix missing translation * fix indentation issue * fix imports in Update accessibility_modals_dialogs_spec.js --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d0babfd254
Коммит
dc4e7bf2ec
@@ -97,7 +97,7 @@ describe('Leave an archived channel', () => {
|
|||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
// # Click on dropdown
|
// # Click on dropdown
|
||||||
cy.findByText('Channel Type: Public').should('be.visible').click();
|
cy.findByText('Show: Public Channels').should('be.visible').click();
|
||||||
|
|
||||||
// # Click archived channels
|
// # Click archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@@ -143,9 +143,9 @@ describe('Leave an archived channel', () => {
|
|||||||
cy.get('#showMoreChannels').click();
|
cy.get('#showMoreChannels').click();
|
||||||
|
|
||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('.more-modal').should('be.visible').within(() => {
|
||||||
// # Public channel list opens by default
|
// # Public channel list opens by default
|
||||||
cy.findByText('Channel Type: Public').should('be.visible').click();
|
cy.findByText('Show: Public Channels').should('be.visible').click();
|
||||||
|
|
||||||
// # Click on archived channels
|
// # Click on archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@@ -196,9 +196,9 @@ describe('Leave an archived channel', () => {
|
|||||||
cy.get('#showMoreChannels').click();
|
cy.get('#showMoreChannels').click();
|
||||||
|
|
||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('.more-modal').should('be.visible').within(() => {
|
||||||
// # Public channels are shown by default
|
// # Public channels are shown by default
|
||||||
cy.findByText('Channel Type: Public').should('be.visible').click();
|
cy.findByText('Show: Public Channels').should('be.visible').click();
|
||||||
|
|
||||||
// # Go to archived channels
|
// # Go to archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@@ -250,9 +250,9 @@ describe('Leave an archived channel', () => {
|
|||||||
cy.get('#showMoreChannels').click();
|
cy.get('#showMoreChannels').click();
|
||||||
|
|
||||||
// # More channels modal opens
|
// # More channels modal opens
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('.more-modal').should('be.visible').within(() => {
|
||||||
// # Show public channels is visible by default
|
// # Show public channels is visible by default
|
||||||
cy.findByText('Channel Type: Public').should('be.visible').click();
|
cy.findByText('Show: Public Channels').should('be.visible').click();
|
||||||
|
|
||||||
// # Go to archived channels
|
// # Go to archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
@@ -286,7 +286,7 @@ describe('Leave an archived channel', () => {
|
|||||||
|
|
||||||
// # More channels modal opens and lands on public channels
|
// # More channels modal opens and lands on public channels
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
cy.findByText('Channel Type: Public').should('be.visible').click();
|
cy.findByText('Show: Public Channels').should('be.visible').click();
|
||||||
|
|
||||||
// # Go to archived channels
|
// # Go to archived channels
|
||||||
cy.findByText('Archived Channels').click();
|
cy.findByText('Archived Channels').click();
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ describe('Channels', () => {
|
|||||||
|
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
// * Dropdown should be visible, defaulting to "Public Channels"
|
// * Dropdown should be visible, defaulting to "Public Channels"
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', 'Channel Type: Public').wait(TIMEOUTS.HALF_SEC);
|
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', 'Show: Public Channels').wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
||||||
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 1).within(() => {
|
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 1).within(() => {
|
||||||
@@ -80,8 +80,8 @@ describe('Channels', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// # Verify that the modal is not closed
|
// # Verify that the modal is closed and it's redirected to the selected channel
|
||||||
cy.get('#moreChannelsModal').should('exist');
|
cy.get('#moreChannelsModal').should('not.exist');
|
||||||
cy.url().should('include', `/${testTeam.name}/channels/${testChannel.name}`);
|
cy.url().should('include', `/${testTeam.name}/channels/${testChannel.name}`);
|
||||||
|
|
||||||
// # Login as channel admin and go directly to the channel
|
// # Login as channel admin and go directly to the channel
|
||||||
@@ -113,7 +113,7 @@ describe('Channels', () => {
|
|||||||
cy.findByText('Archived Channels').should('be.visible').click();
|
cy.findByText('Archived Channels').should('be.visible').click();
|
||||||
|
|
||||||
// * Channel test should be visible as an archived channel in the list
|
// * Channel test should be visible as an archived channel in the list
|
||||||
cy.wrap(el).should('contain', 'Channel Type: Archived');
|
cy.wrap(el).should('contain', 'Show: Archived Channels');
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
cy.get('#searchChannelsTextbox').should('be.visible').type(testChannel.display_name).wait(TIMEOUTS.HALF_SEC);
|
||||||
@@ -196,7 +196,7 @@ describe('Channels', () => {
|
|||||||
|
|
||||||
// * Dropdown should be visible, defaulting to "Public Channels"
|
// * Dropdown should be visible, defaulting to "Public Channels"
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').within((el) => {
|
cy.get('#channelsMoreDropdown').should('be.visible').within((el) => {
|
||||||
cy.wrap(el).should('contain', 'Channel Type: Public');
|
cy.wrap(el).should('contain', 'Show: Public Channels');
|
||||||
});
|
});
|
||||||
|
|
||||||
// * Users should be able to type and search
|
// * Users should be able to type and search
|
||||||
@@ -207,12 +207,12 @@ describe('Channels', () => {
|
|||||||
|
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
// * Users should be able to switch to "Archived Channels" list
|
// * Users should be able to switch to "Archived Channels" list
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', 'Channel Type: Public').click().within((el) => {
|
cy.get('#channelsMoreDropdown').should('be.visible').and('contain', 'Show: Public Channels').click().within((el) => {
|
||||||
// # Click on archived channels item
|
// # Click on archived channels item
|
||||||
cy.findByText('Archived Channels').should('be.visible').click();
|
cy.findByText('Archived Channels').should('be.visible').click();
|
||||||
|
|
||||||
// * Modal should show the archived channels list
|
// * Modal should show the archived channels list
|
||||||
cy.wrap(el).should('contain', 'Channel Type: Archived');
|
cy.wrap(el).should('contain', 'Show: Archived Channels');
|
||||||
}).wait(TIMEOUTS.HALF_SEC);
|
}).wait(TIMEOUTS.HALF_SEC);
|
||||||
cy.get('#searchChannelsTextbox').clear();
|
cy.get('#searchChannelsTextbox').clear();
|
||||||
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 2);
|
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 2);
|
||||||
@@ -250,7 +250,7 @@ function verifyMoreChannelsModal(isEnabled) {
|
|||||||
// * Verify that the more channels modal is open and with or without option to view archived channels
|
// * Verify that the more channels modal is open and with or without option to view archived channels
|
||||||
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
cy.get('#moreChannelsModal').should('be.visible').within(() => {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
cy.get('#channelsMoreDropdown').should('be.visible').and('have.text', 'Channel Type: Public');
|
cy.get('#channelsMoreDropdown').should('be.visible').and('have.text', 'Show: Public Channels');
|
||||||
} else {
|
} else {
|
||||||
cy.get('#channelsMoreDropdown').should('not.exist');
|
cy.get('#channelsMoreDropdown').should('not.exist');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
// Group: @channels @channel
|
// Group: @channels @channel
|
||||||
|
|
||||||
function verifyNoChannelToJoinMessage(isVisible) {
|
function verifyNoChannelToJoinMessage(isVisible) {
|
||||||
cy.findByText('No public channels').should(isVisible ? 'be.visible' : 'not.exist');
|
cy.findByText('No more channels to join').should(isVisible ? 'be.visible' : 'not.exist');
|
||||||
|
cy.findByText('Click \'Create New Channel\' to make a new one').should(isVisible ? 'be.visible' : 'not.exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('more public channels', () => {
|
describe('more public channels', () => {
|
||||||
@@ -52,10 +53,7 @@ describe('more public channels', () => {
|
|||||||
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
||||||
|
|
||||||
// * Assert that the moreChannelsModel is visible
|
// * Assert that the moreChannelsModel is visible
|
||||||
cy.findByRole('dialog', {name: 'Browse Channels'}).should('be.visible').within(() => {
|
cy.findByRole('dialog', {name: 'More Channels'}).should('be.visible').within(() => {
|
||||||
// # Click hide joined checkbox
|
|
||||||
cy.findByText('Hide Joined').should('be.visible').click();
|
|
||||||
|
|
||||||
// * Assert that the moreChannelsList is visible and the number of channels is 31
|
// * Assert that the moreChannelsList is visible and the number of channels is 31
|
||||||
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 31);
|
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 31);
|
||||||
|
|
||||||
@@ -88,9 +86,9 @@ describe('more public channels', () => {
|
|||||||
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
||||||
|
|
||||||
// * Assert the moreChannelsModel is visible
|
// * Assert the moreChannelsModel is visible
|
||||||
cy.findByRole('dialog', {name: 'Browse Channels'}).should('be.visible').within(() => {
|
cy.findByRole('dialog', {name: 'More Channels'}).should('be.visible').within(() => {
|
||||||
// # Click hide joined checkbox
|
// * Assert the moreChannelsList does have one child
|
||||||
cy.findByText('Hide Joined').should('be.visible').click();
|
cy.get('#moreChannelsList').should('be.visible').children().should('have.length', 1);
|
||||||
|
|
||||||
// * Assert that the "No more channels to join" message is visible
|
// * Assert that the "No more channels to join" message is visible
|
||||||
verifyNoChannelToJoinMessage(true);
|
verifyNoChannelToJoinMessage(true);
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ describe('Channel sidebar', () => {
|
|||||||
cy.get('.AddChannelDropdown .MenuItem:contains(Browse Channels) button').should('be.visible').click();
|
cy.get('.AddChannelDropdown .MenuItem:contains(Browse Channels) button').should('be.visible').click();
|
||||||
|
|
||||||
// * Verify that the more channels modal is visible
|
// * Verify that the more channels modal is visible
|
||||||
cy.get('#moreChannelsModal').should('be.visible');
|
cy.get('.more-modal').should('be.visible');
|
||||||
|
|
||||||
// Click the Off-Topic channel
|
// Click the Off-Topic channel
|
||||||
cy.findByText('Off-Topic').should('be.visible').click();
|
cy.get('.more-modal button:contains(Off-Topic)').should('be.visible').click();
|
||||||
|
|
||||||
// Verify that new channel is in the sidebar and is active
|
// Verify that new channel is in the sidebar and is active
|
||||||
cy.get('#moreChannelsModal').should('exist');
|
cy.get('.more-modal').should('not.exist');
|
||||||
cy.url().should('include', `/${teamName}/channels/off-topic`);
|
cy.url().should('include', `/${teamName}/channels/off-topic`);
|
||||||
cy.get('#channelHeaderTitle').should('contain', 'Off-Topic');
|
cy.get('#channelHeaderTitle').should('contain', 'Off-Topic');
|
||||||
cy.get('.SidebarChannel.active:contains(Off-Topic)').should('be.visible');
|
cy.get('.SidebarChannel.active:contains(Off-Topic)').should('be.visible');
|
||||||
|
|||||||
@@ -104,26 +104,30 @@ describe('Verify Accessibility Support in Modals & Dialogs', () => {
|
|||||||
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
cy.uiBrowseOrCreateChannel('Browse Channels').click();
|
||||||
|
|
||||||
// * Verify the accessibility support in More Channels Dialog
|
// * Verify the accessibility support in More Channels Dialog
|
||||||
cy.findByRole('dialog', {name: 'Browse Channels'}).within(() => {
|
cy.findByRole('dialog', {name: 'More Channels'}).within(() => {
|
||||||
cy.findByRole('heading', {name: 'Browse Channels'});
|
cy.findByRole('heading', {name: 'More Channels'});
|
||||||
|
|
||||||
// * Verify the accessibility support in search input
|
// * Verify the accessibility support in search input
|
||||||
cy.findByPlaceholderText('Search channels');
|
cy.findByPlaceholderText('Search channels');
|
||||||
|
|
||||||
cy.get('#moreChannelsList').should('be.visible').then((el) => {
|
cy.waitUntil(() => cy.get('#moreChannelsList').then((el) => {
|
||||||
return el[0].children.length === 2;
|
return el[0].children.length === 2;
|
||||||
});
|
}));
|
||||||
|
|
||||||
// # Hide already joined channels
|
// # Focus on the Create Channel button and TAB twice
|
||||||
cy.findByText('Hide Joined').click();
|
cy.get('#createNewChannel').focus().tab().tab();
|
||||||
|
|
||||||
// # Focus on the Create Channel button and TAB three time
|
|
||||||
cy.get('#createNewChannelButton').focus().tab().tab().tab();
|
|
||||||
|
|
||||||
// * Verify channel name is highlighted and reader reads the channel name and channel description
|
// * Verify channel name is highlighted and reader reads the channel name and channel description
|
||||||
cy.get('#moreChannelsList').within(() => {
|
cy.get('#moreChannelsList').children().eq(0).within(() => {
|
||||||
const selectedChannel = getChannelAriaLabel(channel);
|
const selectedChannel = getChannelAriaLabel(channel);
|
||||||
cy.findByLabelText(selectedChannel).should('be.visible').should('be.focused');
|
cy.findByLabelText(selectedChannel).should('be.focused');
|
||||||
|
|
||||||
|
// * Press Tab and verify if focus changes to Join button
|
||||||
|
cy.focused().tab();
|
||||||
|
cy.findByText('Join').parent().should('be.focused');
|
||||||
|
|
||||||
|
// * Verify previous button should no longer be focused
|
||||||
|
cy.findByLabelText(selectedChannel).should('not.be.focused');
|
||||||
});
|
});
|
||||||
|
|
||||||
// * Press Tab again and verify if focus changes to next row
|
// * Press Tab again and verify if focus changes to next row
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ context('ldap', () => {
|
|||||||
|
|
||||||
// * Search private channel name and make sure it isn't there in public channel directory
|
// * Search private channel name and make sure it isn't there in public channel directory
|
||||||
cy.get('#searchChannelsTextbox').type(testChannel.display_name);
|
cy.get('#searchChannelsTextbox').type(testChannel.display_name);
|
||||||
cy.get('#moreChannelsList').should('include.text', 'No results for');
|
cy.get('#moreChannelsList').should('include.text', 'No more channels to join');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T2629 - Private to public - More....', () => {
|
it('MM-T2629 - Private to public - More....', () => {
|
||||||
@@ -473,7 +473,7 @@ context('ldap', () => {
|
|||||||
|
|
||||||
// * Search private channel name and make sure it isn't there in public channel directory
|
// * Search private channel name and make sure it isn't there in public channel directory
|
||||||
cy.get('#searchChannelsTextbox').type(publicChannel.display_name);
|
cy.get('#searchChannelsTextbox').type(publicChannel.display_name);
|
||||||
cy.get('#moreChannelsList').should('include.text', 'No results for');
|
cy.get('#moreChannelsList').should('include.text', 'No more channels to join');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ describe('Actions.Channel', () => {
|
|||||||
}],
|
}],
|
||||||
}];
|
}];
|
||||||
|
|
||||||
await testStore.dispatch(searchMoreChannels('', false, true));
|
await testStore.dispatch(searchMoreChannels('', false));
|
||||||
expect(testStore.getActions()).toEqual(expectedActions);
|
expect(testStore.getActions()).toEqual(expectedActions);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export function loadChannelsForCurrentUser(): ActionFunc {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function searchMoreChannels(term: string, showArchivedChannels: boolean, hideJoinedChannels: boolean): ActionFunc<Channel[], ServerError> {
|
export function searchMoreChannels(term: string, showArchivedChannels: boolean): ActionFunc<Channel[], ServerError> {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const teamId = getCurrentTeamId(state);
|
const teamId = getCurrentTeamId(state);
|
||||||
@@ -121,7 +121,9 @@ export function searchMoreChannels(term: string, showArchivedChannels: boolean,
|
|||||||
const {data, error} = await dispatch(ChannelActions.searchChannels(teamId, term, showArchivedChannels));
|
const {data, error} = await dispatch(ChannelActions.searchChannels(teamId, term, showArchivedChannels));
|
||||||
if (data) {
|
if (data) {
|
||||||
const myMembers = getMyChannelMemberships(state);
|
const myMembers = getMyChannelMemberships(state);
|
||||||
const channels = hideJoinedChannels ? (data as Channel[]).filter((channel) => !myMembers[channel.id]) : data;
|
|
||||||
|
// When searching public channels, only get channels user is not a member of
|
||||||
|
const channels = showArchivedChannels ? data : (data as Channel[]).filter((c) => !myMembers[c.id]);
|
||||||
return {data: channels};
|
return {data: channels};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`components/SearchableChannelList should match init snapshot 1`] = `
|
||||||
|
<div
|
||||||
|
className="filtered-user-list"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="filter-row filter-row--full"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="col-sm-12"
|
||||||
|
>
|
||||||
|
<QuickInput
|
||||||
|
className="form-control filter-textbox"
|
||||||
|
id="searchChannelsTextbox"
|
||||||
|
inputComponent={
|
||||||
|
Object {
|
||||||
|
"$$typeof": Symbol(react.forward_ref),
|
||||||
|
"render": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onInput={[Function]}
|
||||||
|
placeholder={
|
||||||
|
Object {
|
||||||
|
"defaultMessage": "Search channels",
|
||||||
|
"id": "filtered_channels_list.search",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="more-modal__list"
|
||||||
|
role="application"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
id="moreChannelsList"
|
||||||
|
>
|
||||||
|
<LoadingScreen />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="filter-controls"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import React, {SVGProps} from 'react';
|
|
||||||
|
|
||||||
const SvgComponent = (props: SVGProps<SVGSVGElement>) => (
|
|
||||||
<svg
|
|
||||||
width={140}
|
|
||||||
height={141}
|
|
||||||
fill='none'
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
opacity={0.4}
|
|
||||||
d='M37.593 38.008c4.754-4.815 10.754-7.295 17.989-7.428 7.101.133 13.065 2.601 17.892 7.428 4.815 4.827 7.295 10.791 7.428 17.892-.133 7.235-2.601 13.223-7.428 17.99-4.827 4.754-10.791 7.27-17.892 7.512-7.235-.254-13.223-2.758-17.99-7.513-4.754-4.766-7.258-10.766-7.512-18 .254-7.102 2.758-13.066 7.513-17.881Z'
|
|
||||||
fill='#fff'
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d='M78.887 51.382c-2.151-6.992-6.225-12.225-12.226-15.69-6.001-3.465-12.57-4.376-19.701-2.743-3.9.995-7.297 2.717-10.22 5.162 3.269-3.567 7.415-6.037 12.428-7.416 7.13-1.633 13.732-.703 19.787 2.793s10.161 8.748 12.313 15.74c1.323 5.037 1.257 9.862-.21 14.47-1.454 4.614-4.066 8.49-7.84 11.611 2.833-3.087 4.783-6.713 5.844-10.894 1.05-4.187.991-8.522-.175-13.033Z'
|
|
||||||
fill='#000'
|
|
||||||
fillOpacity={0.4}
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d='M86.76 53.929c-.508-7.506-3.553-14.097-9.125-19.774-6.346-6.05-13.67-9.08-21.974-9.08-8.303 0-15.616 3.03-21.961 9.08-6.08 6.315-9.126 13.591-9.126 21.855 0 8.262 3.046 15.551 9.126 21.854 5.826 5.556 12.485 8.551 19.967 8.984 7.481.445 14.383-1.611 20.728-6.146l4.75 4.727 6.08-6.05-4.75-4.727c4.69-6.302 6.78-13.218 6.285-20.723Zm-13.126 19.87c-4.823 4.726-10.781 7.228-17.876 7.468-7.228-.252-13.21-2.742-17.973-7.469-4.75-4.727-7.252-10.692-7.506-17.885.254-7.06 2.756-12.99 7.506-17.789 4.75-4.787 10.745-7.252 17.973-7.385 7.095.133 13.053 2.586 17.876 7.385 4.81 4.8 7.288 10.73 7.421 17.79-.133 7.192-2.599 13.157-7.421 17.884Z'
|
|
||||||
fill='#BABEC9'
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d='M106.202 114.187c-1.567.449-2.728.291-3.482-.472L78.06 86.651c-.753-.762-1.064-1.743-.945-2.954.12-1.211.874-2.567 2.262-4.093 1.507-1.393 2.847-2.192 4.044-2.385 1.196-.194 2.165.157 2.92 1.053l26.921 24.957c.753.763.873 1.901.37 3.427-.502 1.525-1.447 3.051-2.823 4.577-1.496 1.526-3.039 2.506-4.607 2.954Z'
|
|
||||||
fill='#FFBC1F'
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d='m108.007 98.343-10.08 10.164-12.154-13.34 8.914-9.106 13.32 12.282Z'
|
|
||||||
fill='#7A5600'
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default SvgComponent;
|
|
||||||
@@ -133,7 +133,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.GenericModal__header {
|
.GenericModal__header {
|
||||||
width: 85%;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-top-left-radius: 12px;
|
border-top-left-radius: 12px;
|
||||||
border-top-right-radius: 12px;
|
border-top-right-radius: 12px;
|
||||||
|
|||||||
@@ -1,15 +1,53 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`components/MoreChannels should match snapshot and state 1`] = `
|
exports[`components/MoreChannels should match snapshot and state 1`] = `
|
||||||
<GenericModal
|
<Modal
|
||||||
|
animation={true}
|
||||||
aria-labelledby="moreChannelsModalLabel"
|
aria-labelledby="moreChannelsModalLabel"
|
||||||
aria-modal={true}
|
autoFocus={true}
|
||||||
autoCloseOnCancelButton={true}
|
backdrop={true}
|
||||||
autoCloseOnConfirmButton={false}
|
bsClass="modal"
|
||||||
compassDesign={true}
|
dialogClassName="a11y__modal more-modal more-modal--action"
|
||||||
enforceFocus={false}
|
dialogComponentClass={[Function]}
|
||||||
headerButton={
|
enforceFocus={true}
|
||||||
<Memo(Connect(TeamPermissionGate))
|
id="moreChannelsModal"
|
||||||
|
keyboard={true}
|
||||||
|
manager={
|
||||||
|
ModalManager {
|
||||||
|
"add": [Function],
|
||||||
|
"containers": Array [],
|
||||||
|
"data": Array [],
|
||||||
|
"handleContainerOverflow": true,
|
||||||
|
"hideSiblingNodes": true,
|
||||||
|
"isTopModal": [Function],
|
||||||
|
"modals": Array [],
|
||||||
|
"remove": [Function],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onExited={[Function]}
|
||||||
|
onHide={[Function]}
|
||||||
|
renderBackdrop={[Function]}
|
||||||
|
restoreFocus={true}
|
||||||
|
role="dialog"
|
||||||
|
show={true}
|
||||||
|
>
|
||||||
|
<ModalHeader
|
||||||
|
bsClass="modal-header"
|
||||||
|
closeButton={true}
|
||||||
|
closeLabel="Close"
|
||||||
|
id="moreChannelsModalHeader"
|
||||||
|
>
|
||||||
|
<ModalTitle
|
||||||
|
bsClass="modal-title"
|
||||||
|
componentClass="h1"
|
||||||
|
id="moreChannelsModalLabel"
|
||||||
|
>
|
||||||
|
<MemoizedFormattedMessage
|
||||||
|
defaultMessage="More Channels"
|
||||||
|
id="more_channels.title"
|
||||||
|
/>
|
||||||
|
</ModalTitle>
|
||||||
|
<Connect(TeamPermissionGate)
|
||||||
permissions={
|
permissions={
|
||||||
Array [
|
Array [
|
||||||
"create_public_channel",
|
"create_public_channel",
|
||||||
@@ -18,30 +56,74 @@ exports[`components/MoreChannels should match snapshot and state 1`] = `
|
|||||||
teamId="team_id"
|
teamId="team_id"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-label="Create New Channel"
|
className="btn btn-primary channel-create-btn"
|
||||||
className="btn outlineButton"
|
id="createNewChannel"
|
||||||
id="createNewChannelButton"
|
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<Memo(MemoizedFormattedMessage)
|
<MemoizedFormattedMessage
|
||||||
defaultMessage="Create New Channel"
|
defaultMessage="Create Channel"
|
||||||
id="more_channels.create"
|
id="more_channels.create"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</Memo(Connect(TeamPermissionGate))>
|
</Connect(TeamPermissionGate)>
|
||||||
}
|
</ModalHeader>
|
||||||
id="moreChannelsModal"
|
<ModalBody
|
||||||
keyboardEscape={true}
|
bsClass="modal-body"
|
||||||
modalHeaderText={
|
componentClass="div"
|
||||||
<Memo(MemoizedFormattedMessage)
|
>
|
||||||
defaultMessage="Browse Channels"
|
<SearchableChannelList
|
||||||
id="more_channels.title"
|
canShowArchivedChannels={true}
|
||||||
|
channels={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"create_at": 0,
|
||||||
|
"creator_id": "id",
|
||||||
|
"delete_at": 0,
|
||||||
|
"display_name": "name",
|
||||||
|
"group_constrained": false,
|
||||||
|
"header": "header",
|
||||||
|
"id": "channel_id",
|
||||||
|
"last_post_at": 0,
|
||||||
|
"last_root_post_at": 0,
|
||||||
|
"name": "DN",
|
||||||
|
"purpose": "purpose",
|
||||||
|
"scheme_id": "id",
|
||||||
|
"team_id": "team_id",
|
||||||
|
"type": "O",
|
||||||
|
"update_at": 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
channelsPerPage={50}
|
||||||
|
handleJoin={[Function]}
|
||||||
|
isSearch={false}
|
||||||
|
loading={false}
|
||||||
|
nextPage={[Function]}
|
||||||
|
noResultsText={
|
||||||
|
<Memo(Connect(TeamPermissionGate))
|
||||||
|
permissions={
|
||||||
|
Array [
|
||||||
|
"create_public_channel",
|
||||||
|
"create_private_channel",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
teamId="team_id"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
className="secondary-message"
|
||||||
|
>
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Click 'Create New Channel' to make a new one"
|
||||||
|
id="more_channels.createClick"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</Memo(Connect(TeamPermissionGate))>
|
||||||
|
}
|
||||||
|
search={[Function]}
|
||||||
|
shouldShowArchivedChannels={false}
|
||||||
|
toggleArchivedChannels={[Function]}
|
||||||
/>
|
/>
|
||||||
}
|
</ModalBody>
|
||||||
onExited={[Function]}
|
</Modal>
|
||||||
show={true}
|
|
||||||
>
|
|
||||||
<LoadingScreen />
|
|
||||||
</GenericModal>
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`components/SearchableChannelList should match init snapshot 1`] = `
|
|
||||||
<div
|
|
||||||
className="filtered-user-list"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="filter-row filter-row--full"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
aria-hidden="true"
|
|
||||||
id="searchIcon"
|
|
||||||
>
|
|
||||||
<MagnifyIcon
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<QuickInput
|
|
||||||
aria-label="Search Channels"
|
|
||||||
className="form-control filter-textbox"
|
|
||||||
clearable={true}
|
|
||||||
id="searchChannelsTextbox"
|
|
||||||
inputComponent={
|
|
||||||
Object {
|
|
||||||
"$$typeof": Symbol(react.forward_ref),
|
|
||||||
"render": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onClear={[Function]}
|
|
||||||
onInput={[Function]}
|
|
||||||
placeholder={
|
|
||||||
Object {
|
|
||||||
"defaultMessage": "Search channels",
|
|
||||||
"id": "filtered_channels_list.search",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="more-modal__dropdown"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
id="channelCountLabel"
|
|
||||||
>
|
|
||||||
0 Results
|
|
||||||
</span>
|
|
||||||
<div
|
|
||||||
id="modalPreferenceContainer"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
id="hideJoinedPreferenceCheckbox"
|
|
||||||
onClick={[Function]}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
aria-label="Hide joined channels checkbox, not checked"
|
|
||||||
className="get-app__checkbox"
|
|
||||||
/>
|
|
||||||
<MemoizedFormattedMessage
|
|
||||||
defaultMessage="Hide Joined"
|
|
||||||
id="more_channels.hide_joined"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="more-modal__list"
|
|
||||||
role="application"
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
id="moreChannelsList"
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<LoadingScreen />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="filter-controls"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
@@ -12,29 +12,24 @@ import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
|||||||
import {Action, ActionResult} from 'mattermost-redux/types/actions';
|
import {Action, ActionResult} from 'mattermost-redux/types/actions';
|
||||||
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||||
import {getChannels, getArchivedChannels, joinChannel, getChannelStats} from 'mattermost-redux/actions/channels';
|
import {getChannels, getArchivedChannels, joinChannel} from 'mattermost-redux/actions/channels';
|
||||||
import {getChannelsInCurrentTeam, getMyChannelMemberships, getAllChannelStats} from 'mattermost-redux/selectors/entities/channels';
|
import {getOtherChannels, getChannelsInCurrentTeam} from 'mattermost-redux/selectors/entities/channels';
|
||||||
|
|
||||||
import {Constants, StoragePrefixes} from 'utils/constants';
|
|
||||||
|
|
||||||
import {searchMoreChannels} from 'actions/channel_actions';
|
import {searchMoreChannels} from 'actions/channel_actions';
|
||||||
import {openModal, closeModal} from 'actions/views/modals';
|
import {openModal, closeModal} from 'actions/views/modals';
|
||||||
import {setGlobalItem} from 'actions/storage';
|
|
||||||
import {closeRightHandSide} from 'actions/views/rhs';
|
import {closeRightHandSide} from 'actions/views/rhs';
|
||||||
|
|
||||||
import {getIsRhsOpen, getRhsState} from 'selectors/rhs';
|
import {getIsRhsOpen, getRhsState} from 'selectors/rhs';
|
||||||
|
|
||||||
import {GlobalState} from 'types/store';
|
|
||||||
import {ModalData} from 'types/actions';
|
import {ModalData} from 'types/actions';
|
||||||
|
import {GlobalState} from 'types/store';
|
||||||
import {makeGetGlobalItem} from 'selectors/storage';
|
|
||||||
|
|
||||||
import MoreChannels from './more_channels';
|
import MoreChannels from './more_channels';
|
||||||
|
|
||||||
const getChannelsWithoutArchived = createSelector(
|
const getNotArchivedOtherChannels = createSelector(
|
||||||
'getChannelsWithoutArchived',
|
'getNotArchivedOtherChannels',
|
||||||
getChannelsInCurrentTeam,
|
getOtherChannels,
|
||||||
(channels: Channel[]) => channels && channels.filter((c) => c.delete_at === 0 && c.type !== Constants.PRIVATE_CHANNEL),
|
(channels: Channel[]) => channels && channels.filter((c) => c.delete_at === 0),
|
||||||
);
|
);
|
||||||
|
|
||||||
const getArchivedOtherChannels = createSelector(
|
const getArchivedOtherChannels = createSelector(
|
||||||
@@ -45,19 +40,15 @@ const getArchivedOtherChannels = createSelector(
|
|||||||
|
|
||||||
function mapStateToProps(state: GlobalState) {
|
function mapStateToProps(state: GlobalState) {
|
||||||
const team = getCurrentTeam(state) || {};
|
const team = getCurrentTeam(state) || {};
|
||||||
const getGlobalItem = makeGetGlobalItem(StoragePrefixes.HIDE_JOINED_CHANNELS, 'false');
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
channels: getChannelsWithoutArchived(state) || [],
|
channels: getNotArchivedOtherChannels(state) || [],
|
||||||
archivedChannels: getArchivedOtherChannels(state) || [],
|
archivedChannels: getArchivedOtherChannels(state) || [],
|
||||||
currentUserId: getCurrentUserId(state),
|
currentUserId: getCurrentUserId(state),
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
teamName: team.name,
|
teamName: team.name,
|
||||||
channelsRequestStarted: state.requests.channels.getChannels.status === RequestStatus.STARTED,
|
channelsRequestStarted: state.requests.channels.getChannels.status === RequestStatus.STARTED,
|
||||||
canShowArchivedChannels: (getConfig(state).ExperimentalViewArchivedChannels === 'true'),
|
canShowArchivedChannels: (getConfig(state).ExperimentalViewArchivedChannels === 'true'),
|
||||||
myChannelMemberships: getMyChannelMemberships(state) || {},
|
|
||||||
allChannelStats: getAllChannelStats(state) || {},
|
|
||||||
shouldHideJoinedChannels: getGlobalItem(state) === 'true',
|
|
||||||
rhsState: getRhsState(state),
|
rhsState: getRhsState(state),
|
||||||
rhsOpen: getIsRhsOpen(state),
|
rhsOpen: getIsRhsOpen(state),
|
||||||
};
|
};
|
||||||
@@ -70,8 +61,6 @@ type Actions = {
|
|||||||
searchMoreChannels: (term: string, shouldShowArchivedChannels: boolean) => Promise<ActionResult>;
|
searchMoreChannels: (term: string, shouldShowArchivedChannels: boolean) => Promise<ActionResult>;
|
||||||
openModal: <P>(modalData: ModalData<P>) => void;
|
openModal: <P>(modalData: ModalData<P>) => void;
|
||||||
closeModal: (modalId: string) => void;
|
closeModal: (modalId: string) => void;
|
||||||
getChannelStats: (channelId: string) => void;
|
|
||||||
setGlobalItem: (name: string, value: string) => void;
|
|
||||||
closeRightHandSide: () => void;
|
closeRightHandSide: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +73,6 @@ function mapDispatchToProps(dispatch: Dispatch) {
|
|||||||
searchMoreChannels,
|
searchMoreChannels,
|
||||||
openModal,
|
openModal,
|
||||||
closeModal,
|
closeModal,
|
||||||
getChannelStats,
|
|
||||||
setGlobalItem,
|
|
||||||
closeRightHandSide,
|
closeRightHandSide,
|
||||||
}, dispatch),
|
}, dispatch),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,295 +0,0 @@
|
|||||||
@charset 'UTF-8';
|
|
||||||
|
|
||||||
#moreChannelsModal {
|
|
||||||
.modal-content {
|
|
||||||
min-height: 600px;
|
|
||||||
max-height: calc(50vh - 240px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-dialog {
|
|
||||||
margin-top: calc(45vh - 240px) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-row--full {
|
|
||||||
position: relative;
|
|
||||||
margin: 0 32px;
|
|
||||||
|
|
||||||
.input-clear {
|
|
||||||
top: 16px;
|
|
||||||
right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchIcon {
|
|
||||||
position: absolute;
|
|
||||||
top: 14px;
|
|
||||||
left: 16px;
|
|
||||||
color: rgba(var(--center-channel-color-rgb), 0.64);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchChannelsTextbox {
|
|
||||||
height: 48px;
|
|
||||||
padding-left: 40px;
|
|
||||||
border: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
|
||||||
box-shadow: none;
|
|
||||||
font-size: 16px;
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
color: var(--center-channel-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border: 2px solid var(--button-bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-modal__dropdown {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 8px 32px;
|
|
||||||
border-bottom: solid 1px rgba(var(--center-channel-color-rgb), 0.16);
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: rgba(var(--center-channel-color-rgb), 0.64);
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MenuItem__primary-text {
|
|
||||||
width: 100%;
|
|
||||||
color: var(--center-channel-color);
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 20px;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.Menu__content {
|
|
||||||
border-color: rgba(var(--center-channel-color-rgb), 0.16);
|
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
#channelCountLabel {
|
|
||||||
color: var(--center-channel-color);
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
#modalPreferenceContainer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.get-app__checkbox {
|
|
||||||
display: flex;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
align-items: center;
|
|
||||||
border: 1px solid rgba(var(--center-channel-color-rgb), 0.24);
|
|
||||||
}
|
|
||||||
|
|
||||||
#hideJoinedPreferenceCheckbox {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#channelsMoreDropdown {
|
|
||||||
margin: 0 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menuWrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 4px 6px 4px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MenuWrapper:hover {
|
|
||||||
background-color: rgba(var(--center-channel-color-rgb), 0.08);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MenuWrapper--open {
|
|
||||||
background-color: rgba(var(--button-bg-rgb), 0.12);
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(var(--button-bg-rgb), 0.12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
padding: 15px 0 0;
|
|
||||||
|
|
||||||
.filtered-user-list {
|
|
||||||
height: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-modal__row {
|
|
||||||
padding: 0 32px;
|
|
||||||
border-bottom: none;
|
|
||||||
|
|
||||||
.more-modal__details {
|
|
||||||
padding-left: 0;
|
|
||||||
color: rgba(var(--center-channel-color-rgb), 0.56);
|
|
||||||
|
|
||||||
svg {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-modal__name {
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 0;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: var(--center-channel-color);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#channelPurposeContainer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
.dot {
|
|
||||||
width: 3px;
|
|
||||||
height: 3px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
background-color: rgba(var(--center-channel-color-rgb), 0.56);
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-modal__description {
|
|
||||||
margin-left: 4px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
#membershipIndicatorContainer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
span,
|
|
||||||
svg {
|
|
||||||
color: var(--online-indicator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin: 0 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 12px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-modal__actions {
|
|
||||||
button {
|
|
||||||
display: none;
|
|
||||||
min-width: 54px;
|
|
||||||
height: 32px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-modal__row:hover,
|
|
||||||
.more-modal__row:focus {
|
|
||||||
background-color: rgba(var(--center-channel-color-rgb), 0.08);
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.more-modal__actions {
|
|
||||||
.primaryButton,
|
|
||||||
.outlineButton {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group {
|
|
||||||
padding: 0 32px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
.GenericModal__header {
|
|
||||||
display: flex;
|
|
||||||
width: 95%;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
top: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.outlineButton {
|
|
||||||
border: 1px solid var(--button-bg);
|
|
||||||
background: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
color: var(--button-bg);
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.outlineButton:hover {
|
|
||||||
background-color: rgba(var(--button-bg-rgb), 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-controls {
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
button {
|
|
||||||
min-width: 72px;
|
|
||||||
margin: 8px 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#moreChannelsList {
|
|
||||||
.primary-message {
|
|
||||||
margin-top: 8px;
|
|
||||||
color: var(--center-channel-color);
|
|
||||||
line-height: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary-message {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primaryButton {
|
|
||||||
background-color: var(--button-bg);
|
|
||||||
border-radius: 4px;
|
|
||||||
color: var(--button-color);
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
#createNewChannelButton {
|
|
||||||
padding: 10px 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ import {shallow} from 'enzyme';
|
|||||||
import {ActionResult} from 'mattermost-redux/types/actions';
|
import {ActionResult} from 'mattermost-redux/types/actions';
|
||||||
|
|
||||||
import MoreChannels, {Props} from 'components/more_channels/more_channels';
|
import MoreChannels, {Props} from 'components/more_channels/more_channels';
|
||||||
import SearchableChannelList from 'components/more_channels/searchable_channel_list.jsx';
|
import SearchableChannelList from 'components/searchable_channel_list.jsx';
|
||||||
|
|
||||||
import {getHistory} from 'utils/browser_history';
|
import {getHistory} from 'utils/browser_history';
|
||||||
import {TestHelper} from 'utils/test_helper';
|
import {TestHelper} from 'utils/test_helper';
|
||||||
@@ -59,16 +59,7 @@ describe('components/MoreChannels', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const baseProps: Props = {
|
const baseProps: Props = {
|
||||||
channels: [
|
channels: [TestHelper.getChannelMock({})],
|
||||||
TestHelper.getChannelMock({
|
|
||||||
id: 'channel-1',
|
|
||||||
name: 'channel-1',
|
|
||||||
}),
|
|
||||||
TestHelper.getChannelMock({
|
|
||||||
id: 'channel-2',
|
|
||||||
name: 'channel-2',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
archivedChannels: [TestHelper.getChannelMock({
|
archivedChannels: [TestHelper.getChannelMock({
|
||||||
id: 'channel_id_2',
|
id: 'channel_id_2',
|
||||||
team_id: 'channel_team_2',
|
team_id: 'channel_team_2',
|
||||||
@@ -82,14 +73,6 @@ describe('components/MoreChannels', () => {
|
|||||||
teamName: 'team_name',
|
teamName: 'team_name',
|
||||||
channelsRequestStarted: false,
|
channelsRequestStarted: false,
|
||||||
canShowArchivedChannels: true,
|
canShowArchivedChannels: true,
|
||||||
myChannelMemberships: {
|
|
||||||
'channel-2': TestHelper.getChannelMembershipMock({
|
|
||||||
channel_id: 'channel-2',
|
|
||||||
user_id: 'user-1',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
allChannelStats: {},
|
|
||||||
shouldHideJoinedChannels: false,
|
|
||||||
actions: {
|
actions: {
|
||||||
getChannels: jest.fn(),
|
getChannels: jest.fn(),
|
||||||
getArchivedChannels: jest.fn(),
|
getArchivedChannels: jest.fn(),
|
||||||
@@ -97,8 +80,6 @@ describe('components/MoreChannels', () => {
|
|||||||
searchMoreChannels: jest.fn(channelActions.searchMoreChannels),
|
searchMoreChannels: jest.fn(channelActions.searchMoreChannels),
|
||||||
openModal: jest.fn(),
|
openModal: jest.fn(),
|
||||||
closeModal: jest.fn(),
|
closeModal: jest.fn(),
|
||||||
getChannelStats: jest.fn(),
|
|
||||||
setGlobalItem: jest.fn(),
|
|
||||||
closeRightHandSide: jest.fn(),
|
closeRightHandSide: jest.fn(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -110,6 +91,7 @@ describe('components/MoreChannels', () => {
|
|||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
expect(wrapper.state('searchedChannels')).toEqual([]);
|
expect(wrapper.state('searchedChannels')).toEqual([]);
|
||||||
|
expect(wrapper.state('show')).toEqual(true);
|
||||||
expect(wrapper.state('shouldShowArchivedChannels')).toEqual(false);
|
expect(wrapper.state('shouldShowArchivedChannels')).toEqual(false);
|
||||||
expect(wrapper.state('search')).toEqual(false);
|
expect(wrapper.state('search')).toEqual(false);
|
||||||
expect(wrapper.state('serverError')).toBeNull();
|
expect(wrapper.state('serverError')).toBeNull();
|
||||||
@@ -120,6 +102,16 @@ describe('components/MoreChannels', () => {
|
|||||||
expect(wrapper.instance().props.actions.getChannels).toHaveBeenCalledWith(wrapper.instance().props.teamId, 0, 100);
|
expect(wrapper.instance().props.actions.getChannels).toHaveBeenCalledWith(wrapper.instance().props.teamId, 0, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should match state on handleHide', () => {
|
||||||
|
const wrapper = shallow<MoreChannels>(
|
||||||
|
<MoreChannels {...baseProps}/>,
|
||||||
|
);
|
||||||
|
wrapper.setState({show: true});
|
||||||
|
|
||||||
|
wrapper.instance().handleHide();
|
||||||
|
expect(wrapper.state('show')).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
test('should call closeModal on handleExit', () => {
|
test('should call closeModal on handleExit', () => {
|
||||||
const wrapper = shallow<MoreChannels>(
|
const wrapper = shallow<MoreChannels>(
|
||||||
<MoreChannels {...baseProps}/>,
|
<MoreChannels {...baseProps}/>,
|
||||||
@@ -160,7 +152,7 @@ describe('components/MoreChannels', () => {
|
|||||||
<MoreChannels {...baseProps}/>,
|
<MoreChannels {...baseProps}/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
wrapper.setState({loading: false, search: true, searching: true});
|
wrapper.setState({search: true, searching: true});
|
||||||
const searchList = wrapper.find(SearchableChannelList);
|
const searchList = wrapper.find(SearchableChannelList);
|
||||||
expect(searchList.props().loading).toEqual(true);
|
expect(searchList.props().loading).toEqual(true);
|
||||||
});
|
});
|
||||||
@@ -219,6 +211,7 @@ describe('components/MoreChannels', () => {
|
|||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
expect(getHistory().push).toHaveBeenCalledTimes(1);
|
expect(getHistory().push).toHaveBeenCalledTimes(1);
|
||||||
expect(callback).toHaveBeenCalledTimes(1);
|
expect(callback).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.state('show')).toEqual(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -256,7 +249,7 @@ describe('components/MoreChannels', () => {
|
|||||||
|
|
||||||
jest.runOnlyPendingTimers();
|
jest.runOnlyPendingTimers();
|
||||||
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledTimes(1);
|
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledTimes(1);
|
||||||
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledWith('fail', false, false);
|
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledWith('fail', false);
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
expect(wrapper.state('search')).toEqual(true);
|
expect(wrapper.state('search')).toEqual(true);
|
||||||
expect(wrapper.state('searching')).toEqual(false);
|
expect(wrapper.state('searching')).toEqual(false);
|
||||||
@@ -283,7 +276,7 @@ describe('components/MoreChannels', () => {
|
|||||||
|
|
||||||
jest.runOnlyPendingTimers();
|
jest.runOnlyPendingTimers();
|
||||||
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledTimes(1);
|
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledTimes(1);
|
||||||
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledWith('channel', false, false);
|
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledWith('channel', false);
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
expect(wrapper.state('search')).toEqual(true);
|
expect(wrapper.state('search')).toEqual(true);
|
||||||
expect(wrapper.state('searching')).toEqual(false);
|
expect(wrapper.state('searching')).toEqual(false);
|
||||||
@@ -310,7 +303,7 @@ describe('components/MoreChannels', () => {
|
|||||||
|
|
||||||
jest.runOnlyPendingTimers();
|
jest.runOnlyPendingTimers();
|
||||||
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledTimes(1);
|
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledTimes(1);
|
||||||
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledWith('channel', true, false);
|
expect(wrapper.instance().props.actions.searchMoreChannels).toHaveBeenCalledWith('channel', true);
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
expect(wrapper.state('search')).toEqual(true);
|
expect(wrapper.state('search')).toEqual(true);
|
||||||
expect(wrapper.state('searching')).toEqual(false);
|
expect(wrapper.state('searching')).toEqual(false);
|
||||||
@@ -318,16 +311,4 @@ describe('components/MoreChannels', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should hide joined channels from channels props when shouldHideJoinedChannels prop is true', () => {
|
|
||||||
const props = {
|
|
||||||
...baseProps,
|
|
||||||
shouldHideJoinedChannels: true,
|
|
||||||
};
|
|
||||||
const wrapper = shallow<MoreChannels>(
|
|
||||||
<MoreChannels {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper.instance().activeChannels).not.toContain(baseProps.channels[1]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,32 +2,23 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Modal} from 'react-bootstrap';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import {ActionResult} from 'mattermost-redux/types/actions';
|
import {ActionResult} from 'mattermost-redux/types/actions';
|
||||||
import {Channel, ChannelMembership, ChannelStats} from '@mattermost/types/channels';
|
import {Channel} from '@mattermost/types/channels';
|
||||||
import Permissions from 'mattermost-redux/constants/permissions';
|
import Permissions from 'mattermost-redux/constants/permissions';
|
||||||
|
|
||||||
import {RelationOneToOne} from '@mattermost/types/utilities';
|
|
||||||
|
|
||||||
import NewChannelModal from 'components/new_channel_modal/new_channel_modal';
|
import NewChannelModal from 'components/new_channel_modal/new_channel_modal';
|
||||||
|
import SearchableChannelList from 'components/searchable_channel_list.jsx';
|
||||||
import TeamPermissionGate from 'components/permissions_gates/team_permission_gate';
|
import TeamPermissionGate from 'components/permissions_gates/team_permission_gate';
|
||||||
import GenericModal from 'components/generic_modal';
|
|
||||||
import LoadingScreen from 'components/loading_screen';
|
|
||||||
|
|
||||||
import {ModalData} from 'types/actions';
|
import {ModalData} from 'types/actions';
|
||||||
import {RhsState} from 'types/store/rhs';
|
import {RhsState} from 'types/store/rhs';
|
||||||
|
|
||||||
import {getHistory} from 'utils/browser_history';
|
import {getHistory} from 'utils/browser_history';
|
||||||
import {ModalIdentifiers, StoragePrefixes, RHSStates} from 'utils/constants';
|
import {ModalIdentifiers, RHSStates} from 'utils/constants';
|
||||||
import {getRelativeChannelURL} from 'utils/url';
|
import {getRelativeChannelURL} from 'utils/url';
|
||||||
import {localizeMessage} from 'utils/utils';
|
|
||||||
|
|
||||||
import SearchableChannelList from './searchable_channel_list';
|
|
||||||
|
|
||||||
import './more_channels.scss';
|
|
||||||
|
|
||||||
const CHANNELS_CHUNK_SIZE = 50;
|
const CHANNELS_CHUNK_SIZE = 50;
|
||||||
const CHANNELS_PER_PAGE = 50;
|
const CHANNELS_PER_PAGE = 50;
|
||||||
@@ -37,15 +28,9 @@ type Actions = {
|
|||||||
getChannels: (teamId: string, page: number, perPage: number) => void;
|
getChannels: (teamId: string, page: number, perPage: number) => void;
|
||||||
getArchivedChannels: (teamId: string, page: number, channelsPerPage: number) => void;
|
getArchivedChannels: (teamId: string, page: number, channelsPerPage: number) => void;
|
||||||
joinChannel: (currentUserId: string, teamId: string, channelId: string) => Promise<ActionResult>;
|
joinChannel: (currentUserId: string, teamId: string, channelId: string) => Promise<ActionResult>;
|
||||||
searchMoreChannels: (term: string, shouldShowArchivedChannels: boolean, shouldHideJoinedChannels: boolean) => Promise<ActionResult>;
|
searchMoreChannels: (term: string, shouldShowArchivedChannels: boolean) => Promise<ActionResult>;
|
||||||
openModal: <P>(modalData: ModalData<P>) => void;
|
openModal: <P>(modalData: ModalData<P>) => void;
|
||||||
closeModal: (modalId: string) => void;
|
closeModal: (modalId: string) => void;
|
||||||
getChannelStats: (channelId: string) => void;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function to set a key-value pair in the local storage
|
|
||||||
*/
|
|
||||||
setGlobalItem: (name: string, value: string) => void;
|
|
||||||
closeRightHandSide: () => void;
|
closeRightHandSide: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,27 +43,23 @@ export type Props = {
|
|||||||
channelsRequestStarted?: boolean;
|
channelsRequestStarted?: boolean;
|
||||||
canShowArchivedChannels?: boolean;
|
canShowArchivedChannels?: boolean;
|
||||||
morePublicChannelsModalType?: string;
|
morePublicChannelsModalType?: string;
|
||||||
myChannelMemberships: RelationOneToOne<Channel, ChannelMembership>;
|
|
||||||
allChannelStats: RelationOneToOne<Channel, ChannelStats>;
|
|
||||||
shouldHideJoinedChannels: boolean;
|
|
||||||
rhsState?: RhsState;
|
rhsState?: RhsState;
|
||||||
rhsOpen?: boolean;
|
rhsOpen?: boolean;
|
||||||
actions: Actions;
|
actions: Actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
show: boolean;
|
||||||
shouldShowArchivedChannels: boolean;
|
shouldShowArchivedChannels: boolean;
|
||||||
search: boolean;
|
search: boolean;
|
||||||
searchedChannels: Channel[];
|
searchedChannels: Channel[];
|
||||||
serverError: React.ReactNode | string;
|
serverError: React.ReactNode | string;
|
||||||
searching: boolean;
|
searching: boolean;
|
||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
loading: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class MoreChannels extends React.PureComponent<Props, State> {
|
export default class MoreChannels extends React.PureComponent<Props, State> {
|
||||||
public searchTimeoutId: number;
|
public searchTimeoutId: number;
|
||||||
activeChannels: Channel[] = [];
|
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -86,27 +67,25 @@ export default class MoreChannels extends React.PureComponent<Props, State> {
|
|||||||
this.searchTimeoutId = 0;
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
show: true,
|
||||||
shouldShowArchivedChannels: this.props.morePublicChannelsModalType === 'private',
|
shouldShowArchivedChannels: this.props.morePublicChannelsModalType === 'private',
|
||||||
search: false,
|
search: false,
|
||||||
searchedChannels: [],
|
searchedChannels: [],
|
||||||
serverError: null,
|
serverError: null,
|
||||||
searching: false,
|
searching: false,
|
||||||
searchTerm: '',
|
searchTerm: '',
|
||||||
loading: true,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
componentDidMount() {
|
||||||
await this.props.actions.getChannels(this.props.teamId, 0, CHANNELS_CHUNK_SIZE * 2);
|
this.props.actions.getChannels(this.props.teamId, 0, CHANNELS_CHUNK_SIZE * 2);
|
||||||
if (this.props.canShowArchivedChannels) {
|
if (this.props.canShowArchivedChannels) {
|
||||||
await this.props.actions.getArchivedChannels(this.props.teamId, 0, CHANNELS_CHUNK_SIZE * 2);
|
this.props.actions.getArchivedChannels(this.props.teamId, 0, CHANNELS_CHUNK_SIZE * 2);
|
||||||
}
|
}
|
||||||
await this.props.channels.forEach((channel) => this.props.actions.getChannelStats(channel.id));
|
|
||||||
this.loadComplete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadComplete = () => {
|
handleHide = () => {
|
||||||
this.setState({loading: false});
|
this.setState({show: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewChannel = () => {
|
handleNewChannel = () => {
|
||||||
@@ -145,17 +124,14 @@ export default class MoreChannels extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
handleJoin = async (channel: Channel, done: () => void) => {
|
handleJoin = async (channel: Channel, done: () => void) => {
|
||||||
const {actions, currentUserId, teamId, teamName} = this.props;
|
const {actions, currentUserId, teamId, teamName} = this.props;
|
||||||
let result;
|
const result = await actions.joinChannel(currentUserId, teamId, channel.id);
|
||||||
|
|
||||||
if (!this.isMemberOfChannel(channel.id)) {
|
if (result.error) {
|
||||||
result = await actions.joinChannel(currentUserId, teamId, channel.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result?.error) {
|
|
||||||
this.setState({serverError: result.error.message});
|
this.setState({serverError: result.error.message});
|
||||||
} else {
|
} else {
|
||||||
getHistory().push(getRelativeChannelURL(teamName, channel.name));
|
getHistory().push(getRelativeChannelURL(teamName, channel.name));
|
||||||
this.closeEditRHS();
|
this.closeEditRHS();
|
||||||
|
this.handleHide();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
@@ -177,7 +153,7 @@ export default class MoreChannels extends React.PureComponent<Props, State> {
|
|||||||
const searchTimeoutId = window.setTimeout(
|
const searchTimeoutId = window.setTimeout(
|
||||||
async () => {
|
async () => {
|
||||||
try {
|
try {
|
||||||
const {data} = await this.props.actions.searchMoreChannels(term, this.state.shouldShowArchivedChannels, this.props.shouldHideJoinedChannels);
|
const {data} = await this.props.actions.searchMoreChannels(term, this.state.shouldShowArchivedChannels);
|
||||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -207,47 +183,29 @@ export default class MoreChannels extends React.PureComponent<Props, State> {
|
|||||||
this.setState({shouldShowArchivedChannels});
|
this.setState({shouldShowArchivedChannels});
|
||||||
}
|
}
|
||||||
|
|
||||||
isMemberOfChannel(channelId: string) {
|
|
||||||
return this.props.myChannelMemberships[channelId];
|
|
||||||
}
|
|
||||||
|
|
||||||
handleShowJoinedChannelsPreference = (shouldHideJoinedChannels: boolean) => {
|
|
||||||
// search again when switching channels to update search results
|
|
||||||
this.search(this.state.searchTerm);
|
|
||||||
this.props.actions.setGlobalItem(StoragePrefixes.HIDE_JOINED_CHANNELS, shouldHideJoinedChannels.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
otherChannelsWithoutJoined = this.props.channels.filter((channel) => !this.isMemberOfChannel(channel.id));
|
|
||||||
archivedChannelsWithoutJoined = this.props.archivedChannels.filter((channel) => !this.isMemberOfChannel(channel.id));
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
channels,
|
channels,
|
||||||
archivedChannels,
|
archivedChannels,
|
||||||
teamId,
|
teamId,
|
||||||
channelsRequestStarted,
|
channelsRequestStarted,
|
||||||
shouldHideJoinedChannels,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
search,
|
search,
|
||||||
searchedChannels,
|
searchedChannels,
|
||||||
serverError: serverErrorState,
|
serverError: serverErrorState,
|
||||||
|
show,
|
||||||
searching,
|
searching,
|
||||||
shouldShowArchivedChannels,
|
shouldShowArchivedChannels,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const otherChannelsWithoutJoined = channels.filter((channel) => !this.isMemberOfChannel(channel.id));
|
let activeChannels;
|
||||||
const archivedChannelsWithoutJoined = archivedChannels.filter((channel) => !this.isMemberOfChannel(channel.id));
|
|
||||||
|
|
||||||
if (shouldShowArchivedChannels && shouldHideJoinedChannels) {
|
if (shouldShowArchivedChannels) {
|
||||||
this.activeChannels = search ? searchedChannels : archivedChannelsWithoutJoined;
|
activeChannels = search ? searchedChannels : archivedChannels;
|
||||||
} else if (shouldShowArchivedChannels && !shouldHideJoinedChannels) {
|
|
||||||
this.activeChannels = search ? searchedChannels : archivedChannels;
|
|
||||||
} else if (!shouldShowArchivedChannels && shouldHideJoinedChannels) {
|
|
||||||
this.activeChannels = search ? searchedChannels : otherChannelsWithoutJoined;
|
|
||||||
} else {
|
} else {
|
||||||
this.activeChannels = search ? searchedChannels : channels;
|
activeChannels = search ? searchedChannels : channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
let serverError;
|
let serverError;
|
||||||
@@ -256,87 +214,87 @@ export default class MoreChannels extends React.PureComponent<Props, State> {
|
|||||||
<div className='form-group has-error'><label className='control-label'>{serverErrorState}</label></div>;
|
<div className='form-group has-error'><label className='control-label'>{serverErrorState}</label></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createNewChannelButton = (className: string, icon?: JSX.Element) => {
|
const createNewChannelButton = (
|
||||||
const buttonClassName = classNames('btn', className);
|
<TeamPermissionGate
|
||||||
return (
|
teamId={teamId}
|
||||||
<TeamPermissionGate
|
permissions={[Permissions.CREATE_PUBLIC_CHANNEL]}
|
||||||
teamId={teamId}
|
>
|
||||||
permissions={[Permissions.CREATE_PUBLIC_CHANNEL]}
|
<button
|
||||||
|
id='createNewChannel'
|
||||||
|
type='button'
|
||||||
|
className='btn btn-primary channel-create-btn'
|
||||||
|
onClick={this.handleNewChannel}
|
||||||
>
|
>
|
||||||
<button
|
|
||||||
type='button'
|
|
||||||
id='createNewChannelButton'
|
|
||||||
className={buttonClassName}
|
|
||||||
onClick={this.handleNewChannel}
|
|
||||||
aria-label={localizeMessage('more_channels.create', 'Create New Channel')}
|
|
||||||
>
|
|
||||||
{icon}
|
|
||||||
<FormattedMessage
|
|
||||||
id='more_channels.create'
|
|
||||||
defaultMessage='Create New Channel'
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</TeamPermissionGate>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const noResultsText = (
|
|
||||||
<>
|
|
||||||
<p className='secondary-message'>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='more_channels.searchError'
|
id='more_channels.create'
|
||||||
defaultMessage='Try searching different keywords, checking for typos or adjusting the filters.'
|
defaultMessage='Create Channel'
|
||||||
/>
|
/>
|
||||||
</p>
|
</button>
|
||||||
{createNewChannelButton('primaryButton', <i className='icon-plus'/>)}
|
</TeamPermissionGate>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const body = this.state.loading ? <LoadingScreen/> : (
|
const createChannelHelpText = (
|
||||||
|
<TeamPermissionGate
|
||||||
|
teamId={teamId}
|
||||||
|
permissions={[Permissions.CREATE_PUBLIC_CHANNEL, Permissions.CREATE_PRIVATE_CHANNEL]}
|
||||||
|
>
|
||||||
|
<p className='secondary-message'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='more_channels.createClick'
|
||||||
|
defaultMessage="Click 'Create New Channel' to make a new one"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</TeamPermissionGate>
|
||||||
|
);
|
||||||
|
|
||||||
|
const body = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<SearchableChannelList
|
<SearchableChannelList
|
||||||
channels={this.activeChannels}
|
channels={activeChannels}
|
||||||
channelsPerPage={CHANNELS_PER_PAGE}
|
channelsPerPage={CHANNELS_PER_PAGE}
|
||||||
nextPage={this.nextPage}
|
nextPage={this.nextPage}
|
||||||
isSearch={search}
|
isSearch={search}
|
||||||
search={this.search}
|
search={this.search}
|
||||||
handleJoin={this.handleJoin}
|
handleJoin={this.handleJoin}
|
||||||
noResultsText={noResultsText}
|
noResultsText={createChannelHelpText}
|
||||||
loading={search ? searching : channelsRequestStarted}
|
loading={search ? searching : channelsRequestStarted}
|
||||||
toggleArchivedChannels={this.toggleArchivedChannels}
|
toggleArchivedChannels={this.toggleArchivedChannels}
|
||||||
shouldShowArchivedChannels={this.state.shouldShowArchivedChannels}
|
shouldShowArchivedChannels={this.state.shouldShowArchivedChannels}
|
||||||
canShowArchivedChannels={this.props.canShowArchivedChannels}
|
canShowArchivedChannels={this.props.canShowArchivedChannels}
|
||||||
myChannelMemberships={this.props.myChannelMemberships}
|
|
||||||
allChannelStats={this.props.allChannelStats}
|
|
||||||
closeModal={this.props.actions.closeModal}
|
|
||||||
hideJoinedChannelsPreference={this.handleShowJoinedChannelsPreference}
|
|
||||||
rememberHideJoinedChannelsChecked={shouldHideJoinedChannels}
|
|
||||||
/>
|
/>
|
||||||
{serverError}
|
{serverError}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
||||||
const title = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='more_channels.title'
|
|
||||||
defaultMessage='Browse Channels'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GenericModal
|
<Modal
|
||||||
|
dialogClassName='a11y__modal more-modal more-modal--action'
|
||||||
|
show={show}
|
||||||
|
onHide={this.handleHide}
|
||||||
onExited={this.handleExit}
|
onExited={this.handleExit}
|
||||||
compassDesign={true}
|
role='dialog'
|
||||||
id='moreChannelsModal'
|
id='moreChannelsModal'
|
||||||
aria-labelledby='moreChannelsModalLabel'
|
aria-labelledby='moreChannelsModalLabel'
|
||||||
modalHeaderText={title}
|
|
||||||
headerButton={createNewChannelButton('outlineButton')}
|
|
||||||
autoCloseOnConfirmButton={false}
|
|
||||||
aria-modal={true}
|
|
||||||
enforceFocus={false}
|
|
||||||
>
|
>
|
||||||
{body}
|
<Modal.Header
|
||||||
</GenericModal>
|
id='moreChannelsModalHeader'
|
||||||
|
closeButton={true}
|
||||||
|
>
|
||||||
|
<Modal.Title
|
||||||
|
componentClass='h1'
|
||||||
|
id='moreChannelsModalLabel'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='more_channels.title'
|
||||||
|
defaultMessage='More Channels'
|
||||||
|
/>
|
||||||
|
</Modal.Title>
|
||||||
|
{createNewChannelButton}
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
{body}
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,483 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
|
||||||
|
|
||||||
import {AccountOutlineIcon, ArchiveOutlineIcon, CheckIcon, ChevronDownIcon, GlobeIcon, LockOutlineIcon, MagnifyIcon} from '@mattermost/compass-icons/components';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import {isPrivateChannel} from 'mattermost-redux/utils/channel_utils';
|
|
||||||
|
|
||||||
import LoadingScreen from 'components/loading_screen';
|
|
||||||
import LoadingWrapper from 'components/widgets/loading/loading_wrapper';
|
|
||||||
import QuickInput from 'components/quick_input';
|
|
||||||
import LocalizedInput from 'components/localized_input/localized_input';
|
|
||||||
import CheckboxCheckedIcon from 'components/widgets/icons/checkbox_checked_icon';
|
|
||||||
import MagnifyingGlassSVG from 'components/common/svg_images_components/magnifying_glass_svg';
|
|
||||||
import MenuWrapper from 'components/widgets/menu/menu_wrapper';
|
|
||||||
import Menu from 'components/widgets/menu/menu';
|
|
||||||
|
|
||||||
import {t} from 'utils/i18n';
|
|
||||||
import * as UserAgent from 'utils/user_agent';
|
|
||||||
import Constants, {ModalIdentifiers} from 'utils/constants';
|
|
||||||
import {isKeyPressed, localizeMessage, localizeAndFormatMessage} from 'utils/utils';
|
|
||||||
|
|
||||||
import {isArchivedChannel} from 'utils/channel_utils';
|
|
||||||
|
|
||||||
const NEXT_BUTTON_TIMEOUT_MILLISECONDS = 500;
|
|
||||||
|
|
||||||
export default class SearchableChannelList extends React.PureComponent {
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
|
||||||
return {isSearch: props.isSearch, page: props.isSearch && !state.isSearch ? 0 : state.page};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.nextTimeoutId = 0;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
joiningChannel: '',
|
|
||||||
page: 0,
|
|
||||||
nextDisabled: false,
|
|
||||||
channelSearchValue: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
this.filter = React.createRef();
|
|
||||||
this.channelListScroll = React.createRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
// only focus the search box on desktop so that we don't cause the keyboard to open on mobile
|
|
||||||
if (!UserAgent.isMobile() && this.filter.current) {
|
|
||||||
this.filter.current.focus();
|
|
||||||
}
|
|
||||||
document.addEventListener('keydown', this.onKeyDown);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
document.removeEventListener('keydown', this.onKeyDown);
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyDown = (e) => {
|
|
||||||
const target = e.target;
|
|
||||||
const isEnterKeyPressed = isKeyPressed(e, Constants.KeyCodes.ENTER);
|
|
||||||
if (isEnterKeyPressed && (e.shiftKey || e.ctrlKey || e.altKey)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isEnterKeyPressed && target.classList.contains('more-modal__row')) {
|
|
||||||
target.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleJoin = (channel, e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
this.setState({joiningChannel: channel.id});
|
|
||||||
this.props.handleJoin(
|
|
||||||
channel,
|
|
||||||
() => {
|
|
||||||
this.setState({joiningChannel: ''});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (this.isMemberOfChannel(channel.id)) {
|
|
||||||
this.props.closeModal(ModalIdentifiers.MORE_CHANNELS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isMemberOfChannel(channelId) {
|
|
||||||
return this.props.myChannelMemberships[channelId];
|
|
||||||
}
|
|
||||||
|
|
||||||
createChannelRow = (channel) => {
|
|
||||||
const ariaLabel = `${channel.display_name}, ${channel.purpose}`.toLowerCase();
|
|
||||||
let channelTypeIcon;
|
|
||||||
|
|
||||||
let memberCount = 0;
|
|
||||||
if (this.props.allChannelStats[channel.id]) {
|
|
||||||
memberCount = this.props.allChannelStats[channel.id].member_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isArchivedChannel(channel)) {
|
|
||||||
channelTypeIcon = <ArchiveOutlineIcon size={18}/>;
|
|
||||||
} else if (isPrivateChannel(channel)) {
|
|
||||||
channelTypeIcon = <LockOutlineIcon size={18}/>;
|
|
||||||
} else {
|
|
||||||
channelTypeIcon = <GlobeIcon size={18}/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const membershipIndicator = this.isMemberOfChannel(channel.id) ? (
|
|
||||||
<div
|
|
||||||
id='membershipIndicatorContainer'
|
|
||||||
aria-label={localizeMessage('more_channels.membership_indicator', 'Membership Indicator: Joined')}
|
|
||||||
>
|
|
||||||
<CheckIcon size={14}/>
|
|
||||||
<FormattedMessage
|
|
||||||
id={'more_channels.joined'}
|
|
||||||
defaultMessage={'Joined'}
|
|
||||||
/>
|
|
||||||
<span className='dot'/>
|
|
||||||
</div>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
const channelPurposeContainerAriaLabel = localizeAndFormatMessage(
|
|
||||||
t('more_channels.channel_purpose'),
|
|
||||||
'Channel Information: Membership Indicator: Joined, Member count {memberCount} , Purpose: {channelPurpose}',
|
|
||||||
{memberCount, channelPurpose: channel.purpose || ''},
|
|
||||||
);
|
|
||||||
|
|
||||||
const channelPurposeContainer = (
|
|
||||||
<div
|
|
||||||
id='channelPurposeContainer'
|
|
||||||
aria-label={channelPurposeContainerAriaLabel}
|
|
||||||
>
|
|
||||||
{membershipIndicator}
|
|
||||||
<AccountOutlineIcon size={14}/>
|
|
||||||
<span>{memberCount}</span>
|
|
||||||
{channel.purpose.length > 0 && <span className='dot'/>}
|
|
||||||
<span className='more-modal__description'>{channel.purpose}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const joinViewChannelButtonClass = classNames('btn', {
|
|
||||||
outlineButton: this.isMemberOfChannel(channel.id),
|
|
||||||
primaryButton: !this.isMemberOfChannel(channel.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
const joinViewChannelButton = (
|
|
||||||
<button
|
|
||||||
id='joinViewChannelButton'
|
|
||||||
onClick={(e) => this.handleJoin(channel, e)}
|
|
||||||
className={joinViewChannelButtonClass}
|
|
||||||
disabled={this.state.joiningChannel}
|
|
||||||
tabIndex={-1}
|
|
||||||
aria-label={this.isMemberOfChannel(channel.id) ? localizeMessage('more_channels.view', 'View') : localizeMessage('joinChannel.JoinButton', 'Join')}
|
|
||||||
>
|
|
||||||
<LoadingWrapper
|
|
||||||
loading={this.state.joiningChannel === channel.id}
|
|
||||||
text={localizeMessage('joinChannel.joiningButton', 'Joining...')}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id={this.isMemberOfChannel(channel.id) ? 'more_channels.view' : 'joinChannel.JoinButton'}
|
|
||||||
defaultMessage={this.isMemberOfChannel(channel.id) ? 'View' : 'Join'}
|
|
||||||
/>
|
|
||||||
</LoadingWrapper>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='more-modal__row'
|
|
||||||
key={channel.id}
|
|
||||||
id={`ChannelRow-${channel.name}`}
|
|
||||||
aria-label={ariaLabel}
|
|
||||||
onClick={(e) => this.handleJoin(channel, e)}
|
|
||||||
tabIndex={0}
|
|
||||||
>
|
|
||||||
<div className='more-modal__details'>
|
|
||||||
<div className='style--none more-modal__name'>
|
|
||||||
{channelTypeIcon}
|
|
||||||
<span id='channelName'>{channel.display_name}</span>
|
|
||||||
</div>
|
|
||||||
{channelPurposeContainer}
|
|
||||||
</div>
|
|
||||||
<div className='more-modal__actions'>
|
|
||||||
{joinViewChannelButton}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPage = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
this.setState({page: this.state.page + 1, nextDisabled: true});
|
|
||||||
this.nextTimeoutId = setTimeout(() => this.setState({nextDisabled: false}), NEXT_BUTTON_TIMEOUT_MILLISECONDS);
|
|
||||||
this.props.nextPage(this.state.page + 1);
|
|
||||||
this.channelListScroll.current?.scrollTo({top: 0});
|
|
||||||
}
|
|
||||||
|
|
||||||
previousPage = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
this.setState({page: this.state.page - 1});
|
|
||||||
this.channelListScroll.current?.scrollTo({top: 0});
|
|
||||||
}
|
|
||||||
|
|
||||||
doSearch = () => {
|
|
||||||
this.props.search(this.state.channelSearchValue);
|
|
||||||
if (this.state.channelSearchValue === '') {
|
|
||||||
this.setState({page: 0});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange = (e) => {
|
|
||||||
if (e.target) {
|
|
||||||
this.setState({channelSearchValue: e.target.value}, () => this.doSearch());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClear = () => {
|
|
||||||
this.setState({channelSearchValue: ''}, () => this.doSearch());
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleArchivedChannelsOn = () => {
|
|
||||||
this.props.toggleArchivedChannels(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleArchivedChannelsOff = () => {
|
|
||||||
this.props.toggleArchivedChannels(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChecked = () => {
|
|
||||||
// If it was checked, and now we're unchecking it, clear the preference
|
|
||||||
if (this.props.rememberHideJoinedChannelsChecked) {
|
|
||||||
this.props.hideJoinedChannelsPreference(false);
|
|
||||||
} else {
|
|
||||||
this.props.hideJoinedChannelsPreference(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const channels = this.props.channels;
|
|
||||||
let listContent;
|
|
||||||
let nextButton;
|
|
||||||
let previousButton;
|
|
||||||
|
|
||||||
let emptyStateMessage = (
|
|
||||||
<FormattedMessage
|
|
||||||
id={this.props.shouldShowArchivedChannels ? t('more_channels.noArchived') : t('more_channels.noPublic')}
|
|
||||||
tagName='strong'
|
|
||||||
defaultMessage={this.props.shouldShowArchivedChannels ? 'No archived channels' : 'No public channels'}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.state.channelSearchValue.length > 0) {
|
|
||||||
emptyStateMessage = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='more_channels.noMore'
|
|
||||||
tagName='strong'
|
|
||||||
defaultMessage='No results for {text}'
|
|
||||||
values={{
|
|
||||||
text: this.state.channelSearchValue,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.loading && channels.length === 0) {
|
|
||||||
listContent = <LoadingScreen/>;
|
|
||||||
} else if (channels.length === 0) {
|
|
||||||
listContent = (
|
|
||||||
<div
|
|
||||||
className='no-channel-message'
|
|
||||||
aria-label={this.state.channelSearchValue.length > 0 ?
|
|
||||||
localizeAndFormatMessage(t('more_channels.noMore'), 'No results for {text}', {text: this.state.channelSearchValue}) :
|
|
||||||
localizeMessage('widgets.channels_input.empty', 'No channels found')
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MagnifyingGlassSVG/>
|
|
||||||
<h3 className='primary-message'>
|
|
||||||
{emptyStateMessage}
|
|
||||||
</h3>
|
|
||||||
{this.props.noResultsText}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const pageStart = this.state.page * this.props.channelsPerPage;
|
|
||||||
const pageEnd = pageStart + this.props.channelsPerPage;
|
|
||||||
const channelsToDisplay = this.props.channels.slice(pageStart, pageEnd);
|
|
||||||
listContent = channelsToDisplay.map(this.createChannelRow);
|
|
||||||
|
|
||||||
if (channelsToDisplay.length >= this.props.channelsPerPage && pageEnd < this.props.channels.length) {
|
|
||||||
nextButton = (
|
|
||||||
<button
|
|
||||||
className='btn filter-control filter-control__next outlineButton'
|
|
||||||
onClick={this.nextPage}
|
|
||||||
disabled={this.state.nextDisabled}
|
|
||||||
aria-label={localizeMessage('more_channels.next', 'Next')}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='more_channels.next'
|
|
||||||
defaultMessage='Next'
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.page > 0) {
|
|
||||||
previousButton = (
|
|
||||||
<button
|
|
||||||
className='btn filter-control filter-control__prev outlineButton'
|
|
||||||
onClick={this.previousPage}
|
|
||||||
aria-label={localizeMessage('more_channels.prev', 'Previous')}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='more_channels.prev'
|
|
||||||
defaultMessage='Previous'
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const input = (
|
|
||||||
<div className='filter-row filter-row--full'>
|
|
||||||
<span
|
|
||||||
id='searchIcon'
|
|
||||||
aria-hidden='true'
|
|
||||||
>
|
|
||||||
<MagnifyIcon size={18}/>
|
|
||||||
</span>
|
|
||||||
<QuickInput
|
|
||||||
id='searchChannelsTextbox'
|
|
||||||
ref={this.filter}
|
|
||||||
className='form-control filter-textbox'
|
|
||||||
placeholder={{id: t('filtered_channels_list.search'), defaultMessage: 'Search channels'}}
|
|
||||||
inputComponent={LocalizedInput}
|
|
||||||
onInput={this.handleChange}
|
|
||||||
clearable={true}
|
|
||||||
onClear={this.handleClear}
|
|
||||||
value={this.state.channelSearchValue}
|
|
||||||
aria-label={localizeMessage('filtered_channels_list.search', 'Search Channels')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
let channelDropdown;
|
|
||||||
let checkIcon;
|
|
||||||
|
|
||||||
if (this.props.canShowArchivedChannels) {
|
|
||||||
checkIcon = (
|
|
||||||
<CheckIcon
|
|
||||||
size={18}
|
|
||||||
color={'var(--button-bg)'}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
channelDropdown = (
|
|
||||||
<MenuWrapper id='channelsMoreDropdown'>
|
|
||||||
<a id='menuWrapper'>
|
|
||||||
<span>{this.props.shouldShowArchivedChannels ? localizeMessage('more_channels.show_archived_channels', 'Channel Type: Archived') : localizeMessage('more_channels.show_public_channels', 'Channel Type: Public')}</span>
|
|
||||||
<ChevronDownIcon
|
|
||||||
color={'rgba(var(--center-channel-color-rgb), 0.64)'}
|
|
||||||
size={16}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<Menu
|
|
||||||
openLeft={false}
|
|
||||||
ariaLabel={localizeMessage('more_channels.title', 'Browse channels')}
|
|
||||||
>
|
|
||||||
<div id='modalPreferenceContainer'>
|
|
||||||
<Menu.ItemAction
|
|
||||||
id='channelsMoreDropdownPublic'
|
|
||||||
onClick={this.toggleArchivedChannelsOff}
|
|
||||||
icon={<GlobeIcon size={16}/>}
|
|
||||||
text={localizeMessage('suggestion.search.public', 'Public Channels')}
|
|
||||||
rightDecorator={this.props.shouldShowArchivedChannels ? null : checkIcon}
|
|
||||||
ariaLabel={localizeMessage('suggestion.search.public', 'Public Channels')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Menu.ItemAction
|
|
||||||
id='channelsMoreDropdownArchived'
|
|
||||||
onClick={this.toggleArchivedChannelsOn}
|
|
||||||
icon={<ArchiveOutlineIcon size={16}/>}
|
|
||||||
text={localizeMessage('suggestion.archive', 'Archived Channels')}
|
|
||||||
rightDecorator={this.props.shouldShowArchivedChannels ? checkIcon : null}
|
|
||||||
ariaLabel={localizeMessage('suggestion.archive', 'Archived Channels')}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
</MenuWrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const hideJoinedButtonClass = classNames('get-app__checkbox', {checked: this.props.rememberHideJoinedChannelsChecked});
|
|
||||||
const hideJoinedPreferenceCheckbox = (
|
|
||||||
<div
|
|
||||||
id={'hideJoinedPreferenceCheckbox'}
|
|
||||||
onClick={this.handleChecked}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className={hideJoinedButtonClass}
|
|
||||||
aria-label={this.props.rememberHideJoinedChannelsChecked ? localizeMessage('more_channels.hide_joined_checked', 'Hide joined channels checkbox, checked') : localizeMessage('more_channels.hide_joined_not_checked', 'Hide joined channels checkbox, not checked')
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.props.rememberHideJoinedChannelsChecked ? <CheckboxCheckedIcon/> : null}
|
|
||||||
</button>
|
|
||||||
<FormattedMessage
|
|
||||||
id='more_channels.hide_joined'
|
|
||||||
defaultMessage='Hide Joined'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
let channelCountLabel;
|
|
||||||
if (channels.length === 0) {
|
|
||||||
channelCountLabel = localizeMessage('more_channels.count_zero', '0 Results');
|
|
||||||
} else if (channels.length === 1) {
|
|
||||||
channelCountLabel = localizeMessage('more_channels.count_one', '1 Result');
|
|
||||||
} else if (channels.length > 1) {
|
|
||||||
channelCountLabel = localizeAndFormatMessage(t('more_channels.count'), '0 Results', {count: channels.length});
|
|
||||||
} else {
|
|
||||||
channelCountLabel = localizeMessage('more_channels.count_zero', '0 Results');
|
|
||||||
}
|
|
||||||
|
|
||||||
const dropDownContainer = (
|
|
||||||
<div className='more-modal__dropdown'>
|
|
||||||
<span id='channelCountLabel'>{channelCountLabel}</span>
|
|
||||||
<div id='modalPreferenceContainer'>
|
|
||||||
{channelDropdown}
|
|
||||||
{hideJoinedPreferenceCheckbox}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='filtered-user-list'>
|
|
||||||
{input}
|
|
||||||
{dropDownContainer}
|
|
||||||
<div
|
|
||||||
role='application'
|
|
||||||
className='more-modal__list'
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
id='moreChannelsList'
|
|
||||||
tabIndex={-1}
|
|
||||||
ref={this.channelListScroll}
|
|
||||||
>
|
|
||||||
{listContent}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='filter-controls'>
|
|
||||||
{previousButton}
|
|
||||||
{nextButton}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchableChannelList.defaultProps = {
|
|
||||||
channels: [],
|
|
||||||
isSearch: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
SearchableChannelList.propTypes = {
|
|
||||||
channels: PropTypes.arrayOf(PropTypes.object),
|
|
||||||
channelsPerPage: PropTypes.number,
|
|
||||||
nextPage: PropTypes.func.isRequired,
|
|
||||||
isSearch: PropTypes.bool,
|
|
||||||
search: PropTypes.func.isRequired,
|
|
||||||
handleJoin: PropTypes.func.isRequired,
|
|
||||||
noResultsText: PropTypes.object,
|
|
||||||
loading: PropTypes.bool,
|
|
||||||
toggleArchivedChannels: PropTypes.func.isRequired,
|
|
||||||
shouldShowArchivedChannels: PropTypes.bool.isRequired,
|
|
||||||
canShowArchivedChannels: PropTypes.bool.isRequired,
|
|
||||||
myChannelMemberships: PropTypes.object.isRequired,
|
|
||||||
allChannelStats: PropTypes.object.isRequired,
|
|
||||||
closeModal: PropTypes.func.isRequired,
|
|
||||||
hideJoinedChannelsPreference: PropTypes.func.isRequired,
|
|
||||||
rememberHideJoinedChannelsChecked: PropTypes.bool.isRequired,
|
|
||||||
};
|
|
||||||
/* eslint-enable react/no-string-refs */
|
|
||||||
319
webapp/channels/src/components/searchable_channel_list.jsx
Обычный файл
319
webapp/channels/src/components/searchable_channel_list.jsx
Обычный файл
@@ -0,0 +1,319 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
|
import {ArchiveOutlineIcon} from '@mattermost/compass-icons/components';
|
||||||
|
|
||||||
|
import LoadingScreen from 'components/loading_screen';
|
||||||
|
import LoadingWrapper from 'components/widgets/loading/loading_wrapper';
|
||||||
|
import QuickInput from 'components/quick_input';
|
||||||
|
import * as UserAgent from 'utils/user_agent';
|
||||||
|
import {localizeMessage} from 'utils/utils';
|
||||||
|
import LocalizedInput from 'components/localized_input/localized_input';
|
||||||
|
|
||||||
|
import SharedChannelIndicator from 'components/shared_channel_indicator';
|
||||||
|
|
||||||
|
import {t} from 'utils/i18n';
|
||||||
|
|
||||||
|
import MenuWrapper from './widgets/menu/menu_wrapper';
|
||||||
|
import Menu from './widgets/menu/menu';
|
||||||
|
|
||||||
|
const NEXT_BUTTON_TIMEOUT_MILLISECONDS = 500;
|
||||||
|
|
||||||
|
export default class SearchableChannelList extends React.PureComponent {
|
||||||
|
static getDerivedStateFromProps(props, state) {
|
||||||
|
return {isSearch: props.isSearch, page: props.isSearch && !state.isSearch ? 0 : state.page};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.nextTimeoutId = 0;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
joiningChannel: '',
|
||||||
|
page: 0,
|
||||||
|
nextDisabled: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.filter = React.createRef();
|
||||||
|
this.channelListScroll = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// only focus the search box on desktop so that we don't cause the keyboard to open on mobile
|
||||||
|
if (!UserAgent.isMobile() && this.filter.current) {
|
||||||
|
this.filter.current.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleJoin(channel) {
|
||||||
|
this.setState({joiningChannel: channel.id});
|
||||||
|
this.props.handleJoin(
|
||||||
|
channel,
|
||||||
|
() => {
|
||||||
|
this.setState({joiningChannel: ''});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
createChannelRow = (channel) => {
|
||||||
|
const ariaLabel = `${channel.display_name}, ${channel.purpose}`.toLowerCase();
|
||||||
|
let archiveIcon;
|
||||||
|
let sharedIcon;
|
||||||
|
const {shouldShowArchivedChannels} = this.props;
|
||||||
|
|
||||||
|
if (shouldShowArchivedChannels) {
|
||||||
|
archiveIcon = (
|
||||||
|
<ArchiveOutlineIcon
|
||||||
|
size={20}
|
||||||
|
color={'currentColor'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel.shared) {
|
||||||
|
sharedIcon = (
|
||||||
|
<SharedChannelIndicator
|
||||||
|
className='shared-channel-icon'
|
||||||
|
channelType={channel.type}
|
||||||
|
withTooltip={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className='more-modal__row'
|
||||||
|
key={channel.id}
|
||||||
|
id={`ChannelRow-${channel.name}`}
|
||||||
|
>
|
||||||
|
<div className='more-modal__details'>
|
||||||
|
<button
|
||||||
|
onClick={this.handleJoin.bind(this, channel)}
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
className='style--none more-modal__name'
|
||||||
|
>
|
||||||
|
{archiveIcon}
|
||||||
|
{channel.display_name}
|
||||||
|
{sharedIcon}
|
||||||
|
</button>
|
||||||
|
<p className='more-modal__description'>{channel.purpose}</p>
|
||||||
|
</div>
|
||||||
|
<div className='more-modal__actions'>
|
||||||
|
<button
|
||||||
|
onClick={this.handleJoin.bind(this, channel)}
|
||||||
|
className='btn btn-primary'
|
||||||
|
disabled={this.state.joiningChannel}
|
||||||
|
>
|
||||||
|
<LoadingWrapper
|
||||||
|
loading={this.state.joiningChannel === channel.id}
|
||||||
|
text={localizeMessage('more_channels.joining', 'Joining...')}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id={shouldShowArchivedChannels ? t('more_channels.view') : t('more_channels.join')}
|
||||||
|
defaultMessage={shouldShowArchivedChannels ? 'View' : 'Join'}
|
||||||
|
/>
|
||||||
|
</LoadingWrapper>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPage = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({page: this.state.page + 1, nextDisabled: true});
|
||||||
|
this.nextTimeoutId = setTimeout(() => this.setState({nextDisabled: false}), NEXT_BUTTON_TIMEOUT_MILLISECONDS);
|
||||||
|
this.props.nextPage(this.state.page + 1);
|
||||||
|
this.channelListScroll.current?.scrollTo({top: 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
previousPage = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({page: this.state.page - 1});
|
||||||
|
this.channelListScroll.current?.scrollTo({top: 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
doSearch = () => {
|
||||||
|
const term = this.filter.current.value;
|
||||||
|
this.props.search(term);
|
||||||
|
if (term === '') {
|
||||||
|
this.setState({page: 0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toggleArchivedChannelsOn = () => {
|
||||||
|
this.props.toggleArchivedChannels(true);
|
||||||
|
}
|
||||||
|
toggleArchivedChannelsOff = () => {
|
||||||
|
this.props.toggleArchivedChannels(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const channels = this.props.channels;
|
||||||
|
let listContent;
|
||||||
|
let nextButton;
|
||||||
|
let previousButton;
|
||||||
|
|
||||||
|
if (this.props.loading && channels.length === 0) {
|
||||||
|
listContent = <LoadingScreen/>;
|
||||||
|
} else if (channels.length === 0) {
|
||||||
|
listContent = (
|
||||||
|
<div className='no-channel-message'>
|
||||||
|
<h3 className='primary-message'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='more_channels.noMore'
|
||||||
|
tagName='strong'
|
||||||
|
defaultMessage='No more channels to join'
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
|
{this.props.noResultsText}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const pageStart = this.state.page * this.props.channelsPerPage;
|
||||||
|
const pageEnd = pageStart + this.props.channelsPerPage;
|
||||||
|
const channelsToDisplay = this.props.channels.slice(pageStart, pageEnd);
|
||||||
|
listContent = channelsToDisplay.map(this.createChannelRow);
|
||||||
|
|
||||||
|
if (channelsToDisplay.length >= this.props.channelsPerPage && pageEnd < this.props.channels.length) {
|
||||||
|
nextButton = (
|
||||||
|
<button
|
||||||
|
className='btn btn-link filter-control filter-control__next'
|
||||||
|
onClick={this.nextPage}
|
||||||
|
disabled={this.state.nextDisabled}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='more_channels.next'
|
||||||
|
defaultMessage='Next'
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.page > 0) {
|
||||||
|
previousButton = (
|
||||||
|
<button
|
||||||
|
className='btn btn-link filter-control filter-control__prev'
|
||||||
|
onClick={this.previousPage}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='more_channels.prev'
|
||||||
|
defaultMessage='Previous'
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = (
|
||||||
|
<div className='filter-row filter-row--full'>
|
||||||
|
<div className='col-sm-12'>
|
||||||
|
<QuickInput
|
||||||
|
id='searchChannelsTextbox'
|
||||||
|
ref={this.filter}
|
||||||
|
className='form-control filter-textbox'
|
||||||
|
placeholder={{id: t('filtered_channels_list.search'), defaultMessage: 'Search channels'}}
|
||||||
|
inputComponent={LocalizedInput}
|
||||||
|
onInput={this.doSearch}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.props.createChannelButton) {
|
||||||
|
input = (
|
||||||
|
<div className='channel_search'>
|
||||||
|
<div className='search_input'>
|
||||||
|
<QuickInput
|
||||||
|
id='searchChannelsTextbox'
|
||||||
|
ref={this.filter}
|
||||||
|
className='form-control filter-textbox'
|
||||||
|
placeholder={{id: t('filtered_channels_list.search'), defaultMessage: 'Search channels'}}
|
||||||
|
inputComponent={LocalizedInput}
|
||||||
|
onInput={this.doSearch}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='create_button'>
|
||||||
|
{this.props.createChannelButton}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let channelDropdown;
|
||||||
|
|
||||||
|
if (this.props.canShowArchivedChannels) {
|
||||||
|
channelDropdown = (
|
||||||
|
<div className='more-modal__dropdown'>
|
||||||
|
<MenuWrapper id='channelsMoreDropdown'>
|
||||||
|
<a>
|
||||||
|
<span>{this.props.shouldShowArchivedChannels ? localizeMessage('more_channels.show_archived_channels', 'Show: Archived Channels') : localizeMessage('more_channels.show_public_channels', 'Show: Public Channels')}</span>
|
||||||
|
<span className='caret'/>
|
||||||
|
</a>
|
||||||
|
<Menu
|
||||||
|
openLeft={false}
|
||||||
|
ariaLabel={localizeMessage('team_members_dropdown.menuAriaLabel', 'Change the role of a team member')}
|
||||||
|
>
|
||||||
|
<Menu.ItemAction
|
||||||
|
id='channelsMoreDropdownPublic'
|
||||||
|
onClick={this.toggleArchivedChannelsOff}
|
||||||
|
text={localizeMessage('suggestion.search.public', 'Public Channels')}
|
||||||
|
/>
|
||||||
|
<Menu.ItemAction
|
||||||
|
id='channelsMoreDropdownArchived'
|
||||||
|
onClick={this.toggleArchivedChannelsOn}
|
||||||
|
text={localizeMessage('suggestion.archive', 'Archived Channels')}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
</MenuWrapper>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='filtered-user-list'>
|
||||||
|
{input}
|
||||||
|
{channelDropdown}
|
||||||
|
<div
|
||||||
|
role='application'
|
||||||
|
className='more-modal__list'
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
id='moreChannelsList'
|
||||||
|
ref={this.channelListScroll}
|
||||||
|
>
|
||||||
|
{listContent}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='filter-controls'>
|
||||||
|
{previousButton}
|
||||||
|
{nextButton}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchableChannelList.defaultProps = {
|
||||||
|
channels: [],
|
||||||
|
isSearch: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
SearchableChannelList.propTypes = {
|
||||||
|
channels: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
channelsPerPage: PropTypes.number,
|
||||||
|
nextPage: PropTypes.func.isRequired,
|
||||||
|
isSearch: PropTypes.bool,
|
||||||
|
search: PropTypes.func.isRequired,
|
||||||
|
handleJoin: PropTypes.func.isRequired,
|
||||||
|
noResultsText: PropTypes.object,
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
createChannelButton: PropTypes.element,
|
||||||
|
toggleArchivedChannels: PropTypes.func.isRequired,
|
||||||
|
shouldShowArchivedChannels: PropTypes.bool.isRequired,
|
||||||
|
canShowArchivedChannels: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
@@ -4,25 +4,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {shallow} from 'enzyme';
|
import {shallow} from 'enzyme';
|
||||||
|
|
||||||
import SearchableChannelList from './searchable_channel_list.jsx';
|
import SearchableChannelList from 'components/searchable_channel_list.jsx';
|
||||||
|
|
||||||
describe('components/SearchableChannelList', () => {
|
describe('components/SearchableChannelList', () => {
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
channels: [],
|
channels: [],
|
||||||
isSearch: false,
|
isSearch: false,
|
||||||
channelsPerPage: 10,
|
channelsPerPage: 10,
|
||||||
nextPage: jest.fn(),
|
nextPage: () => {}, // eslint-disable-line no-empty-function
|
||||||
search: jest.fn(),
|
search: () => {}, // eslint-disable-line no-empty-function
|
||||||
handleJoin: jest.fn(),
|
handleJoin: () => {}, // eslint-disable-line no-empty-function
|
||||||
loading: true,
|
loading: true,
|
||||||
rememberHideJoinedChannelsChecked: false,
|
toggleArchivedChannels: () => {}, // eslint-disable-line no-empty-function
|
||||||
toggleArchivedChannels: jest.fn(),
|
|
||||||
shouldShowArchivedChannels: false,
|
shouldShowArchivedChannels: false,
|
||||||
canShowArchivedChannels: false,
|
canShowArchivedChannels: false,
|
||||||
myChannelMemberships: {},
|
|
||||||
allChannelStats: {},
|
|
||||||
closeModal: jest.fn(),
|
|
||||||
hideJoinedChannelsPreference: jest.fn(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should match init snapshot', () => {
|
test('should match init snapshot', () => {
|
||||||
@@ -4155,22 +4155,13 @@
|
|||||||
"modal.manual_status.title_dnd": "Your Status is Set to \"Do Not Disturb\"",
|
"modal.manual_status.title_dnd": "Your Status is Set to \"Do Not Disturb\"",
|
||||||
"modal.manual_status.title_offline": "Your Status is Set to \"Offline\"",
|
"modal.manual_status.title_offline": "Your Status is Set to \"Offline\"",
|
||||||
"modal.manual_status.title_ooo": "Your Status is Set to \"Out of Office\"",
|
"modal.manual_status.title_ooo": "Your Status is Set to \"Out of Office\"",
|
||||||
"more_channels.channel_purpose": "Channel Information: Membership Indicator: Joined, Member count {memberCount} , Purpose: {channelPurpose}",
|
|
||||||
"more_channels.count": "{count} Results",
|
|
||||||
"more_channels.count_one": "1 Result",
|
|
||||||
"more_channels.count_zero": "0 Results",
|
|
||||||
"more_channels.create": "Create New Channel",
|
"more_channels.create": "Create New Channel",
|
||||||
"more_channels.hide_joined": "Hide Joined",
|
"more_channels.createClick": "Click 'Create New Channel' to make a new one",
|
||||||
"more_channels.hide_joined_checked": "Hide joined channels checkbox, checked",
|
"more_channels.join": "Join",
|
||||||
"more_channels.hide_joined_not_checked": "Hide joined channels checkbox, not checked",
|
"more_channels.joining": "Joining...",
|
||||||
"more_channels.joined": "Joined",
|
|
||||||
"more_channels.membership_indicator": "Membership Indicator: Joined",
|
|
||||||
"more_channels.next": "Next",
|
"more_channels.next": "Next",
|
||||||
"more_channels.noArchived": "No archived channels",
|
|
||||||
"more_channels.noMore": "No results for \"{text}\"",
|
"more_channels.noMore": "No results for \"{text}\"",
|
||||||
"more_channels.noPublic": "No public channels",
|
|
||||||
"more_channels.prev": "Previous",
|
"more_channels.prev": "Previous",
|
||||||
"more_channels.searchError": "Try searching different keywords, checking for typos or adjusting the filters.",
|
|
||||||
"more_channels.show_archived_channels": "Channel Type: Archived",
|
"more_channels.show_archived_channels": "Channel Type: Archived",
|
||||||
"more_channels.show_public_channels": "Channel Type: Public",
|
"more_channels.show_public_channels": "Channel Type: Public",
|
||||||
"more_channels.title": "Browse Channels",
|
"more_channels.title": "Browse Channels",
|
||||||
|
|||||||
@@ -71,9 +71,7 @@
|
|||||||
|
|
||||||
.primary-message {
|
.primary-message {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--center-channel-color);
|
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
line-height: 28px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -896,7 +896,6 @@ export const StoragePrefixes = {
|
|||||||
CHANNEL_CATEGORY_COLLAPSED: 'channelCategoryCollapsed_',
|
CHANNEL_CATEGORY_COLLAPSED: 'channelCategoryCollapsed_',
|
||||||
INLINE_IMAGE_VISIBLE: 'isInlineImageVisible_',
|
INLINE_IMAGE_VISIBLE: 'isInlineImageVisible_',
|
||||||
DELINQUENCY: 'delinquency_',
|
DELINQUENCY: 'delinquency_',
|
||||||
HIDE_JOINED_CHANNELS: 'hideJoinedChannels',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LandingPreferenceTypes = {
|
export const LandingPreferenceTypes = {
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ export type Props = {
|
|||||||
compassDesign?: boolean;
|
compassDesign?: boolean;
|
||||||
backdrop?: boolean;
|
backdrop?: boolean;
|
||||||
backdropClassName?: string;
|
backdropClassName?: string;
|
||||||
headerButton?: React.ReactNode;
|
|
||||||
tabIndex?: number;
|
tabIndex?: number;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
keyboardEscape?: boolean;
|
keyboardEscape?: boolean;
|
||||||
@@ -166,7 +165,6 @@ export class GenericModal extends React.PureComponent<Props, State> {
|
|||||||
<h1 id='genericModalLabel'>
|
<h1 id='genericModalLabel'>
|
||||||
{this.props.modalHeaderText}
|
{this.props.modalHeaderText}
|
||||||
</h1>
|
</h1>
|
||||||
{this.props.headerButton}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user