Commit 33979b98 authored by Derrick Anderson's avatar Derrick Anderson
Browse files

Merge branch 'merge410rc5'

parents c0b766c8 9bbfb61b
......@@ -10,7 +10,10 @@ export default class CustomPluginSettings extends SchemaAdminSettings {
}
componentWillReceiveProps(nextProps) {
if (!this.props.schema && nextProps.schema) {
const id = this.props.schema ? this.props.schema.id : '';
const nextId = nextProps.schema ? nextProps.schema.id : '';
if ((!this.props.schema && nextProps.schema) || (id !== nextId)) {
this.setState(this.getStateFromConfig(nextProps.config, nextProps.schema));
}
}
......
......@@ -56,7 +56,17 @@ export default class AnnouncementBar extends React.PureComponent {
this.setInitialError();
this.state = this.getState();
this.state = this.getState(props);
}
componentWillReceiveProps(nextProps) {
if (nextProps.enableBanner !== this.props.enableBanner ||
nextProps.bannerText !== this.props.bannerText ||
nextProps.bannerColor !== this.props.bannerColor ||
nextProps.bannerTextColor !== this.props.bannerTextColor ||
nextProps.allowBannerDismissal !== this.props.allowBannerDismissal) {
this.setState(this.getState(nextProps));
}
}
setInitialError = () => {
......@@ -85,17 +95,17 @@ export default class AnnouncementBar extends React.PureComponent {
}
}
getState() {
getState(props = this.props) {
const error = ErrorStore.getLastError();
if (error && error.message) {
return {message: error.message, color: null, textColor: null, type: error.type, allowDismissal: true};
}
const bannerText = this.props.bannerText || '';
const allowDismissal = this.props.allowBannerDismissal;
const bannerDismissed = localStorage.getItem(StoragePrefixes.ANNOUNCEMENT + this.props.bannerText);
const bannerText = props.bannerText || '';
const allowDismissal = props.allowBannerDismissal;
const bannerDismissed = localStorage.getItem(StoragePrefixes.ANNOUNCEMENT + props.bannerText);
if (this.props.enableBanner &&
if (props.enableBanner &&
bannerText.length > 0 &&
(!bannerDismissed || !allowDismissal)
) {
......@@ -103,8 +113,8 @@ export default class AnnouncementBar extends React.PureComponent {
Utils.removePrefixFromLocalStorage(StoragePrefixes.ANNOUNCEMENT);
return {
message: bannerText,
color: this.props.bannerColor,
textColor: this.props.bannerTextColor,
color: props.bannerColor,
textColor: props.bannerTextColor,
type: BAR_ANNOUNCEMENT_TYPE,
allowDismissal,
};
......
......@@ -267,16 +267,15 @@ export default class PostList extends React.PureComponent {
}
const messageSeparator = this.refs.newMessageSeparator;
if (messageSeparator) {
// Scroll to new message indicator since we have unread posts
// Scroll to new message indicator since we have unread posts and we can't show every new post in the screen
if (messageSeparator && (postList.scrollHeight - messageSeparator.offsetTop) > postList.clientHeight) {
messageSeparator.scrollIntoView();
if (!this.checkBottom()) {
this.setUnreadsBelow(posts, this.props.currentUserId);
}
this.setUnreadsBelow(posts, this.props.currentUserId);
return true;
}
// Scroll to bottom since we don't have unread posts
// Scroll to bottom since we don't have unread posts or we can show every new post in the screen
postList.scrollTop = postList.scrollHeight;
this.atBottom = true;
return true;
......
......@@ -17,7 +17,12 @@ import {getMyChannelMemberships} from 'mattermost-redux/selectors/entities/commo
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {searchProfiles, getUserIdsInChannels, getUser} from 'mattermost-redux/selectors/entities/users';
import {
getCurrentUserId,
getUserIdsInChannels,
getUser,
searchProfiles,
} from 'mattermost-redux/selectors/entities/users';
import GlobeIcon from 'components/svg/globe_icon';
import LockIcon from 'components/svg/lock_icon';
......@@ -240,9 +245,10 @@ export default class SwitchChannelProvider extends Provider {
}
const users = Object.assign([], searchProfiles(state, channelPrefix, false)).concat(usersFromServer.users);
const currentUserId = getCurrentUserId(state);
store.dispatch({
type: UserTypes.RECEIVED_PROFILES_LIST,
data: users,
data: users.filter((user) => user.id !== currentUserId),
});
const channels = getChannelsInCurrentTeam(state).concat(getDirectChannels(state)).concat(channelsFromServer);
this.formatChannelsAndDispatch(channelPrefix, suggestionId, channels, users);
......
......@@ -21,7 +21,7 @@ export default [
title: (
<FormattedHTMLMessage
id='system_notice.title'
defaultMessage='<strong>System Message</strong> from Mattermost'
defaultMessage='<strong>Notice</strong> from Mattermost'
/>
),
icon: mattermostIcon,
......
......@@ -93,6 +93,19 @@ export default class SystemNotice extends React.PureComponent {
return null;
}
let visibleMessage;
if (notice.adminOnly) {
visibleMessage = (
<div className='system-notice__info'>
<i className='fa fa-eye'/>
<FormattedMessage
id='system_notice.adminVisible'
defaultMessage='Only visible to System Admins'
/>
</div>
);
}
return (
<div
className='system-notice bg--white shadow--2'
......@@ -108,6 +121,7 @@ export default class SystemNotice extends React.PureComponent {
<div className='system-notice__body'>
{notice.body}
</div>
{visibleMessage}
<div className='system-notice__footer'>
<button
id='systemnotice_remindme'
......
This diff is collapsed.
......@@ -2715,7 +2715,8 @@
"system_notice.body.api3": "If you’ve created or installed integrations in the last two years, find out how <a href=\"https://about.mattermost.com/default-apiv3-deprecation-guide\" target=\"_blank\">upcoming changes</a> may affect them.",
"system_notice.dont_show": "Don't show again",
"system_notice.remind_me": "Remind me later",
"system_notice.title": "<strong>System Message</strong><br>from Mattermost",
"system_notice.title": "<strong>Notice</strong><br>from Mattermost",
"system_notice.adminVisible": "Only visible to System Admins",
"system_users_list.count": "{count, number} {count, plural, one {user} other {users}}",
"system_users_list.countPage": "{startCount, number} - {endCount, number} {count, plural, one {user} other {users}} of {total, number} total",
"system_users_list.countSearch": "{count, number} {count, plural, one {user} other {users}} of {total, number} total",
......
This diff is collapsed.
This diff is collapsed.
......@@ -1372,7 +1372,7 @@
"channel_header.addToFavorites": "Добавить в избранное",
"channel_header.channelHeader": "Изменить заголовок канала",
"channel_header.channelMembers": "Участники",
"channel_header.convert": "Convert to Private Channel",
"channel_header.convert": "Преобразование в приватный канал",
"channel_header.delete": "Удалить канал",
"channel_header.directchannel.you": "{displayname} (you) ",
"channel_header.flagged": "Отмеченные сообщения",
......
......@@ -685,23 +685,23 @@
"admin.license.upload": "Yükle",
"admin.license.uploadDesc": "Bu sunucuyu yükseltmek için bir Mattermost Enterprise Sürümü lisans anahtarı yükleyin. Enterprise sürümün katacaklarını öğrenmek ve bir anahtar satın almak için <a href=\"http://mattermost.com\" target='_blank'>sitemize bakın</a>.",
"admin.license.uploading": "Lisans Yükleniyor...",
"admin.log.consoleDescription": "Bu seçenek genel olarak üretim ortamında devre dışı bırakılır. Geliştiriciler günlük iletilerini konsola göndermek için bu seçeneği etkinleştirebilir. Bu seçenek etkinleştirildiğinde iletiler standart çıktı akışına (stdout) yazılır.",
"admin.log.consoleJsonTitle": "Output console logs as JSON:",
"admin.log.consoleDescription": "Bu seçenek genel olarak üretim ortamında devre dışı bırakılır. Geliştiriciler günlüğe kaydedilen iletileri konsola göndermek için bu seçeneği etkinleştirebilir. Bu seçenek etkinleştirildiğinde iletiler standart çıktı akışına (stdout) yazılır. Bu seçenek değiştirildiğinde yeni ayarın etkili olması için sunucunun yeniden başlatılması gerekir.",
"admin.log.consoleJsonTitle": "Konsol günlüğü kayıtları JSON olarak kaydedilsin:",
"admin.log.consoleLogLevel": "Konsol Günlüğü Düzeyi:",
"admin.log.consoleTitle": "Günlükler konsola gönderilsin: ",
"admin.log.enableDiagnostics": "Tanılama ve Hata Bildirme Kulanılsın:",
"admin.log.enableDiagnosticsDescription": "Bu seçenek etkinleştirildiğinde, Mattermost kalitesini ve başarımını arttırmaya yardımcı olacak hata bildirimleri ve tanılama bilgileri gönderilir. Ayrıntılı bilgi almak için <a href=\"https://about.mattermost.com/default-privacy-policy/\" target='_blank'>gizlilik ilkemize</a> bakın.",
"admin.log.enableWebhookDebugging": "Web Bağlantısı Hata Ayıklaması Kullanılsın:",
"admin.log.enableWebhookDebuggingDescription": "Gelen web bağlantılarının istek gövdesinin konsolda görüntülenmesi için bu seçeneği etkinleştirin ve {boldedConsoleLogLevel} ayarını 'HATA AYIKLAMA' olarak seçin. HATA AYIKLAMA kipinde konsol günlüklerinde web bağlantısı isteği gövdesi bilgilerinin görüntülenmemesi için bu seçeneği devre dışı bırakın.",
"admin.log.fileDescription": "Bu seçenek genel olarak üretim ortamında etkinleştirilir. Etkinleştirildiğinde, günlüğe yazılan işlemler Dosya Günlüğü Klasörü alanında belirtilen klasördeki mattermost.log dosyasına yazılır. Günlükler 10,000 satıra ulaştığında aynı klasörde tarih damgası ve seri numarası ile adlandırılarak arşivlenir. Örnek: mattermost.201703-31.001.",
"admin.log.fileJsonTitle": "Output file logs as JSON:",
"admin.log.fileDescription": "Bu seçenek genel olarak üretim ortamında etkinleştirilir. Etkinleştirildiğinde, günlüğe kaydedilen işlemler Dosya Günlüğü Klasörü alanında belirtilen klasördeki mattermost.log dosyasına yazılır. Günlük kayıtları 10,000 satıra ulaştığında aynı klasörde tarih damgası ve seri numarası ile adlandırılarak arşivlenir. Örnek: mattermost.2017-03-31.001. Bu seçenek değiştirildiğinde yeni ayarın etkili olması için sunucunun yeniden başlatılması gerekir.",
"admin.log.fileJsonTitle": "Dosya günlüğü kayıtları JSON olarak kaydedilsin:",
"admin.log.fileLevelDescription": "Bu seçenek dosya günlüklemesinin hangi düzeyde yapılacağını belirtir. ERROR: Yalnız hata iletileri kaydedilir. INFO: Hata ile başlatma ve hazırlık iletileri kaydedilir. DEBUG: Geliştiricilerin sorunlar üzerinde çalışmasına yardımcı olan ayrıntılı bilgiler kaydedilir.",
"admin.log.fileLevelTitle": "Dosya Günlüğü Düzeyi:",
"admin.log.fileTitle": "Günlükler dosyaya yazılsın: ",
"admin.log.jsonDescription": "When true, logged events are written in a machine readable JSON format. Otherwise they are printed as plain text. Changing this setting requires a server restart before taking effect.",
"admin.log.jsonDescription": "Bu seçenek etkinleştirildiğinde, günlüğe kaydedilen işlemler makine tarafından okunabilecek JSON biçiminde kaydedilir. Devre dışı bırakıldığında, düz metin olarak görüntülenir. Bu seçenek değiştirildiğinde yeni ayarın etkili olması için sunucunun yeniden başlatılması gerekir.",
"admin.log.levelDescription": "Bu seçenek konsol günlüklemesinin hangi düzeyde yapılacağını belirtir. ERROR: Yalnız hata iletileri kaydedilir. INFO: Hata ile başlatma ve hazırlık iletileri kaydedilir. DEBUG: Geliştiricilerin sorunlar üzerinde çalışmasına yardımcı olan ayrıntılı bilgiler kaydedilir.",
"admin.log.levelTitle": "Konsol Günlüğü Düzeyi:",
"admin.log.locationDescription": "The location of the log files. If blank, they are stored in the ./logs directory. The path that you set must exist and Mattermost must have write permissions in it. Changing this setting requires a server restart before taking effect.",
"admin.log.locationDescription": "Günlük dosyalarının konumu. Boş bırakılırsa ./logs klasörü kullanılır. Ayarlanacak klasörün var olması ve Mattermost tarafından yazılabiliyor olması gereklidir. Bu seçenek değiştirildiğinde yeni ayarın etkili olması için sunucunun yeniden başlatılması gerekir.",
"admin.log.locationPlaceholder": "Dosyanızın konumunu yazın",
"admin.log.locationTitle": "Dosya Günlüğü Klasörü:",
"admin.log.logSettings": "Günlük Ayarları",
......
......@@ -122,7 +122,7 @@
}
.post__header {
padding-right: 70px;
padding-right: 85px;
}
.search-channel__name {
......
......@@ -38,10 +38,20 @@
text-overflow: ellipsis;
}
.system-notice__info {
@include opacity(.5);
font-size: 12px;
margin-bottom: 12px;
.fa {
margin-right: 4px;
}
}
.system-notice__body {
@include opacity(.7);
line-height: 16px;
padding: 18px 0 20px;
padding: 18px 0 16px;
}
.system-notice__footer {
......
......@@ -843,15 +843,18 @@
}
blockquote {
display: flex;
font-size: 1em;
margin-left: 0;
padding: 3px 0 2px 25px;
padding: 0;
vertical-align: top;
&:before {
display: inline-block;
font-size: 15px;
left: 4px;
top: 2px;
left: 0;
margin-right: 5px;
position: relative;
top: 0;
}
}
......
......@@ -19,7 +19,7 @@
}
&.sidebar--right--expanded {
z-index: 11;
z-index: 15;
}
.sidebar--right__bg {
......
......@@ -282,12 +282,6 @@
top: 1px;
}
blockquote {
&:first-child {
margin-left: 53px;
}
}
&.same--root {
&.same--user {
padding-left: 77px;
......@@ -299,12 +293,6 @@
top: 4px;
}
blockquote {
&:first-child {
margin-left: 0;
}
}
.post__header {
.col__reply {
top: -1px;
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/AnnouncementBar should match snapshot, bar not showing 1`] = `<div />`;
exports[`components/AnnouncementBar should match snapshot, bar showing 1`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "black",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, bar showing, no dismissal 1`] = `
<div
className="error-bar error-bar--fixed"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, dismissal 1`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "black",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, dismissal 2`] = `<div />`;
exports[`components/AnnouncementBar should match snapshot, dismissal 3`] = `<div />`;
exports[`components/AnnouncementBar should match snapshot, dismissal 4`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "yellow",
"color": "red",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Some new text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "red",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 1`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "black",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 2`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "yellow",
"color": "red",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "red",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 3`] = `
<div
className="error-bar error-bar--fixed"
style={
Object {
"backgroundColor": "yellow",
"color": "red",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 4`] = `<div />`;
......@@ -23,6 +23,18 @@ exports[`components/SystemNotice should match snapshot for admin, admin notice 1
>
some body
</div>
<div
className="system-notice__info"
>
<i
className="fa fa-eye"
/>
<FormattedMessage
defaultMessage="Only visible to System Admins"
id="system_notice.adminVisible"
values={Object {}}
/>
</div>
<div
className="system-notice__footer"
>
......
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {shallow} from 'enzyme';
import 'tests/helpers/localstorage.jsx';
import AnnouncementBar from 'components/announcement_bar/announcement_bar.jsx';
describe('components/AnnouncementBar', () => {
const baseProps = {
isLoggedIn: true,
canViewSystemErrors: false,
canViewAPIv3Banner: false,
licenseId: '',
siteURL: '',
sendEmailNotifications: true,
bannerText: 'Banner text',
allowBannerDismissal: true,
enableBanner: true,
bannerColor: 'green',
bannerTextColor: 'black',
enableSignUpWithGitLab: false,
};
test('should match snapshot, bar showing', () => {
const props = baseProps;
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, bar not showing', () => {
const props = {...baseProps, enableBanner: false};
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, bar showing, no dismissal', () => {
const props = {...baseProps, allowBannerDismissal: false};
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, props change', () => {
const props = baseProps;
const wrapper = shallow(
<AnnouncementBar {...props}/>