MM-54181 : Clean up code around deprecated Gfycat (#24343)

* first pass of removal

* first pass of removal

* Update admin_console.js

* rev beta

* remove more

* Update initial_state.ts

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
M-ZubairAhmed 2023-09-06 02:10:37 +05:30 committed by GitHub
parent 77fa1c5824
commit bac317dfe5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 0 additions and 2740 deletions

View File

@ -13,8 +13,6 @@
"EnableCustomEmoji": false,
"EnableEmojiPicker": true,
"EnableGifPicker": false,
"GfycatAPIKey": "2_KtH_W5",
"GfycatAPISecret": "3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof",
"PostEditTimeLimit": -1,
"EnablePreviewFeatures": true,
"EnableTutorial": true,

View File

@ -52,8 +52,6 @@
"EnableCustomEmoji": false,
"EnableEmojiPicker": true,
"EnableGifPicker": false,
"GfycatAPIKey": "2_KtH_W5",
"GfycatAPISecret": "3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof",
"PostEditTimeLimit": -1,
"TimeBetweenUserTypingUpdatesMilliseconds": 5000,
"EnablePostSearch": true,

View File

@ -127,8 +127,6 @@ const defaultServerConfig: AdminConfig = {
WebsocketPort: 80,
WebserverMode: 'gzip',
EnableGifPicker: true,
GfycatAPIKey: '2_KtH_W5',
GfycatAPISecret: '3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof',
GiphySdkKey: 's0glxvzVg9azvPipKxcPLpXV0q1x1fVP',
EnableCustomEmoji: true,
EnableEmojiPicker: true,

View File

@ -79,8 +79,6 @@ func GenerateClientConfig(c *model.Config, telemetryID string, license *model.Li
props["EnableEmojiPicker"] = strconv.FormatBool(*c.ServiceSettings.EnableEmojiPicker)
props["EnableGifPicker"] = strconv.FormatBool(*c.ServiceSettings.EnableGifPicker)
props["GfycatApiKey"] = *c.ServiceSettings.GfycatAPIKey
props["GfycatApiSecret"] = *c.ServiceSettings.GfycatAPISecret
props["GiphySdkKey"] = getGiphySdkKey(c.ServiceSettings)
props["MaxFileSize"] = strconv.FormatInt(*c.FileSettings.MaxFileSize, 10)

View File

@ -53,7 +53,6 @@ var configSensitivePaths = map[string]bool{
"MessageExportSettings.GlobalRelaySettings.SMTPUsername": true,
"MessageExportSettings.GlobalRelaySettings.SMTPPassword": true,
"MessageExportSettings.GlobalRelaySettings.EmailAddress": true,
"ServiceSettings.GfycatAPISecret": true,
"ServiceSettings.SplitKey": true,
"PluginSettings.Plugins": true,
}

View File

@ -464,27 +464,6 @@ func TestDiffSanitized(t *testing.T) {
},
"",
},
{
"sensitive ServiceSettings.GfycatAPISecret",
func() *model.Config {
cfg := defaultConfigGen()
cfg.ServiceSettings.GfycatAPISecret = model.NewString("base")
return cfg
}(),
func() *model.Config {
cfg := defaultConfigGen()
cfg.ServiceSettings.GfycatAPISecret = model.NewString("actual")
return cfg
}(),
ConfigDiffs{
{
Path: "ServiceSettings.GfycatAPISecret",
BaseVal: model.FakeSetting,
ActualVal: model.FakeSetting,
},
},
"",
},
{
"sensitive ServiceSettings.SplitKey",
func() *model.Config {

View File

@ -85,10 +85,6 @@ func desanitize(actual, target *model.Config) {
*target.MessageExportSettings.GlobalRelaySettings.SMTPPassword = *actual.MessageExportSettings.GlobalRelaySettings.SMTPPassword
}
if target.ServiceSettings.GfycatAPISecret != nil && *target.ServiceSettings.GfycatAPISecret == model.FakeSetting {
*target.ServiceSettings.GfycatAPISecret = *actual.ServiceSettings.GfycatAPISecret
}
if *target.ServiceSettings.SplitKey == model.FakeSetting {
*target.ServiceSettings.SplitKey = *actual.ServiceSettings.SplitKey
}

View File

@ -419,8 +419,6 @@ func (ts *TelemetryService) trackConfig() {
"enable_custom_emoji": *cfg.ServiceSettings.EnableCustomEmoji,
"enable_emoji_picker": *cfg.ServiceSettings.EnableEmojiPicker,
"enable_gif_picker": *cfg.ServiceSettings.EnableGifPicker,
"gfycat_api_key": isDefault(*cfg.ServiceSettings.GfycatAPIKey, model.ServiceSettingsDefaultGfycatAPIKey),
"gfycat_api_secret": isDefault(*cfg.ServiceSettings.GfycatAPISecret, model.ServiceSettingsDefaultGfycatAPISecret),
"experimental_enable_authentication_transfer": *cfg.ServiceSettings.ExperimentalEnableAuthenticationTransfer,
"enable_testing": cfg.ServiceSettings.EnableTesting,
"enable_developer": *cfg.ServiceSettings.EnableDeveloper,

View File

@ -109,8 +109,6 @@ const (
ServiceSettingsDefaultMaxLoginAttempts = 10
ServiceSettingsDefaultAllowCorsFrom = ""
ServiceSettingsDefaultListenAndAddress = ":8065"
ServiceSettingsDefaultGfycatAPIKey = "2_KtH_W5"
ServiceSettingsDefaultGfycatAPISecret = "3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof"
ServiceSettingsDefaultGiphySdkKeyTest = "s0glxvzVg9azvPipKxcPLpXV0q1x1fVP"
ServiceSettingsDefaultDeveloperFlags = ""
@ -347,8 +345,6 @@ type ServiceSettings struct {
WebsocketPort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none
WebserverMode *string `access:"environment_web_server,write_restrictable,cloud_restrictable"`
EnableGifPicker *bool `access:"integrations_gif"`
GfycatAPIKey *string `access:"integrations_gif"`
GfycatAPISecret *string `access:"integrations_gif"`
GiphySdkKey *string `access:"integrations_gif"`
EnableCustomEmoji *bool `access:"site_emoji"`
EnableEmojiPicker *bool `access:"site_emoji"`
@ -736,14 +732,6 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) {
s.EnableGifPicker = NewBool(true)
}
if s.GfycatAPIKey == nil || *s.GfycatAPIKey == "" {
s.GfycatAPIKey = NewString(ServiceSettingsDefaultGfycatAPIKey)
}
if s.GfycatAPISecret == nil || *s.GfycatAPISecret == "" {
s.GfycatAPISecret = NewString(ServiceSettingsDefaultGfycatAPISecret)
}
if s.GiphySdkKey == nil || *s.GiphySdkKey == "" {
s.GiphySdkKey = NewString("")
}
@ -4202,10 +4190,6 @@ func (o *Config) Sanitize() {
*o.MessageExportSettings.GlobalRelaySettings.SMTPPassword = FakeSetting
}
if o.ServiceSettings.GfycatAPISecret != nil && *o.ServiceSettings.GfycatAPISecret != "" {
*o.ServiceSettings.GfycatAPISecret = FakeSetting
}
if o.ServiceSettings.SplitKey != nil {
*o.ServiceSettings.SplitKey = FakeSetting
}

View File

@ -1885,42 +1885,6 @@ trademarks does not indicate endorsement of the trademark holder by Font
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
to represent the company, product, or service to which they refer.**
---
## gfycat-sdk
This product contains 'gfycat-sdk' by gfycat.
Javascript API wrapper for Gfycat.com API that supports callbacks and promises.
* HOMEPAGE:
* https://github.com/gfycat/gfycat-sdk
* LICENSE: MIT
MIT License
Copyright (c) 2016 Josh Kang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
## highlight.js
@ -1959,7 +1923,6 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
## history

View File

@ -40,7 +40,6 @@
"fast-deep-equal": "3.1.3",
"flexsearch": "0.6.32",
"font-awesome": "4.7.0",
"gfycat-sdk": "1.4.18",
"highlight.js": "11.6.0",
"history": "4.10.1",
"hoist-non-react-statics": "3.3.2",

View File

@ -1,65 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent, ReactNode} from 'react';
import {connect} from 'react-redux';
import {saveAppProps} from 'mattermost-redux/actions/gifs';
import Header from 'components/gif_picker/components/Header';
const mapDispatchToProps = ({
saveAppProps,
});
type Props = {
appProps: any;
action: string;
onCategories: () => void;
onSearch?: () => void;
onTrending: () => void;
children?: ReactNode;
saveAppProps?: (appProps: Props['appProps']) => void;
defaultSearchText?: string;
handleSearchTextChange: (text: string) => void;
}
export class App extends PureComponent<Props> {
constructor(props: Props) {
super(props);
const {appProps} = this.props;
this.props.saveAppProps?.(appProps);
}
render() {
const {
appProps,
action,
onCategories,
onSearch,
onTrending,
children,
defaultSearchText,
handleSearchTextChange,
} = this.props;
const appClassName = 'main-container ' + (appProps.appClassName || '');
return (
<div className={appClassName}>
<Header
appProps={appProps}
action={action}
onCategories={onCategories}
onSearch={onSearch}
onTrending={onTrending}
defaultSearchText={defaultSearchText}
handleSearchTextChange={handleSearchTextChange}
/>
<div className='component-container'>
{children}
</div>
</div>
);
}
}
export default connect(null, mapDispatchToProps)(App);

View File

@ -1,43 +0,0 @@
.categories-container {
position: relative;
height: 292px;
box-sizing: border-box;
padding: 0 0.2rem;
font-size: 0;
overflow-x: hidden;
.category-container {
display: inline-block;
width: 33.33%;
box-sizing: border-box;
padding: 0.2rem;
}
.category {
position: relative;
display: inline-block;
overflow: hidden;
width: 100%;
padding-bottom: 75%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 0.6rem;
cursor: pointer;
}
.category-name {
position: absolute;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.2);
color: white;
font-size: 1.2rem;
font-weight: bold;
text-align: center;
text-transform: uppercase;
}
}

View File

@ -1,151 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {GfycatAPIItem, GfycatAPITag} from '@mattermost/types/gifs';
import {requestCategoriesList, requestCategoriesListIfNeeded, saveSearchBarText, saveSearchScrollPosition, searchTextUpdate} from 'mattermost-redux/actions/gifs';
import {GlobalState} from 'types/store';
import {trackEvent} from 'actions/telemetry_actions.jsx';
import {getImageSrc} from 'utils/post_utils';
import InfiniteScroll from 'components/gif_picker/components/InfiniteScroll';
import './Categories.scss';
function mapStateToProps(state: GlobalState) {
return {
tagsList: state.entities.gifs.categories.tagsList,
hasMore: state.entities.gifs.categories.hasMore,
gifs: state.entities.gifs.cache.gifs,
searchText: state.entities.gifs.search.searchText,
searchBarText: state.entities.gifs.search.searchBarText,
hasImageProxy: state.entities.general.config.HasImageProxy,
};
}
const mapDispatchToProps = ({
saveSearchBarText,
saveSearchScrollPosition,
searchTextUpdate,
requestCategoriesList,
requestCategoriesListIfNeeded,
});
type Props = {
appProps: any;
gifs?: Record<string, GfycatAPIItem>;
hasMore?: boolean;
onSearch: () => void;
onTrending: () => void;
requestCategoriesList: () => void;
requestCategoriesListIfNeeded: () => void;
saveSearchBarText: (searchBarText: string) => void;
saveSearchScrollPosition: (scrollPosition: number) => void;
searchTextUpdate: (searchText: string) => void;
searchBarText: string;
tagsList: GfycatAPITag[];
hasImageProxy?: string;
}
export class Categories extends PureComponent<Props> {
componentDidMount() {
window.scrollTo(0, 0);
this.props.requestCategoriesListIfNeeded();
this.sendImpressions();
}
sendImpressions = () => {
const {tagsList} = this.props;
const gfycats = tagsList.map((tag) => {
return {gfyId: tag.gfyId};
});
if (gfycats.length) {
trackEvent('gfycat', 'views', {context: 'category_list', count: gfycats.length});
}
};
componentWillUnmount() {
this.props.saveSearchScrollPosition(0);
}
filterTagsList = () => {
const {searchBarText, tagsList} = this.props;
const substr = searchBarText.toLowerCase().trim().split(/ +/).join(' ');
return tagsList && tagsList.length ? tagsList.filter((tag) => {
if (!searchBarText || tag.tagName.indexOf(substr) !== -1) {
return tag;
}
return '';
}) : [];
};
loadMore = () => this.props.requestCategoriesList();
render() {
const {hasMore, tagsList, gifs, onSearch, onTrending, hasImageProxy} = this.props;
const content = tagsList && tagsList.length ? this.filterTagsList().map((item, index) => {
const {tagName, gfyId} = item;
if (!gifs?.[gfyId]) {
return null;
}
const gfyItem = gifs[gfyId];
const {max1mbGif, max2mbGif, avgColor} = gfyItem;
const url = getImageSrc(max1mbGif || max2mbGif, hasImageProxy === 'true');
const searchText = tagName.replace(/\s/g, '-');
const backgroundImage = {backgroundImage: `url(${url}`};
const backgroundColor = {backgroundColor: avgColor};
const props = this.props;
function callback() {
props.searchTextUpdate(tagName);
props.saveSearchBarText(tagName);
if (searchText === 'trending') {
onTrending();
} else {
onSearch();
}
}
return (
<a
onClick={callback}
key={index}
>
<div className='category-container'>
<div
className='category'
style={{...backgroundImage, ...backgroundColor}}
>
<div className='category-name'>{tagName}</div>
</div>
</div>
</a>
);
}) : [];
return content && content.length ? (
<div className='categories-container'>
<InfiniteScroll
hasMore={hasMore}
loadMore={this.loadMore}
threshold={1}
>
{content}
</InfiniteScroll>
</div>
) : (
<div className='categories-container'/>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Categories);

View File

@ -1,35 +0,0 @@
.header-container {
z-index: 1;
width: 100%;
.nav-bar {
position: relative;
display: flex;
height: 3.5rem;
align-items: center;
justify-content: space-around;
border-bottom-width: 1px;
border-bottom-style: solid;
.ic {
cursor: pointer;
vertical-align: middle;
}
a {
display: flex;
height: 100%;
flex-grow: 1;
align-items: center;
justify-content: space-around;
.header-text {
padding-left: 1rem;
font-family: SFUIDisplay, sans-serif;
font-size: 1.6rem;
font-weight: 500;
vertical-align: middle;
}
}
}
}

View File

@ -1,151 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {saveSearchBarText, searchTextUpdate} from 'mattermost-redux/actions/gifs';
import {getTheme, Theme} from 'mattermost-redux/selectors/entities/preferences';
import {changeOpacity, makeStyleFromTheme} from 'mattermost-redux/utils/theme_utils';
import constants from 'components/gif_picker/utils/constants';
import SearchBar from 'components/gif_picker/components/SearchBar';
import GifTrendingIcon from 'components/widgets/icons/gif_trending_icon';
import GifReactionsIcon from 'components/widgets/icons/gif_reactions_icon';
import './Header.scss';
import {GlobalState} from 'types/store';
function mapStateToProps(state: GlobalState) {
return {
theme: getTheme(state),
};
}
const mapDispatchToProps = ({
saveSearchBarText,
searchTextUpdate,
});
type Style = {
background: {backgroundColor: string};
header: {borderBottomColor: string};
icon: {fill: string};
iconActive: {fill: string};
iconHover: {fill: string};
}
const getStyle = makeStyleFromTheme((theme) => {
return {
background: {
backgroundColor: theme.centerChannelBg,
},
header: {
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.2),
},
icon: {
fill: changeOpacity(theme.centerChannelColor, 0.3),
},
iconActive: {
fill: theme.centerChannelColor,
},
iconHover: {
fill: changeOpacity(theme.centerChannelColor, 0.8),
},
};
});
type Props = {
action: string;
appProps: any;
saveSearchBarText: (searchBarText: string) => void;
searchTextUpdate: (searchText: string) => void;
theme: Theme;
defaultSearchText?: string;
onTrending?: () => void;
onCategories?: () => void;
onSearch?: () => void;
handleSearchTextChange: (text: string) => void;
}
type State = {
hovering: string;
}
export class Header extends PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
hovering: '',
};
}
render() {
const style = getStyle(this.props.theme);
return (
<header
className='header-container'
style={style.background}
>
<SearchBar {...this.props}/>
<nav
className='nav-bar'
style={style.header}
>
{this.renderTabs(this.props, style)}
</nav>
</header>
);
}
renderTabs(props: Props, style: Style) {
const {appProps, onTrending, onCategories} = props;
const {header} = appProps;
return header.tabs.map((tab: any, index: any) => {
let link;
if (tab === constants.Tab.TRENDING) {
link = this.renderTab({name: 'trending', callback: onTrending, Icon: GifTrendingIcon, index, style});
} else if (tab === constants.Tab.REACTIONS) {
link = this.renderTab({name: 'reactions', callback: onCategories, Icon: GifReactionsIcon, index, style});
}
return link;
});
}
renderTab(renderTabParams: {name: string; Icon: typeof GifTrendingIcon; index: number; style: Style; callback?: () => void}) {
const props = this.props;
const {action} = props;
const {Icon} = renderTabParams;
function callbackWrapper() {
props.searchTextUpdate('');
props.saveSearchBarText('');
renderTabParams.callback?.();
}
return (
<a
onClick={callbackWrapper}
onMouseOver={() => {
this.setState({hovering: renderTabParams.name});
}}
onMouseOut={() => {
this.setState({hovering: ''});
}}
style={{cursor: 'pointer'}}
key={renderTabParams.index}
>
<div style={{paddingTop: '2px'}}>
<Icon
style={(() => {
if (this.state.hovering === renderTabParams.name) {
return renderTabParams.style.iconHover;
}
return action === renderTabParams.name ? renderTabParams.style.iconActive : renderTabParams.style.icon;
})()}
/>
</div>
</a>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);

View File

@ -1,75 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {throttle} from 'lodash';
import {GfycatAPIItem} from '@mattermost/types/gifs';
import {searchIfNeededInitial, searchGfycat} from 'mattermost-redux/actions/gifs';
import SearchGrid from 'components/gif_picker/components/SearchGrid';
import {GlobalState} from 'types/store';
const GIF_SEARCH_THROTTLE_TIME_MS = 1000;
function mapStateToProps(state: GlobalState) {
return {
searchText: state.entities.gifs.search.searchText,
};
}
const mapDispatchToProps = ({
searchGfycat,
searchIfNeededInitial,
});
type Props = {
appProps: any;
onCategories?: () => void;
handleItemClick: (gif: GfycatAPIItem) => void;
searchText: string;
searchIfNeededInitial: (searchText: string) => void;
searchGfycat: (params: {searchText: string; count?: number; startIndex?: number }) => void;
}
export class Search extends PureComponent<Props> {
componentDidMount() {
const {searchText} = this.props;
this.props.searchIfNeededInitial(searchText.split('-').join(' '));
}
componentDidUpdate(prevProps: Props) {
const {searchText} = this.props;
if (prevProps.searchText !== searchText) {
this.throttledSearchGif(searchText);
}
}
throttledSearchGif = throttle(
(searchText) => this.props.searchIfNeededInitial(searchText.split('-').join(' ')),
GIF_SEARCH_THROTTLE_TIME_MS,
);
loadMore = () => {
const {searchText} = this.props;
this.props.searchGfycat({searchText});
};
render() {
const {handleItemClick, searchText, onCategories} = this.props;
return (
<SearchGrid
keyword={searchText}
handleItemClick={handleItemClick}
onCategories={onCategories}
loadMore={this.loadMore}
/>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Search);

View File

@ -1,74 +0,0 @@
.gfycat-search {
position: relative;
width: 100%;
box-sizing: border-box;
padding: 8px 7px 1px 7px;
.search-input {
position: relative;
z-index: 1;
display: block;
width: 100%;
height: 29px;
box-sizing: border-box;
padding: 0 27px;
border-width: 1px;
border-style: solid;
background-color: transparent;
border-radius: 30px;
box-shadow: none;
font-size: 1.3rem;
outline: none;
}
// Hide IE input clear button
.search-input::-ms-clear {
display: none;
}
.search-input-bg {
position: absolute;
width: calc(100% - 2.4rem);
height: 3.3rem;
border-radius: 0.6rem;
}
.placeholder {
position: absolute;
top: 14px;
left: 34px;
font-size: 13px;
}
.ic {
position: absolute;
top: calc(50% - 0.3rem);
}
.ic-clear-search,
.ic-search {
position: absolute;
z-index: 1;
background-position: center;
background-repeat: no-repeat;
cursor: pointer;
}
.ic-clear-search {
top: 12px;
right: 12px;
width: 2rem;
height: 2rem;
}
.ic-search {
top: 11px;
left: 11px;
width: 2.4rem;
height: 2.4rem;
}
.submit-button {
display: none;
}
}

View File

@ -1,244 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {ChangeEvent, Component, FormEvent, RefObject} from 'react';
import {connect} from 'react-redux';
import {GfycatAPITag} from '@mattermost/types/gifs';
import {saveSearchScrollPosition, saveSearchBarText, searchTextUpdate} from 'mattermost-redux/actions/gifs';
import {getTheme, Theme} from 'mattermost-redux/selectors/entities/preferences';
import {changeOpacity, makeStyleFromTheme} from 'mattermost-redux/utils/theme_utils';
import {GlobalState} from 'types/store';
import {t} from 'utils/i18n';
import GifSearchIcon from 'components/widgets/icons/gif_search_icon';
import GifSearchClearIcon from 'components/widgets/icons/gif_search_clear_icon';
import LocalizedInput from 'components/localized_input/localized_input';
import './SearchBar.scss';
function mapStateToProps(state: GlobalState) {
return {
...state.entities.gifs.categories,
...state.entities.gifs.search,
theme: getTheme(state),
appProps: state.entities.gifs.app,
};
}
const mapDispatchToProps = ({
saveSearchBarText,
saveSearchScrollPosition,
searchTextUpdate,
});
const getStyle = makeStyleFromTheme((theme) => {
return {
background: {
backgroundColor: theme.centerChannelBg,
},
icon: {
fill: changeOpacity(theme.centerChannelColor, 0.4),
},
inputBackground: {
backgroundColor: theme.centerChannelBg,
},
input: {
borderColor: changeOpacity(theme.centerChannelColor, 0.12),
},
};
});
type Props = {
action?: string;
theme: Theme;
onSearch?: () => void;
onTrending?: () => void;
onCategories?: () => void;
saveSearchBarText: (searchBarText: string) => void;
saveSearchScrollPosition?: (scrollPosition: number) => void;
searchTextUpdate: (searchText: string) => void;
searchBarText?: string;
defaultSearchText?: string;
tagsList?: GfycatAPITag[];
hasImageProxyd?: string;
handleSearchTextChange: (text: string) => void;
}
type State = {
inputFocused: boolean;
}
export class SearchBar extends Component<Props, State> {
private searchTimeout!: NodeJS.Timeout;
private searchInputRef: RefObject<HTMLInputElement>;
constructor(props: Props) {
super(props);
this.state = {inputFocused: false};
this.searchInputRef = React.createRef();
const defaultSearchText = this.props.defaultSearchText || '';
this.props.saveSearchBarText(defaultSearchText);
this.props.searchTextUpdate(defaultSearchText);
}
componentDidUpdate(prevProps: Props) {
const {searchBarText} = this.props;
if (searchBarText !== prevProps.searchBarText) {
if (!searchBarText || searchBarText === 'trending') {
this.updateSearchInputValue('');
} else {
this.updateSearchInputValue(searchBarText);
}
}
}
/**
* Returns text request with hyphens
*/
parseSearchText = (searchText: string) => searchText.trim().split(/ +/).join('-');
removeExtraSpaces = (searchText: string) => searchText.trim().split(/ +/).join(' ');
updateSearchInputValue = (searchText: string) => {
if (this.searchInputRef.current) {
this.searchInputRef.current.value = searchText;
}
this.props.saveSearchBarText(searchText);
this.props.handleSearchTextChange(searchText);
};
handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
this.triggerSearch(this.searchInputRef.current?.value || '');
this.searchInputRef.current?.blur();
};
triggerSearch = (searchText: string) => {
const {onSearch} = this.props;
this.props.searchTextUpdate(this.parseSearchText(searchText));
onSearch?.();
this.props.saveSearchScrollPosition?.(0);
};
handleChange = (event: ChangeEvent<HTMLInputElement>) => {
clearTimeout(this.searchTimeout);
const searchText = event.target.value;
const {onCategories, action} = this.props;
this.props.saveSearchBarText(searchText);
this.props.handleSearchTextChange(searchText);
if (searchText === '') {
onCategories?.();
} else if (action !== 'reactions' || !this.isFilteredTags(searchText)) {
// not reactions page or there's no reactions for this search request
this.searchTimeout = setTimeout(() => {
this.triggerSearch(searchText);
}, 500);
}
};
focusInput = () => this.setState({inputFocused: true});
blurInput = () => this.setState({inputFocused: false});
/**
* Checks if there're reactions for a current searchText
*/
isFilteredTags = (searchText: string) => {
const text = this.removeExtraSpaces(searchText);
const {tagsList} = this.props;
const substr = text.toLowerCase();
const filteredTags = tagsList && tagsList.length ? tagsList.filter((tag) => {
if (!text || tag.tagName.indexOf(substr) !== -1) {
return tag;
}
return '';
}) : [];
return Boolean(filteredTags.length);
};
clearSearchHandle = () => {
const {action, onTrending, onCategories} = this.props;
this.updateSearchInputValue('');
if (action === 'reactions') {
onCategories?.();
} else {
onTrending?.();
}
};
shouldComponentUpdate(nextProps: Props, nextState: State) {
return ((!nextProps.searchBarText && this.props.searchBarText) ||
(nextProps.searchBarText && !this.props.searchBarText) ||
(nextState.inputFocused !== this.state.inputFocused) ||
(nextProps.searchBarText !== this.props.searchBarText)) as boolean;
}
render() {
const style = getStyle(this.props.theme);
const {searchBarText} = this.props;
const clearSearchButton = searchBarText ? (
<GifSearchClearIcon
className='ic-clear-search'
style={style.icon}
onClick={this.clearSearchHandle}
/>
) : null;
return (
<form
className='gfycat-search'
method='get'
target='_top'
onSubmit={this.handleSubmit}
>
<div
className='search-bar'
style={style.background}
>
<div
className='search-input-bg'
style={style.inputBackground}
/>
<LocalizedInput
className='search-input'
name='searchText'
autoFocus={true}
placeholder={{id: t('gif_picker.gfycat'), defaultMessage: 'Search Gfycat'}}
onChange={this.handleChange}
autoComplete='off'
autoCapitalize='off'
onFocus={this.focusInput}
onBlur={this.blurInput}
ref={this.searchInputRef}
style={style.input}
value={searchBarText}
/>
<GifSearchIcon
className='ic ic-search'
style={style.icon}
/>
{clearSearchButton}
</div>
<button
type='submit'
className='submit-button'
/>
</form>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);

View File

@ -1,38 +0,0 @@
.search-grid-container {
position: relative;
width: 100%;
height: 336px;
margin: 0 auto;
overflow-x: hidden;
}
.empty-search {
margin: 2rem auto;
color: #a0a0a0;
font-size: 1.6rem;
text-align: center;
a {
text-decoration: none;
}
.empty-search-button {
display: inline-block;
padding: 0.6rem 1.6rem;
background-color: #1b70ff;
border-radius: 0.6rem;
color: #fff;
font-size: 1.2rem;
line-height: 1.5;
}
}
.empty-search-image {
width: 100%;
height: 9rem;
margin-bottom: 2rem;
background-image: url('../../static/search_end.png');
background-position: center;
background-repeat: no-repeat;
background-size: contain;
}

View File

@ -1,224 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {trackEvent} from 'actions/telemetry_actions.jsx';
import NoResultsIndicator from 'components/no_results_indicator/no_results_indicator';
import {NoResultsVariant} from 'components/no_results_indicator/types';
import InfiniteScroll from 'components/gif_picker/components/InfiniteScroll';
import SearchItem from 'components/gif_picker/components/SearchItem';
import {GfycatAPIItem, GifsAppState, GifsResult} from '@mattermost/types/gifs';
import './SearchGrid.scss';
const ITEMS_PADDING = 8;
const NUMBER_OF_COLUMNS_PORTRAIT = 2;
const NUMBER_OF_COLUMNS_LANDSCAPE = 2;
const WEBKIT_SCROLLBAR_WIDTH = 8;
type Props = {
appProps: GifsAppState;
gifs: Record<string, GfycatAPIItem>;
resultsByTerm: Record<string, GifsResult>;
containerClassName?: string;
keyword: string; // searchText, tagName
handleItemClick: (gfyItem: GfycatAPIItem) => void;
onCategories?: () => void;
loadMore: () => void;
numberOfColumns?: number;
scrollPosition: number;
saveSearchScrollPosition: (scrollPosition: number) => void;
}
type State = {
containerWidth: number | null;
}
export default class SearchGrid extends PureComponent<Props, State> {
private scrollPosition: number;
private columnsHeights: number[];
private numberOfColumns!: number;
private padding: number;
private container?: HTMLElement | null;
private containerHeight?: number;
constructor(props: Props) {
super(props);
this.state = {
containerWidth: null,
};
this.scrollPosition = this.props.scrollPosition;
this.setNumberOfColumns();
/**
* Inital values for columns heights
*/
this.columnsHeights = Array(this.numberOfColumns).fill(0);
/**
* Items padding value
*/
this.padding = ITEMS_PADDING;
}
componentDidMount() {
this.container = document.getElementById('search-grid-container');
if (this.container) {
this.setState({
...this.state,
containerWidth: this.container.offsetWidth - WEBKIT_SCROLLBAR_WIDTH,
});
}
window.addEventListener('resize', this.resizeHandler);
window.addEventListener('scroll', this.scrollHandler);
}
componentDidUpdate(prevProps: Props) {
if (prevProps.keyword !== this.props.keyword) {
window.scrollTo(0, 0);
}
}
componentWillUnmount() {
const {keyword} = this.props;
if (keyword !== 'trending') {
this.props.saveSearchScrollPosition(this.scrollPosition);
}
window.removeEventListener('resize', this.resizeHandler);
window.removeEventListener('scroll', this.scrollHandler);
}
setNumberOfColumns = () => {
if (window.matchMedia('(orientation: portrait)').matches) {
this.numberOfColumns = NUMBER_OF_COLUMNS_PORTRAIT;
} else {
this.numberOfColumns = NUMBER_OF_COLUMNS_LANDSCAPE;
}
};
itemClickHandler = (gfyItem: GfycatAPIItem) => {
const {keyword, handleItemClick} = this.props;
this.props.saveSearchScrollPosition(this.scrollPosition);
trackEvent('gfycat', 'shares', {gfyid: gfyItem.gfyId, keyword});
handleItemClick(gfyItem);
};
minHeightColumnIndex = () => {
return this.columnsHeights.indexOf(Math.min(...this.columnsHeights));
};
maxHeightColumnIndex = () => {
return this.columnsHeights.indexOf(Math.max(...this.columnsHeights));
};
maxColumnHeight = () => {
return Math.max(...this.columnsHeights);
};
resizeHandler = () => {
if (this.container && this.state.containerWidth !== this.container.offsetWidth - WEBKIT_SCROLLBAR_WIDTH) {
this.setNumberOfColumns();
this.setState({
...this.state,
containerWidth: this.container.offsetWidth - WEBKIT_SCROLLBAR_WIDTH,
});
this.columnsHeights = Array(this.numberOfColumns).fill(0);
}
};
scrollHandler = () => {
this.scrollPosition = window.scrollY;
};
render() {
const {
containerClassName,
gifs,
keyword,
resultsByTerm,
scrollPosition,
loadMore,
} = this.props;
const {containerWidth} = this.state;
const {moreRemaining, items = [], isFetching} = resultsByTerm[keyword] ? resultsByTerm[keyword] : {} as Partial<GifsResult>;
const isEmpty = items.length === 0;
/**
* Columns 'left' values
*/
const columnWidth = containerWidth ? Math.floor(containerWidth / this.numberOfColumns) : 0;
const leftPosition = Array(this.numberOfColumns).fill(0).map((item, index) => this.padding + ((index * columnWidth) - (index * (this.padding / 2))));
this.columnsHeights = Array(this.numberOfColumns).fill(this.padding);
// Item width in %
//const itemWidth = this.numberOfColumns === NUMBER_OF_COLUMNS_PORTRAIT ? 100 / NUMBER_OF_COLUMNS_PORTRAIT : 100 / this.numberOfColumns;
const itemWidth = 140;
const searchItems = containerWidth && items.length ?
items.map((item, index) => {
const gfyItem = gifs[item];
const {gfyId} = gfyItem;
// Position calculation
const colIndex = this.minHeightColumnIndex();
const top = this.columnsHeights[colIndex] + 'px';
const left = leftPosition[colIndex] + 'px';
const itemHeight = ((itemWidth / gfyItem.width) * gfyItem.height) + this.padding;
this.columnsHeights[colIndex] += itemHeight;
return (
<SearchItem
gfyItem={gfyItem}
top={top}
left={left}
itemWidth={itemWidth}
itemClickHandler={this.itemClickHandler}
key={`${index}-${gfyId}`}
/>
);
}) : null;
this.containerHeight = this.maxColumnHeight();
const content = searchItems ? (
<InfiniteScroll
className='search-grid-infinite-scroll'
pageStart={0}
loadMore={loadMore}
initialLoad={false}
hasMore={moreRemaining}
threshold={1}
containerHeight={this.containerHeight}
scrollPosition={scrollPosition}
useWindow={false}
>
{searchItems}
</InfiniteScroll>
) : null;
const emptySearch = !isFetching && isEmpty ? (
<NoResultsIndicator
variant={NoResultsVariant.ChannelSearch}
titleValues={{channelName: `"${keyword}"`}}
/>
) : null;
return (
<div
id='search-grid-container'
className={`search-grid-container ${containerClassName}`}
>
{content}
{emptySearch}
</div>
);
}
}

View File

@ -1,24 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {connect} from 'react-redux';
import {saveSearchScrollPosition} from 'mattermost-redux/actions/gifs';
import {GlobalState} from 'types/store';
import SearchGrid from './SearchGrid';
function mapStateToProps(state: GlobalState) {
return {
...state.entities.gifs.cache,
...state.entities.gifs.search,
appProps: state.entities.gifs.app,
};
}
const mapDispatchToProps = ({
saveSearchScrollPosition,
});
export default connect(mapStateToProps, mapDispatchToProps)(SearchGrid);

View File

@ -1,15 +0,0 @@
.search-item-wrapper {
position: absolute;
overflow: hidden;
width: 50%;
box-sizing: border-box;
border-radius: 0.6rem;
}
.search-item {
display: inline-block;
width: 100%;
background-size: cover;
border-radius: 0.6rem;
cursor: pointer;
}

View File

@ -1,63 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {GfycatAPIItem} from '@mattermost/types/gifs';
import {GlobalState} from 'types/store';
import {getImageSrc} from 'utils/post_utils';
import './SearchItem.scss';
function mapStateToProps(state: GlobalState) {
return {
hasImageProxy: state.entities.general.config.HasImageProxy,
};
}
type Props = {
gfyItem: GfycatAPIItem;
top: string;
left: string;
itemWidth: number;
itemClickHandler: (gif: GfycatAPIItem) => void;
hasImageProxy?: string;
}
export class SearchItem extends PureComponent<Props> {
render() {
const {
gfyItem,
top,
left,
itemWidth,
itemClickHandler,
} = this.props;
const {width, height, max1mbGif, max2mbGif, avgColor} = gfyItem;
const {hasImageProxy} = this.props;
const url = getImageSrc(max1mbGif || max2mbGif, hasImageProxy === 'true');
const backgroundImage = {backgroundImage: `url(${url})`};
const backgroundColor = {backgroundColor: avgColor};
const paddingBottom = {paddingBottom: ((itemWidth / width) * height) + 'px'};
return (
<div
className='search-item-wrapper'
style={{top, left, width: itemWidth ? `${itemWidth}px` : ''}}
>
<div
className='search-item'
style={{...backgroundImage, ...backgroundColor, ...paddingBottom}}
onClick={() => itemClickHandler(gfyItem)}
/>
</div>
);
}
}
export default connect(mapStateToProps)(SearchItem);

View File

@ -1,56 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {GfycatAPIItem} from '@mattermost/types/gifs';
import {
searchCategory,
searchIfNeededInitial,
saveSearchScrollPosition,
} from 'mattermost-redux/actions/gifs';
import SearchGrid from 'components/gif_picker/components/SearchGrid';
const mapDispatchToProps = ({
searchCategory,
searchIfNeededInitial,
saveSearchScrollPosition,
});
type Props = {
appProps: any;
searchIfNeededInitial: (searchText: string) => void;
onCategories: () => void;
saveSearchScrollPosition: (scrollPosition: number) => void;
handleItemClick: (gif: GfycatAPIItem) => void;
searchCategory: (params: {tagName?: string}) => void;
}
export class Trending extends PureComponent<Props> {
componentDidMount() {
this.props.searchIfNeededInitial('trending');
}
componentWillUnmount() {
this.props.saveSearchScrollPosition(0);
}
loadMore = () => this.props.searchCategory({tagName: 'trending'});
render() {
const {handleItemClick, onCategories} = this.props;
return (
<SearchGrid
keyword='trending'
handleItemClick={handleItemClick}
onCategories={onCategories}
loadMore={this.loadMore}
/>
);
}
}
export default connect(null, mapDispatchToProps)(Trending);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 20 34" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<g id="ic-chevron-left" transform="matrix(-0.666667,0,-0,0.666667,23.3333,-3.33333)">
<path d="M8.138,5.546L5.555,8.112C5.185,8.386 5,8.843 5,9.21C5,9.667 5.185,10.128 5.555,10.401L25.768,30.545L5.555,50.599C5.185,50.962 5,51.329 5,51.786C5,52.247 5.185,52.61 5.555,52.977L8.138,55.45C8.418,55.816 8.878,56 9.248,56C9.708,56 10.079,55.816 10.445,55.45L34.445,31.642C34.815,31.369 35,30.912 35,30.545C35,30.088 34.815,29.631 34.445,29.353L10.445,5.546C10.079,5.184 9.708,5 9.248,5C8.878,5 8.418,5.184 8.138,5.546Z" style="fill:#626f84;fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 980 B

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="338px" height="338px" viewBox="0 0 338 338" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 45.2 (43514) - http://www.bohemiancoding.com/sketch -->
<title>ic_canvas_border</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="ic_canvas_border" fill-rule="nonzero" fill="#CACACA">
<path d="M211.926,0 C214.968,0 214.968,3.38 211.926,3.38 L129.116,3.38 C126.412,3.38 126.412,0 129.116,0 L211.926,0 Z M334.62,35.152 C334.62,17.576 320.086,3.38 302.51,3.38 L259.922,3.38 C257.218,3.38 257.218,-1.77635684e-15 259.922,-1.77635684e-15 L302.51,-1.77635684e-15 C322.114,7.67561597e-17 338,15.886 338,35.152 L338,79.092 C338,82.134 334.62,82.134 334.62,79.092 L334.62,35.152 Z M338,210.236 C338,212.94 334.62,212.94 334.62,210.236 L334.62,127.426 C334.62,124.722 338,124.722 338,127.426 L338,210.236 Z M129.116,334.62 L211.926,334.62 C212.762543,334.701215 213.402239,335.433539 213.402239,336.31 C213.402239,337.186461 212.762543,337.918785 211.926,338 L129.116,338 C126.412,338 126.412,334.62 129.116,334.62 L129.116,334.62 Z M0,127.426 C0,124.722 3.38,124.722 3.38,127.426 L3.38,210.236 C3.38,212.602 0,212.94 0,210.236 L0,127.426 Z M35.49,-1.77635684e-15 L81.12,-1.77635684e-15 C83.824,-1.77635684e-15 83.824,3.38 81.12,3.38 L35.49,3.38 C17.914,3.38 3.38,17.576 3.38,35.152 L3.38,79.092 C3.38,82.134 0,82.134 0,79.092 L0,35.152 C-2.66453526e-15,15.886 15.886,-1.77635684e-15 35.49,-1.77635684e-15 Z M35.49,334.62 L81.12,334.62 C81.9565428,334.701215 82.5962386,335.433539 82.5962386,336.31 C82.5962386,337.186461 81.9565428,337.918785 81.12,338 L35.49,338 C15.886,338 0,322.114 0,302.848 L0,258.232 C0,255.528 3.38,255.528 3.38,258.232 L3.38,302.848 C3.38,320.424 17.914,334.62 35.49,334.62 Z M334.62,258.232 C334.62,255.528 338,255.528 338,258.232 L338,302.848 C338,322.114 322.114,338 302.51,338 L259.922,338 C257.218,338 257.218,334.62 259.922,334.62 L302.51,334.62 C320.086,334.62 334.62,320.424 334.62,302.848 L334.62,258.232 L334.62,258.232 Z" id="Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 20 20" enable-background="new 0 0 20 20" version="1.1" xml:space="preserve" stroke-linejoin="round">
<g transform="matrix(0.952381,0,0,1,0,0)">
<path fill="#626f84" d="M10.5 11.7L2.2 19.8C2 19.9 1.9 20 1.7 20 1.6 20 1.4 19.9 1.3 19.8L0.2 18.8C0.1 18.7 0 18.5 0 18.3 0 18.2 0.1 18 0.2 17.9L8.3 10 0.2 2.1C0.1 2 0 1.8 0 1.7 0 1.5 0.1 1.3 0.2 1.2L1.3 0.2C1.4 0.1 1.6 0 1.7 0 1.9 0 2 0.1 2.2 0.2L10.5 8.3 18.8 0.2C19 0.1 19.1 0 19.3 0 19.4 0 19.6 0.1 19.7 0.2L20.8 1.2C20.9 1.3 21 1.5 21 1.7 21 1.8 20.9 2 20.8 2.1L12.7 10 20.8 17.9C20.9 18 21 18.2 21 18.3 21 18.5 20.9 18.7 20.8 18.8L19.7 19.8C19.6 19.9 19.4 20 19.3 20 19.1 20 19 19.9 18.8 19.8L10.5 11.7Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 756 B

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
<g fill="none" fill-rule="evenodd">
<path d="M0 0h18v18H0z"/>
<path fill="#CCC" d="M18 9A9 9 0 1 1 0 9a9 9 0 0 1 18 0zM6.468 5.104a.964.964 0 1 0-1.364 1.363L7.636 9l-2.532 2.533a.964.964 0 1 0 1.364 1.363L9 10.364l2.532 2.532a.964.964 0 1 0 1.364-1.363L10.364 9l2.532-2.533a.964.964 0 1 0-1.364-1.363L9 7.636 6.468 5.104z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 446 B

View File

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 20 20" enable-background="new 0 0 20 20" version="1.1" xml:space="preserve" stroke-linejoin="round">
<g transform="matrix(0.952381,0,0,1,0,0)">
<path fill="#FFF" d="M10.5 11.7L2.2 19.8C2 19.9 1.9 20 1.7 20 1.6 20 1.4 19.9 1.3 19.8L0.2 18.8C0.1 18.7 0 18.5 0 18.3 0 18.2 0.1 18 0.2 17.9L8.3 10 0.2 2.1C0.1 2 0 1.8 0 1.7 0 1.5 0.1 1.3 0.2 1.2L1.3 0.2C1.4 0.1 1.6 0 1.7 0 1.9 0 2 0.1 2.2 0.2L10.5 8.3 18.8 0.2C19 0.1 19.1 0 19.3 0 19.4 0 19.6 0.1 19.7 0.2L20.8 1.2C20.9 1.3 21 1.5 21 1.7 21 1.8 20.9 2 20.8 2.1L12.7 10 20.8 17.9C20.9 18 21 18.2 21 18.3 21 18.5 20.9 18.7 20.8 18.8L19.7 19.8C19.6 19.9 19.4 20 19.3 20 19.1 20 19 19.9 18.8 19.8L10.5 11.7Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 753 B

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="23px" height="22px" viewBox="0 0 23 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 45.2 (43514) - http://www.bohemiancoding.com/sketch -->
<title>drawing-icon</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="drawing-icon" transform="translate(1.000000, 1.000000)" stroke="#2475FF" stroke-width="1.75">
<path d="M4.768,0 C-2.722,14.953 -2.066,10.4 11.621,0.6 C13.113,-0.468 3.201,17.226 4.616,18.71 C6.031,20.192 19.456,6.635 20.766,6.52 C22.077,6.404 17.541,16.93 15.254,20.403" id="Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 783 B

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="23px" height="22px" viewBox="0 0 23 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 45.2 (43514) - http://www.bohemiancoding.com/sketch -->
<title>drawing-icon</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="drawing-icon" transform="translate(1.000000, 1.000000)" stroke="#9E9E9E" stroke-width="1.75">
<path d="M4.768,0 C-2.722,14.953 -2.066,10.4 11.621,0.6 C13.113,-0.468 3.201,17.226 4.616,18.71 C6.031,20.192 19.456,6.635 20.766,6.52 C22.077,6.404 17.541,16.93 15.254,20.403" id="Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 783 B

View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="56" height="64" viewBox="0 0 56 64">
<path fill="#CACACA" fill-rule="nonzero" d="M54.415 62h-46.3l10.2-2.9c.3-.1.5-.3.6-.5l35.5-42.4c1-1.2 1.5-2.8 1.4-4.4-.1-1.6-.9-3-2.1-4l-7.7-6.5c-1.1-.8-2.4-1.3-3.8-1.3-1.8 0-3.4.8-4.6 2.1l-35.5 42.4c-.2.2-.4.4-.4.7L.015 63c-.1.1.3 1 1 1h53.4c.5 0 1-.4 1-1s-.4-1-1-1zm-18.2-55.1l13.8 11.6-8 9.5-2.6-10c-.1-.4-.5-.7-.9-.7l-10.3-.9 8-9.5zm-9.5 11.4l11 1 2.9 10.6-22.7 26.9-13.8-11.6 22.6-26.9zm-23.2 29l12.5 10.5-7.3 2.1-5.9-5 .7-7.6z"/>
</svg>

Before

Width:  |  Height:  |  Size: 531 B

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 45.2 (43514) - http://www.bohemiancoding.com/sketch -->
<title>reactions</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="reactions">
<circle id="Oval" stroke="#2475FF" stroke-width="1.45" cx="11" cy="11" r="10.275"></circle>
<path d="M6.919,7 C6.092,7 5.419,7.673 5.419,8.5 C5.419,9.327 6.091,10 6.919,10 C7.746,10 8.419,9.327 8.419,8.5 C8.419,7.673 7.745,7 6.919,7 Z" id="Shape" fill="#2475FF" fill-rule="nonzero"></path>
<path d="M5.5,13 C5.5,15.21 7.962,17 11,17 C14.038,17 16.5,15.21 16.5,13 L5.5,13 Z" id="Shape" fill="#2475FF" fill-rule="nonzero"></path>
<path d="M15.39,7 C14.564,7 13.89,7.63 13.89,8.405 C13.89,9.179 14.564,9.809 15.39,9.809 C16.218,9.809 16.89,9.179 16.89,8.405 C16.89,7.63 16.218,7 15.39,7 L15.39,7 Z" id="Shape" fill="#2475FF" fill-rule="nonzero"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 45.2 (43514) - http://www.bohemiancoding.com/sketch -->
<title>reactions</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="reactions">
<circle id="Oval" stroke="#9E9E9E" stroke-width="1.45" cx="11" cy="11" r="10.275"></circle>
<path d="M6.919,7 C6.092,7 5.419,7.673 5.419,8.5 C5.419,9.327 6.091,10 6.919,10 C7.746,10 8.419,9.327 8.419,8.5 C8.419,7.673 7.745,7 6.919,7 Z" id="Shape" fill="#9E9E9E" fill-rule="nonzero"></path>
<path d="M5.5,13 C5.5,15.21 7.962,17 11,17 C14.038,17 16.5,15.21 16.5,13 L5.5,13 Z" id="Shape" fill="#9E9E9E" fill-rule="nonzero"></path>
<path d="M15.39,7 C14.564,7 13.89,7.63 13.89,8.405 C13.89,9.179 14.564,9.809 15.39,9.809 C16.218,9.809 16.89,9.179 16.89,8.405 C16.89,7.63 16.218,7 15.39,7 L15.39,7 Z" id="Shape" fill="#9E9E9E" fill-rule="nonzero"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<g id="ic_search" transform="matrix(0.959095,-9.6091e-18,-1.00189e-17,0.959095,-0.0633002,-0.777826)">
<path d="M2.648,15.872C3.433,16.658 4.376,17.287 5.454,17.758C6.553,18.229 7.698,18.454 8.888,18.454C10.728,18.454 12.389,17.938 13.893,16.905L18.18,21.192C18.494,21.506 18.854,21.664 19.302,21.664C19.751,21.664 20.111,21.506 20.447,21.192C20.761,20.855 20.919,20.496 20.919,20.047C20.919,19.621 20.761,19.239 20.447,18.925L16.16,14.638C17.193,13.134 17.709,11.473 17.709,9.633C17.709,8.443 17.484,7.298 17.013,6.198C16.542,5.121 15.913,4.178 15.128,3.393C14.342,2.607 13.399,1.979 12.322,1.507C11.222,1.036 10.077,0.811 8.888,0.811C7.698,0.811 6.553,1.036 5.454,1.507C4.376,1.979 3.433,2.607 2.648,3.393C1.862,4.178 1.234,5.121 0.762,6.198C0.291,7.298 0.066,8.443 0.066,9.633C0.066,10.822 0.291,11.967 0.762,13.067C1.234,14.144 1.862,15.087 2.648,15.872ZM8.888,4.021C10.436,4.021 11.761,4.56 12.861,5.66C13.96,6.76 14.499,8.084 14.499,9.633C14.499,11.181 13.96,12.506 12.861,13.606C11.761,14.705 10.436,15.244 8.888,15.244C7.339,15.244 6.015,14.705 4.915,13.606C3.815,12.506 3.276,11.181 3.276,9.633C3.276,8.084 3.815,6.76 4.915,5.66C6.015,4.56 7.339,4.021 8.888,4.021Z" style="fill:#626f84;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fill-rule="evenodd">
<path d="M0 0h24v24H0z"/>
<path fill="#FFF" d="M3.845 2.133l17.215 8.385a1.638 1.638 0 0 1 0 2.964L3.845 21.867C2.998 22.28 2 21.68 2 20.757l.734-6.126a1.26 1.26 0 0 1 1.117-1.09l9.079-.923c.762-.078.762-1.158 0-1.236l-9.079-.924a1.259 1.259 0 0 1-1.117-1.09L2 3.244c0-.924.998-1.524 1.845-1.111"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 455 B

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill:#2475ff;fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<g transform="matrix(1,0,0,1,3,5)">
<path d="M0.203,1.042C-0.296,0.291 0.202,-0.003 0.853,0.016L13.092,0C13.86,0.018 13.886,0.676 13.439,1.171L5.356,9.36C4.957,9.864 3.956,10.518 3.692,9.426L3.164,6.374C3.126,6.139 3.241,5.793 3.494,5.61L6.47,3.368C6.762,3.1 6.511,3.057 6.143,3.179L3.256,3.966C2.996,4.086 2.611,3.969 2.446,3.708L0.203,1.042Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 801 B

View File

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="27" viewBox="0 0 25 27">
<g fill="#D8D8D8" fill-rule="nonzero">
<path d="M19.563 26.9c1.26 0 2.288-.993 2.32-2.252l.63-18.616h2.156V4.044h-6.665V2.951A2.376 2.376 0 0 0 15.617.566H9.383a2.376 2.376 0 0 0-2.387 2.385v1.093H.33v1.988h2.155l.63 18.616a2.313 2.313 0 0 0 2.321 2.253h14.126zM8.985 2.985c0-.232.166-.397.398-.397h6.234c.232 0 .398.165.398.397v1.094h-7.03V2.984zm-3.88 21.598l-.63-18.55h15.983l-.63 18.55a.356.356 0 0 1-.332.331H5.437c-.165 0-.298-.132-.331-.331z"/>
<path d="M11.505 10.438h1.99v9.904h-1.99zM7.526 10.438h1.99v9.904h-1.99zM15.484 10.438h1.99v9.904h-1.99z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 680 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

View File

@ -1,18 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export default {
ItemTapAction: {
OPEN_EMBED_PAGE: 1,
SHARE: 2,
},
Tab: {
TRENDING: 0,
REACTIONS: 1,
},
appName: {
mattermost: 'mattermost',
},
};

View File

@ -1,38 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
export default class GfycatIcon extends React.PureComponent<React.HTMLAttributes<HTMLSpanElement>> {
render() {
return (
<span {...this.props}>
<svg
width='22px'
height='14px'
viewBox='0 0 22 14'
>
<g
stroke='none'
strokeWidth='1'
fill='inherit'
fillRule='evenodd'
>
<g
transform='translate(-1344.000000, -552.000000)'
fill='inherit'
>
<g transform='translate(1147.000000, 542.000000)'>
<g transform='translate(1.000000, 1.000000)'>
<g transform='translate(138.000000, 0.000000)'>
<path d='M63.6748519,23 L62.2292481,23 C61.8176589,23 61.4619872,22.8510143 61.1631497,22.5539741 C60.8633954,22.2569338 60.71306,21.8993681 60.71306,21.4831393 C60.71306,21.0678417 60.8597287,20.710276 61.1539829,20.4132358 C61.4473204,20.1161955 61.800242,19.9672098 62.2118312,19.9672098 L63.6565183,19.9672098 C64.0681075,19.9672098 64.4182791,19.8219488 64.7061166,19.5304955 C64.993954,19.2390422 65.1378727,18.8917193 65.1378727,18.4866644 L65.1378727,15.4371134 C65.1378727,15.0208846 64.993954,14.6670436 64.7061166,14.3755903 C64.4182791,14.084137 64.0745243,13.938876 63.6748519,13.938876 C63.2632628,13.938876 62.9103411,14.0869305 62.6170036,14.3849019 C62.3227494,14.6819421 62.1760807,15.0329897 62.1760807,15.4371134 C62.1760807,15.7294978 62.3016658,16.0563352 62.5519193,16.4185567 L62.575753,16.4530096 C62.8269232,16.8143 62.9515917,17.1420685 62.9515917,17.4344529 C62.9515917,17.8506817 62.8049229,18.2073163 62.5115854,18.5043565 C62.2173313,18.8023279 61.8653263,18.9503824 61.4537371,18.9503824 C60.7836443,18.9503824 60.2198863,18.5164616 59.7615465,17.6486199 C59.373791,16.9232458 59.1794549,16.1857665 59.1794549,15.4371134 C59.1794549,14.188427 59.6176278,13.1213169 60.4930568,12.234852 C61.3684859,11.3493183 62.4226675,10.9060858 63.6565183,10.9060858 C64.8912858,10.9060858 65.9482175,11.3493183 66.8300633,12.234852 C67.7109925,13.1213169 68.1519154,14.188427 68.1519154,15.4371134 L68.1519154,18.4866644 C68.1519154,19.7353508 67.7137425,20.7996674 66.8383134,21.6796142 C65.9628844,22.559561 64.9087028,23 63.6748519,23 Z M80,15.9269039 C80,16.3068174 79.8689148,16.6317925 79.6076611,16.9027602 C79.3454907,17.173728 79.0319863,17.3096774 78.6653144,17.3096774 L76.8438719,17.3096774 L76.8438719,18.6589292 C76.8438719,19.0388427 76.7127867,19.3638178 76.4506164,19.6347855 C76.1893627,19.9057532 75.8749415,20.0417027 75.5082697,20.0417027 C75.1315143,20.0417027 74.8125098,19.9057532 74.5503394,19.6347855 C74.2890857,19.3638178 74.1580005,19.0388427 74.1580005,18.6589292 L74.1580005,13.1464583 C74.1580005,12.00858 74.5485061,11.0355171 75.3276838,10.2272697 C76.1077782,9.41995344 77.0473748,9.01582973 78.1473904,9.01582973 L78.6653144,9.01582973 C79.0319863,9.01582973 79.3454907,9.15177918 79.6076611,9.42274692 C79.8689148,9.69371467 80,10.0186897 80,10.3986033 C80,10.7775856 79.8689148,11.1034919 79.6076611,11.3744596 C79.3454907,11.6454273 79.0319863,11.7804456 78.6653144,11.7804456 L78.162974,11.7804456 C77.7963021,11.7804456 77.481881,11.9163951 77.2206273,12.1873628 C76.9584569,12.4583306 76.8282884,12.7777187 76.8282884,13.1464583 L76.8282884,14.5450615 L78.6653144,14.5450615 C79.0319863,14.5450615 79.3454907,14.681011 79.6076611,14.9519787 C79.8689148,15.2229465 80,15.5479215 80,15.9269039 Z M72.6344789,18.6589292 C72.6344789,19.0388427 72.5043104,19.3638178 72.24214,19.6347855 C71.9808863,19.9057532 71.6664652,20.0417027 71.2997933,20.0417027 C70.9340382,20.0417027 70.616867,19.9057532 70.3501132,19.6347855 C70.0833594,19.3638178 69.9495242,19.0388427 69.9495242,18.6589292 L69.9495242,14.170735 C69.9495242,13.7917526 70.0806094,13.4667775 70.3418631,13.1958098 C70.6040335,12.9239109 70.9175379,12.7888926 71.2842098,12.7888926 C71.6508817,12.7888926 71.9671361,12.9239109 72.2348066,13.1958098 C72.5015604,13.4667775 72.6344789,13.7917526 72.6344789,14.170735 L72.6344789,18.6589292 Z M58.3370263,12.5356169 C58.1023563,11.7441304 58.0042716,10.9163286 58.0042716,10.9163286 C57.9721878,10.6937812 58.1243566,10.547589 58.3425264,10.5904223 C58.3425264,10.5904223 58.5350291,10.6267376 58.8017829,10.6807449 C59.0767868,10.7375457 59.4324585,10.8139009 59.7404628,10.8921184 C60.3473048,11.0448287 60.95323,11.2720319 60.95323,11.2720319 C60.95323,11.2720319 60.2904706,11.6621882 59.7239626,12.3018956 C59.1565379,12.9406718 58.8650338,13.8420353 58.8650338,13.8420353 C58.8650338,13.8420353 58.5716963,13.3280346 58.3370263,12.5356169 Z M69.088762,12.5356169 C69.323432,11.7441304 69.4224334,10.9163286 69.4224334,10.9163286 C69.4536005,10.6937812 69.3014317,10.547589 69.0832619,10.5904223 C69.0832619,10.5904223 68.2921674,10.7384769 67.6853254,10.8921184 C67.0794002,11.0448287 66.4725583,11.2720319 66.4725583,11.2720319 C66.4725583,11.2720319 67.1353177,11.6621882 67.7027424,12.3018956 C68.2692504,12.9406718 68.5616712,13.8420353 68.5616712,13.8420353 C68.5616712,13.8420353 68.8550087,13.3280346 69.088762,12.5356169 Z M72.6344789,10.3818424 C72.6344789,10.7617559 72.5043104,11.086731 72.24214,11.3576987 C71.9808863,11.6286664 71.6664652,11.7646159 71.2997933,11.7646159 C70.9340382,11.7646159 70.616867,11.6286664 70.3501132,11.3576987 C70.0833594,11.086731 69.9495242,10.7617559 69.9495242,10.3818424 C69.9495242,10.00286 70.0806094,9.67788494 70.3418631,9.40691719 C70.6040335,9.13594945 70.9175379,9 71.2842098,9 C71.6508817,9 71.9671361,9.13594945 72.2348066,9.40691719 C72.5015604,9.67788494 72.6344789,10.00286 72.6344789,10.3818424 Z'/>
</g>
</g>
</g>
</g>
</g>
</svg>
</span>
);
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
export default class GifReactionsIcon extends React.PureComponent<React.HTMLAttributes<HTMLSpanElement>> {
render() {
return (
<span {...this.props}>
<svg
className='ic-svg ic-reactions-svg'
width='14px'
height='14px'
viewBox='0 0 14 14'
version='1.1'
>
<g
id='Finalized-Design'
stroke='none'
fill='inherit'
>
<g
id='GfyCat---Gycat-Tab'
transform='translate(-1348.000000, -620.000000)'
fill='inherit'
>
<g
id='modal---emojis'
transform='translate(1147.000000, 542.000000)'
>
<g
id='tabs---gfycat'
transform='translate(1.000000, 68.000000)'
>
<g
id='tab---category---deselected'
transform='translate(138.000000, 0.000000)'
>
<path
d='M62,16 L62,10 L68,10 L68,16 L62,16 Z M64,12 L64,14 L66,14 L66,12 L64,12 Z M70,24 L70,18 L76,18 L76,24 L70,24 Z M72,20 L72,22 L74,22 L74,20 L72,20 Z M70,10 L76,10 L76,16 L70,16 L70,10 Z M74,14 L74,12 L72,12 L72,14 L74,14 Z M62,24 L62,18 L68,18 L68,24 L62,24 Z M64,20 L64,22 L66,22 L66,20 L64,20 Z'
id='icon---categories'
/>
</g>
</g>
</g>
</g>
</g>
</svg>
</span>
);
}
}

View File

@ -1,27 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
export default class GifSearchClearIcon extends React.PureComponent<React.HTMLAttributes<HTMLSpanElement>> {
render() {
return (
<span {...this.props}>
<svg
width='100%'
height='100%'
viewBox='-10 -10 40 40'
enableBackground='new 0 0 20 20'
version='1.1'
>
<g transform='matrix(0.952381,0,0,1,0,0)'>
<path
fill='inherit'
d='M10.5 11.7L2.2 19.8C2 19.9 1.9 20 1.7 20 1.6 20 1.4 19.9 1.3 19.8L0.2 18.8C0.1 18.7 0 18.5 0 18.3 0 18.2 0.1 18 0.2 17.9L8.3 10 0.2 2.1C0.1 2 0 1.8 0 1.7 0 1.5 0.1 1.3 0.2 1.2L1.3 0.2C1.4 0.1 1.6 0 1.7 0 1.9 0 2 0.1 2.2 0.2L10.5 8.3 18.8 0.2C19 0.1 19.1 0 19.3 0 19.4 0 19.6 0.1 19.7 0.2L20.8 1.2C20.9 1.3 21 1.5 21 1.7 21 1.8 20.9 2 20.8 2.1L12.7 10 20.8 17.9C20.9 18 21 18.2 21 18.3 21 18.5 20.9 18.7 20.8 18.8L19.7 19.8C19.6 19.9 19.4 20 19.3 20 19.1 20 19 19.9 18.8 19.8L10.5 11.7Z'
/>
</g>
</svg>
</span>
);
}
}

View File

@ -1,29 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
export default class GifSearchIcon extends React.PureComponent<React.HTMLAttributes<HTMLSpanElement>> {
render() {
return (
<span {...this.props}>
<svg
width='100%'
height='100%'
viewBox='-10 -10 40 40'
version='1.1'
>
<g
id='ic_search'
transform='matrix(0.959095,-9.6091e-18,-1.00189e-17,0.959095,-0.0633002,-0.777826)'
>
<path
d='M2.648,15.872C3.433,16.658 4.376,17.287 5.454,17.758C6.553,18.229 7.698,18.454 8.888,18.454C10.728,18.454 12.389,17.938 13.893,16.905L18.18,21.192C18.494,21.506 18.854,21.664 19.302,21.664C19.751,21.664 20.111,21.506 20.447,21.192C20.761,20.855 20.919,20.496 20.919,20.047C20.919,19.621 20.761,19.239 20.447,18.925L16.16,14.638C17.193,13.134 17.709,11.473 17.709,9.633C17.709,8.443 17.484,7.298 17.013,6.198C16.542,5.121 15.913,4.178 15.128,3.393C14.342,2.607 13.399,1.979 12.322,1.507C11.222,1.036 10.077,0.811 8.888,0.811C7.698,0.811 6.553,1.036 5.454,1.507C4.376,1.979 3.433,2.607 2.648,3.393C1.862,4.178 1.234,5.121 0.762,6.198C0.291,7.298 0.066,8.443 0.066,9.633C0.066,10.822 0.291,11.967 0.762,13.067C1.234,14.144 1.862,15.087 2.648,15.872ZM8.888,4.021C10.436,4.021 11.761,4.56 12.861,5.66C13.96,6.76 14.499,8.084 14.499,9.633C14.499,11.181 13.96,12.506 12.861,13.606C11.761,14.705 10.436,15.244 8.888,15.244C7.339,15.244 6.015,14.705 4.915,13.606C3.815,12.506 3.276,11.181 3.276,9.633C3.276,8.084 3.815,6.76 4.915,5.66C6.015,4.56 7.339,4.021 8.888,4.021Z'
style={{fill: 'inherit'}}
/>
</g>
</svg>
</span>
);
}
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
export default class GifTrendingIcon extends React.PureComponent<React.HTMLAttributes<HTMLSpanElement>> {
render() {
return (
<span {...this.props}>
<svg
className='ic-svg ic-trending-svg'
width='11px'
height='15px'
viewBox='0 0 11 15'
version='1.1'
>
<g
id='Finalized-Design'
stroke='none'
fill='inherit'
>
<g
id='GfyCat---Gycat-Tab'
transform='translate(-1212.000000, -619.000000)'
fill='inherit'
>
<g
id='modal---emojis'
transform='translate(1147.000000, 542.000000)'
>
<g
id='tabs---gfycat'
transform='translate(1.000000, 68.000000)'
>
<g id='tab---trending---selected'>
<path
d='M69.90625,10.4062776 C69.90625,10.9531513 70.0976562,11.4909106 70.4804688,12.019555 C70.6992188,12.32945 71.1276043,12.7760638 71.765625,13.3593956 C72.3489582,13.9062693 72.7773438,14.3346538 73.0507812,14.6445488 C73.5065106,15.1731932 73.8528644,15.7109525 74.0898438,16.2578262 C74.3632812,16.9505327 74.5,17.6979271 74.5,18.5000083 C74.5,19.4479229 74.2630207,20.3229208 73.7890625,21.1250021 C73.3151043,21.9270834 72.6770832,22.565103 71.875,23.03906 C71.0729168,23.5130171 70.1979168,23.7499958 69.25,23.7499958 C68.3020832,23.7499958 67.4270832,23.5130171 66.625,23.03906 C65.8229168,22.565103 65.1848957,21.9270834 64.7109375,21.1250021 C64.2369793,20.3229208 64,19.4479229 64,18.5000083 C64,17.6432397 64.2005207,16.8320436 64.6015625,16.0664204 C65.0026043,15.3007972 65.5494793,14.6718925 66.2421875,14.1797061 C66.4609375,14.0338733 66.6888019,14.0247585 66.9257812,14.1523625 C67.1627606,14.2799665 67.28125,14.4713723 67.28125,14.7265798 L67.28125,17.6250104 C67.28125,17.9349054 67.3860676,18.1946704 67.5957031,18.4043054 C67.8053387,18.6139405 68.0651043,18.7187578 68.375,18.7187578 C68.6848957,18.7187578 68.9446613,18.6139405 69.1542969,18.4043054 C69.3639324,18.1946704 69.46875,17.9349054 69.46875,17.6250104 C69.46875,17.4427191 69.4049481,17.2330844 69.2773438,16.9961057 C69.2044269,16.8320436 69.0677082,16.576836 68.8671875,16.2304825 C68.4661457,15.5742341 68.1835938,15.0547041 68.0195312,14.6718925 C67.7643231,13.9791859 67.6640625,13.2955938 67.71875,12.6211161 C67.8098957,11.7825763 68.1380207,10.9258077 68.703125,10.0508097 C68.8125,9.86851837 68.9628906,9.76825847 69.1542969,9.75002921 C69.3457031,9.73179994 69.5188801,9.78648731 69.6738281,9.91409132 C69.8287762,10.0416953 69.90625,10.2057574 69.90625,10.4062776 Z M69.2499875,22.437499 C69.9609233,22.437499 70.6171717,22.259765 71.2187328,21.9042971 C71.8202939,21.5488292 72.2988083,21.0703147 72.6542762,20.4687537 C73.0097441,19.8671926 73.1874781,19.2109441 73.1874781,18.5000083 C73.1874781,17.880218 73.0781034,17.3060006 72.8593539,16.7773562 C72.6588337,16.3398572 72.376282,15.9023583 72.0116996,15.4648593 C71.7929502,15.1914225 71.4329248,14.8131683 70.9316241,14.3300964 C70.4303233,13.8470245 70.070298,13.4687703 69.8515485,13.1953335 C69.4869662,12.7760638 69.2135294,12.3567937 69.031238,11.937524 C68.8671759,12.5573143 68.8945196,13.1953335 69.1132691,13.8515819 C69.2408731,14.2343935 69.5143099,14.7812672 69.9335796,15.492203 C70.2252457,15.9661601 70.4166515,16.321628 70.507797,16.5586067 C70.6900884,16.9414183 70.7812338,17.2968862 70.7812338,17.6250104 C70.7812338,18.2812589 70.5442551,18.8463618 70.070298,19.3203189 C69.596341,19.794276 69.031238,20.0312547 68.3749896,20.0312547 C67.7187411,20.0312547 67.1536382,19.794276 66.6796811,19.3203189 C66.205724,18.8463618 65.9687453,18.2812589 65.9687453,17.6250104 L65.9687453,16.0937641 C65.7682251,16.403659 65.60872,16.7819136 65.4902308,17.228527 C65.3717417,17.6751404 65.3124969,18.0989675 65.3124969,18.5000083 C65.3124969,19.2109441 65.4902308,19.8671926 65.8456987,20.4687537 C66.2011666,21.0703147 66.6796811,21.5488292 67.2812422,21.9042971 C67.8828032,22.259765 68.5390517,22.437499 69.2499875,22.437499 Z'
id='icon---trending'
/>
</g>
</g>
</g>
</g>
</g>
</svg>
</span>
);
}
}

View File

@ -3629,7 +3629,6 @@
"get_public_link_modal.help": "The link below allows anyone to see this file without being registered on this server.",
"get_public_link_modal.title": "Copy Public Link",
"gif_picker.attribution.alt": "Powered by GIPHY",
"gif_picker.gfycat": "Search Gfycat",
"gif_picker.input.label": "Search for GIFs",
"gif_picker.input.placeholder": "Search GIPHY",
"global_header.productSettings": "Settings",

View File

@ -1,49 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import keyMirror from 'mattermost-redux/utils/key_mirror';
export default keyMirror({
// General.
SAVE_APP_PROPS: null,
// Search.
SEARCH_REQUEST: null,
SEARCH_FAILURE: null,
SEARCH_SUCCESS: null,
SEARCH_BY_ID_REQUEST: null,
SEARCH_BY_ID_FAILURE: null,
SEARCH_BY_ID_SUCCESS: null,
SELECT_SEARCH_TEXT: null,
INVALIDATE_SEARCH_TEXT: null,
REQUEST_SEARCH: null,
RECEIVE_SEARCH: null,
RECEIVE_SEARCH_END: null,
RECEIVE_CATEGORY_SEARCH: null,
CLEAR_SEARCH_RESULTS: null,
SAVE_SEARCH_SCROLL_POSITION: null,
SAVE_SEARCH_PRIOR_LOCATION: null,
UPDATE_SEARCH_TEXT: null,
SAVE_SEARCH_BAR_TEXT: null,
// Categories.
REQUEST_CATEGORIES_LIST: null,
CATEGORIES_LIST_RECEIVED: null,
CATEGORIES_LIST_FAILURE: null,
// Cache.
CACHE_GIFS: null,
CACHE_REQUEST: null,
});

View File

@ -12,7 +12,6 @@ import FileTypes from './files';
import PreferenceTypes from './preferences';
import IntegrationTypes from './integrations';
import EmojiTypes from './emojis';
import GifTypes from './gifs';
import AdminTypes from './admin';
import JobTypes from './jobs';
import SearchTypes from './search';
@ -39,7 +38,6 @@ export {
PreferenceTypes,
IntegrationTypes,
EmojiTypes,
GifTypes,
AdminTypes,
JobTypes,
SearchTypes,

View File

@ -1,423 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {GifTypes} from 'mattermost-redux/action_types';
import {Client4} from 'mattermost-redux/client';
import gfycatSdk from 'mattermost-redux/utils/gfycat_sdk';
import {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import {GlobalState} from '@mattermost/types/store';
// APP PROPS
export function saveAppPropsRequest(props: any) {
return {
type: GifTypes.SAVE_APP_PROPS,
props,
};
}
export function saveAppProps(appProps: any) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatAPIKey, GfycatAPISecret} = getState().entities.general.config;
gfycatSdk(GfycatAPIKey!, GfycatAPISecret!).authenticate();
dispatch(saveAppPropsRequest(appProps));
};
}
// SEARCH
export function selectSearchText(searchText: string) {
return {
type: GifTypes.SELECT_SEARCH_TEXT,
searchText,
};
}
export function updateSearchText(searchText: string) {
return {
type: GifTypes.UPDATE_SEARCH_TEXT,
searchText,
};
}
export function searchBarTextSave(searchBarText: string) {
return {
type: GifTypes.SAVE_SEARCH_BAR_TEXT,
searchBarText,
};
}
export function invalidateSearchText(searchText: string) {
return {
type: GifTypes.INVALIDATE_SEARCH_TEXT,
searchText,
};
}
export function requestSearch(searchText: string) {
return {
type: GifTypes.REQUEST_SEARCH,
searchText,
};
}
export function receiveSearch({searchText, count, start, json}: {searchText: string; count: number; start: number; json: any}) {
return {
type: GifTypes.RECEIVE_SEARCH,
searchText,
...json,
count,
start,
currentPage: start / count,
receivedAt: Date.now(),
};
}
export function receiveSearchEnd(searchText: string) {
return {
type: GifTypes.RECEIVE_SEARCH_END,
searchText,
};
}
export function errorSearching(err: any, searchText: string) {
return {
type: GifTypes.SEARCH_FAILURE,
searchText,
err,
};
}
export function receiveCategorySearch({tagName, json}: {tagName: string; json: any}) {
return {
type: GifTypes.RECEIVE_CATEGORY_SEARCH,
searchText: tagName,
...json,
receiveAt: Date.now(),
};
}
export function clearSearchResults() {
return {
type: GifTypes.CLEAR_SEARCH_RESULTS,
};
}
export function requestSearchById(gfyId: string) {
return {
type: GifTypes.SEARCH_BY_ID_REQUEST,
payload: {
gfyId,
},
};
}
export function receiveSearchById(gfyId: string, gfyItem: any) {
return {
type: GifTypes.SEARCH_BY_ID_SUCCESS,
payload: {
gfyId,
gfyItem,
},
};
}
export function errorSearchById(err: any, gfyId: string) {
return {
type: GifTypes.SEARCH_BY_ID_FAILURE,
err,
gfyId,
};
}
export function searchScrollPosition(scrollPosition: number) {
return {
type: GifTypes.SAVE_SEARCH_SCROLL_POSITION,
scrollPosition,
};
}
export function searchPriorLocation(priorLocation: number) {
return {
type: GifTypes.SAVE_SEARCH_PRIOR_LOCATION,
priorLocation,
};
}
export function searchGfycat({searchText, count = 30, startIndex = 0}: { searchText: string; count?: number; startIndex?: number}) {
let start = startIndex;
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatAPIKey, GfycatAPISecret} = getState().entities.general.config;
const {resultsByTerm} = getState().entities.gifs.search;
if (resultsByTerm[searchText]) {
start = resultsByTerm[searchText].start + count;
}
dispatch(requestSearch(searchText));
const sdk = gfycatSdk(GfycatAPIKey!, GfycatAPISecret!);
sdk.authenticate();
return sdk.search({search_text: searchText, count, start}).then((json: any) => {
if (json.errorMessage) {
// There was no results before
if (resultsByTerm[searchText].items) {
dispatch(receiveSearchEnd(searchText));
} else {
dispatch(errorSearching(json, searchText));
}
} else {
dispatch(updateSearchText(searchText));
dispatch(cacheGifsRequest(json.gfycats));
dispatch(receiveSearch({searchText, count, start, json}));
const context = getState().entities.gifs.categories.tagsDict[searchText] ?
'category' :
'search';
Client4.trackEvent(
'gfycat',
'views',
{context, count: json.gfycats.length, keyword: searchText},
);
}
}).catch(
(err: any) => dispatch(errorSearching(err, searchText)),
);
};
}
export function searchCategory({tagName = '', gfyCount = 30, cursorPos = undefined}) {
let cursor: string | undefined = cursorPos;
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatAPIKey, GfycatAPISecret} = getState().entities.general.config;
const {resultsByTerm} = getState().entities.gifs.search;
if (resultsByTerm[tagName]) {
cursor = resultsByTerm[tagName].cursor;
}
dispatch(requestSearch(tagName));
return gfycatSdk(GfycatAPIKey!, GfycatAPISecret!).getTrendingCategories({tagName, gfyCount, cursor}).then(
(json: any) => {
if (json.errorMessage) {
if (resultsByTerm[tagName].gfycats) {
dispatch(receiveSearchEnd(tagName));
} else {
dispatch(errorSearching(json, tagName));
}
} else {
dispatch(updateSearchText(tagName));
dispatch(cacheGifsRequest(json.gfycats));
dispatch(receiveCategorySearch({tagName, json}));
Client4.trackEvent(
'gfycat',
'views',
{context: 'category', count: json.gfycats.length, keyword: tagName},
);
// preload categories list
if (tagName === 'trending') {
dispatch(requestCategoriesListIfNeeded() as any);
}
}
},
).catch((err: any) => dispatch(errorSearching(err, tagName)));
};
}
export function shouldSearch(state: GlobalState, searchText: string) {
const resultsByTerm = state.entities.gifs.search.resultsByTerm[searchText];
if (!resultsByTerm) {
return true;
} else if (resultsByTerm.isFetching) {
return false;
} else if (resultsByTerm.moreRemaining) {
return true;
}
return resultsByTerm.didInvalidate;
}
export function searchIfNeeded(searchText: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
if (shouldSearch(getState(), searchText)) {
if (searchText.toLowerCase() === 'trending') {
return dispatch(searchCategory({tagName: searchText}));
}
return dispatch(searchGfycat({searchText}));
}
return Promise.resolve();
};
}
export function searchIfNeededInitial(searchText: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
dispatch(updateSearchText(searchText));
if (shouldSearchInitial(getState(), searchText)) {
if (searchText.toLowerCase() === 'trending') {
return dispatch(searchCategory({tagName: searchText}));
}
return dispatch(searchGfycat({searchText}));
}
return Promise.resolve();
};
}
export function shouldSearchInitial(state: GlobalState, searchText: string) {
const resultsByTerm = state.entities.gifs.search.resultsByTerm[searchText];
if (!resultsByTerm) {
return true;
} else if (resultsByTerm.isFetching) {
return false;
}
return false;
}
export function searchById(gfyId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatAPIKey, GfycatAPISecret} = getState().entities.general.config;
dispatch(requestSearchById(gfyId));
return gfycatSdk(GfycatAPIKey!, GfycatAPISecret!).searchById({id: gfyId}).then(
(response: any) => {
dispatch(receiveSearchById(gfyId, response.gfyItem));
dispatch(cacheGifsRequest([response.gfyItem]));
},
).catch((err: any) => dispatch(errorSearchById(err, gfyId)));
};
}
export function shouldSearchById(state: GlobalState, gfyId: string) {
return !state.entities.gifs.cache.gifs[gfyId]; //TODO investigate, used to be !state.cache.gifs[gfyId];
}
export function searchByIdIfNeeded(gfyId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
if (shouldSearchById(getState(), gfyId)) {
return dispatch(searchById(gfyId));
}
return Promise.resolve(getState().entities.gifs.cache.gifs[gfyId]); //TODO: investigate, used to be getState().cache.gifs[gfyId]
};
}
export function saveSearchScrollPosition(scrollPosition: number) {
return (dispatch: DispatchFunc) => {
dispatch(searchScrollPosition(scrollPosition));
};
}
export function saveSearchPriorLocation(priorLocation: number) {
return (dispatch: DispatchFunc) => {
dispatch(searchPriorLocation(priorLocation));
};
}
export function searchTextUpdate(searchText: string) {
return (dispatch: DispatchFunc) => {
dispatch(updateSearchText(searchText));
};
}
export function saveSearchBarText(searchBarText: string) {
return (dispatch: DispatchFunc) => {
dispatch(searchBarTextSave(searchBarText));
};
}
// CATEGORIES
export function categoriesListRequest() {
return {
type: GifTypes.REQUEST_CATEGORIES_LIST,
};
}
export function categoriesListReceived(json: any) {
return {
type: GifTypes.CATEGORIES_LIST_RECEIVED,
...json,
};
}
export function categoriesListFailure(err: any) {
return {
type: GifTypes.CATEGORIES_LIST_FAILURE,
err,
};
}
export function requestCategoriesList({count = 60} = {}) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const {GfycatAPIKey, GfycatAPISecret} = getState().entities.general.config;
const state = getState().entities.gifs.categories;
if (!shouldRequestCategoriesList(state)) {
return Promise.resolve();
}
dispatch(categoriesListRequest());
const {cursor} = state;
const options = {
...(count && {count}),
...(cursor && {cursor}),
};
return gfycatSdk(GfycatAPIKey!, GfycatAPISecret!).getCategories(options).then((json: any) => {
const newGfycats = json.tags.reduce((gfycats: any[], tag: any) => {
if (tag.gfycats[0] && tag.gfycats[0].width) {
return [...gfycats, ...tag.gfycats];
}
return gfycats;
}, []);
dispatch(cacheGifsRequest(newGfycats));
dispatch(categoriesListReceived(json));
}).catch(
(err: any) => {
dispatch(categoriesListFailure(err));
},
);
};
}
export function requestCategoriesListIfNeeded({
count,
} = {count: undefined}) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState().entities.gifs.categories;
if (state.tagsList && state.tagsList.length) {
return Promise.resolve();
}
return dispatch(requestCategoriesList({count}));
};
}
export function shouldRequestCategoriesList(state: {hasMore: boolean; isFetching: boolean; tagsList: any[]}) {
const {hasMore, isFetching, tagsList} = state;
if (!tagsList || !tagsList.length) {
return true;
} else if (isFetching) {
return false;
} else if (hasMore) {
return true;
}
return false;
}
// CACHE
export function cacheRequest() {
return {
type: GifTypes.CACHE_REQUEST,
payload: {
updating: true,
},
};
}
export function cacheGifs(gifs: any) {
return {
type: GifTypes.CACHE_GIFS,
gifs,
};
}
export function cacheGifsRequest(gifs: any) {
return async (dispatch: DispatchFunc) => {
dispatch(cacheRequest());
dispatch(cacheGifs(gifs));
return {data: true};
};
}

View File

@ -10,7 +10,6 @@ import * as emojis from './emojis';
import * as files from './files';
import * as general from './general';
import * as groups from './groups';
import * as gifs from './gifs';
import * as helpers from './helpers';
import * as integrations from './integrations';
import * as jobs from './jobs';
@ -34,7 +33,6 @@ export {
files,
general,
groups,
gifs,
integrations,
helpers,
jobs,

View File

@ -1,251 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {combineReducers} from 'redux';
import {GifTypes} from 'mattermost-redux/action_types';
import {GenericAction} from 'mattermost-redux/types/actions';
type ReducerMap = {[actionType: string]: (state: any, action: GenericAction) => any};
const SEARCH_SELECTORS: ReducerMap = {
[GifTypes.SELECT_SEARCH_TEXT]: (state: any, action: GenericAction) => ({
...state,
searchText: action.searchText,
}),
[GifTypes.INVALIDATE_SEARCH_TEXT]: (state: any, action: GenericAction) => ({
...state,
resultsByTerm: {
...state.resultsByTerm[action.searchText],
didInvalidate: true,
},
}),
[GifTypes.REQUEST_SEARCH]: (state: any, action: GenericAction) => ({
...state,
resultsByTerm: TERM_SELECTOR[action.type](state.resultsByTerm, action),
}),
[GifTypes.RECEIVE_SEARCH]: (state: any, action: GenericAction) => ({
...state,
searchText: action.searchText,
resultsByTerm: TERM_SELECTOR[action.type](state.resultsByTerm, action),
}),
[GifTypes.RECEIVE_SEARCH_END]: (state: any, action: GenericAction) => ({
...state,
searchText: action.searchText,
resultsByTerm: TERM_SELECTOR[action.type](state.resultsByTerm, action),
}),
[GifTypes.RECEIVE_CATEGORY_SEARCH]: (state: any, action: GenericAction) => ({
...state,
searchText: action.searchText,
resultsByTerm: TERM_SELECTOR[action.type](state.resultsByTerm, action),
}),
[GifTypes.SEARCH_FAILURE]: (state: any, action: GenericAction) => ({
...state,
searchText: action.searchText,
resultsByTerm: TERM_SELECTOR[action.type](state.resultsByTerm, action),
}),
[GifTypes.CLEAR_SEARCH_RESULTS]: (state: any) => ({
...state,
searchText: '',
resultsByTerm: {},
}),
[GifTypes.SAVE_SEARCH_SCROLL_POSITION]: (state: any, action: GenericAction) => ({
...state,
scrollPosition: action.scrollPosition,
}),
[GifTypes.SAVE_SEARCH_PRIOR_LOCATION]: (state: any, action: GenericAction) => ({
...state,
priorLocation: action.priorLocation,
}),
[GifTypes.UPDATE_SEARCH_TEXT]: (state: any, action: GenericAction) => ({
...state,
searchText: action.searchText,
}),
[GifTypes.SAVE_SEARCH_BAR_TEXT]: (state: any, action: GenericAction) => ({
...state,
searchBarText: action.searchBarText,
}),
};
const CATEGORIES_SELECTORS: ReducerMap = {
[GifTypes.REQUEST_CATEGORIES_LIST]: (state: any) => ({
...state,
isFetching: true,
}),
[GifTypes.CATEGORIES_LIST_RECEIVED]: (state: any, action: GenericAction) => {
const {cursor, tags} = action;
const {tagsList: oldTagsList = []} = state;
const tagsDict: any = {};
const newTagsList = tags.filter((item: any) => {
return Boolean(item && item.gfycats[0] && item.gfycats[0].width);
}).map((item: any) => {
tagsDict[item.tag] = true;
return {
tagName: item.tag,
gfyId: item.gfycats[0].gfyId,
};
});
const tagsList = [...oldTagsList, ...newTagsList];
return {
...state,
cursor,
hasMore: Boolean(cursor),
isFetching: false,
tagsList,
tagsDict,
};
},
[GifTypes.CATEGORIES_LIST_FAILURE]: (state: any) => ({
...state,
isFetching: false,
}),
};
const TERM_SELECTOR: ReducerMap = {
[GifTypes.REQUEST_SEARCH]: (state: any, action: GenericAction) => ({
...state,
[action.searchText]: {
...state[action.searchText],
isFetching: true,
didInvalidate: false,
pages: PAGE_SELECTOR[action.type](state[action.searchText], action),
},
}),
[GifTypes.RECEIVE_SEARCH]: (state: any, action: GenericAction) => {
const gfycats = action.gfycats.filter((item: any) => {
return Boolean(item.gfyId && item.width && item.height);
});
const newItems = gfycats.map((gfycat: any) => gfycat.gfyId);
return {
...state,
[action.searchText]: {
...state[action.searchText],
isFetching: false,
items: typeof state[action.searchText] !== 'undefined' &&
state[action.searchText].items ?
[...state[action.searchText].items, ...newItems] :
newItems,
moreRemaining:
typeof state[action.searchText] !== 'undefined' &&
state[action.searchText].items ?
[
...state[action.searchText].items,
...action.gfycats,
].length < action.found :
action.gfycats.length < action.found,
count: action.count,
found: action.found,
start: action.start,
currentPage: action.currentPage,
pages: PAGE_SELECTOR[action.type](state[action.searchText], action),
cursor: action.cursor,
},
};
},
[GifTypes.RECEIVE_CATEGORY_SEARCH]: (state: any, action: GenericAction) => {
const gfycats = action.gfycats.filter((item: any) => {
return Boolean(item.gfyId && item.width && item.height);
});
const newItems = gfycats.map((gfycat: any) => gfycat.gfyId);
return {
...state,
[action.searchText]: {
...state[action.searchText],
isFetching: false,
items: typeof state[action.searchText] !== 'undefined' &&
state[action.searchText].items ?
[...state[action.searchText].items, ...newItems] :
newItems,
cursor: action.cursor,
moreRemaining: Boolean(action.cursor),
},
};
},
[GifTypes.RECEIVE_SEARCH_END]: (state: any, action: GenericAction) => ({
...state,
[action.searchText]: {
...state[action.searchText],
isFetching: false,
moreRemaining: false,
},
}),
[GifTypes.SEARCH_FAILURE]: (state: any, action: GenericAction) => ({
...state,
[action.searchText]: {
...state[action.searchText],
isFetching: false,
items: [],
moreRemaining: false,
count: 0,
found: 0,
start: 0,
isEmpty: true,
},
}),
};
const PAGE_SELECTOR: ReducerMap = {
[GifTypes.REQUEST_SEARCH]: (state: {pages?: any} = {}) => {
if (typeof state.pages == 'undefined') {
return {};
}
return {...state.pages};
},
[GifTypes.RECEIVE_SEARCH]: (state: any, action: GenericAction) => ({
...state.pages,
[action.currentPage]: action.gfycats.map((gfycat: any) => gfycat.gfyId),
}),
};
const CACHE_SELECTORS: ReducerMap = {
[GifTypes.CACHE_GIFS]: (state: any, action: GenericAction) => ({
...state,
gifs: CACHE_GIF_SELECTOR[action.type](state.gifs, action),
updating: false,
}),
[GifTypes.CACHE_REQUEST]: (state: any, action: GenericAction) => ({
...state,
...action.payload,
}),
};
const CACHE_GIF_SELECTOR: ReducerMap = {
[GifTypes.CACHE_GIFS]: (state: any, action: GenericAction) => ({
...state,
...action.gifs.reduce((map: any, obj: any) => {
map[obj.gfyId] = obj;
return map;
}, {}),
}),
};
function appReducer(state: any = {}, action: GenericAction) {
const nextState = {...state};
switch (action.type) {
case GifTypes.SAVE_APP_PROPS:
return {...nextState, ...action.props};
default:
return state;
}
}
function categoriesReducer(state: any = {}, action: GenericAction) {
const selector = CATEGORIES_SELECTORS[action.type];
return selector ? selector(state, action) : state;
}
function searchReducer(state: any = {}, action: GenericAction) {
const selector = SEARCH_SELECTORS[action.type];
return selector ? selector(state, action) : state;
}
function cacheReducer(state: any = {}, action: GenericAction) {
const selector = CACHE_SELECTORS[action.type];
return selector ? selector(state, action) : state;
}
export default combineReducers({
app: appReducer,
categories: categoriesReducer,
search: searchReducer,
cache: cacheReducer,
});

View File

@ -13,7 +13,6 @@ import preferences from './preferences';
import typing from './typing';
import integrations from './integrations';
import emojis from './emojis';
import gifs from './gifs';
import admin from './admin';
import jobs from './jobs';
import search from './search';
@ -39,7 +38,6 @@ export default combineReducers({
typing,
integrations,
emojis,
gifs,
admin,
jobs,
search,

View File

@ -150,39 +150,6 @@ const state: GlobalState = {
roles: {},
pending: new Set(),
},
gifs: {
app: {
appClassName: '',
appId: '',
appName: '',
basePath: '',
enableHistory: false,
header: {
tabs: [],
displayText: false,
},
itemTapType: 0,
shareEvent: '',
},
categories: {
tagsList: [],
tagsDict: {},
cursor: '',
hasMore: false,
isFetching: false,
},
cache: {
gifs: {},
updating: false,
},
search: {
searchText: '',
searchBarText: '',
resultsByTerm: {},
scrollPosition: 0,
priorLocation: null,
},
},
schemes: {
schemes: {},
},

View File

@ -1,26 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Gfycat from 'gfycat-sdk';
const defaultKey = '2_KtH_W5';
const defaultSecret = '3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof';
let activeKey: string|null = null;
let activeSecret: string | null = null;
let instance: any = null;
export default function gfycatSdk(key: string, secret: string): any {
if (instance && activeKey === key && activeSecret === secret) {
return instance;
}
if (!key || !secret) {
instance = new Gfycat({client_id: defaultKey, client_secret: defaultSecret});
return instance;
}
activeKey = key;
activeSecret = secret;
instance = new Gfycat({client_id: key, client_secret: secret});
return instance;
}

View File

@ -1,4 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
declare module 'gfycat-sdk';

View File

@ -86,7 +86,6 @@
"fast-deep-equal": "3.1.3",
"flexsearch": "0.6.32",
"font-awesome": "4.7.0",
"gfycat-sdk": "1.4.18",
"highlight.js": "11.6.0",
"history": "4.10.1",
"hoist-non-react-statics": "3.3.2",
@ -6784,27 +6783,6 @@
"@babel/core": "^7.0.0"
}
},
"node_modules/babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
"dependencies": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
}
},
"node_modules/babel-runtime/node_modules/core-js": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
"hasInstallScript": true
},
"node_modules/babel-runtime/node_modules/regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
},
"node_modules/bail": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
@ -11861,14 +11839,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gfycat-sdk": {
"version": "1.4.18",
"resolved": "https://registry.npmjs.org/gfycat-sdk/-/gfycat-sdk-1.4.18.tgz",
"integrity": "sha512-BrINtO6rj8Nr0pm38Qr3epayOuvlKcEFcDCw6yL9T4SrsWTECct6FS/isli766kdij2GGG6bWU6bRp+fDS2Cbg==",
"dependencies": {
"babel-runtime": "^6.23.0"
}
},
"node_modules/gifsicle": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-5.3.0.tgz",
@ -28599,27 +28569,6 @@
"babel-preset-current-node-syntax": "^1.0.0"
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
},
"dependencies": {
"core-js": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
}
}
},
"bail": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
@ -32616,14 +32565,6 @@
"get-intrinsic": "^1.1.1"
}
},
"gfycat-sdk": {
"version": "1.4.18",
"resolved": "https://registry.npmjs.org/gfycat-sdk/-/gfycat-sdk-1.4.18.tgz",
"integrity": "sha512-BrINtO6rj8Nr0pm38Qr3epayOuvlKcEFcDCw6yL9T4SrsWTECct6FS/isli766kdij2GGG6bWU6bRp+fDS2Cbg==",
"requires": {
"babel-runtime": "^6.23.0"
}
},
"gifsicle": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-5.3.0.tgz",
@ -35724,7 +35665,6 @@
"fast-deep-equal": "3.1.3",
"flexsearch": "0.6.32",
"font-awesome": "4.7.0",
"gfycat-sdk": "1.4.18",
"highlight.js": "11.6.0",
"history": "4.10.1",
"hoist-non-react-statics": "3.3.2",

View File

@ -122,8 +122,6 @@ export type ClientConfig = {
FeatureFlagCallsEnabled: string;
FeatureFlagGraphQL: string;
ForgotPasswordLink: string;
GfycatAPIKey: string;
GfycatAPISecret: string;
GiphySdkKey: string;
GoogleDeveloperKey: string;
GuestAccountsEnforceMultifactorAuthentication: string;
@ -336,8 +334,6 @@ export type ServiceSettings = {
EnableCustomEmoji: boolean;
EnableEmojiPicker: boolean;
EnableGifPicker: boolean;
GfycatAPIKey: string;
GfycatAPISecret: string;
GiphySdkKey: string;
PostEditTimeLimit: number;
TimeBetweenUserTypingUpdatesMilliseconds: number;

View File

@ -1,164 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export type GifsState = {
app: GifsAppState;
cache: GifsCacheState;
categories: GifsCategoriesState;
search: GifsSearchState;
};
export type GifsAppState = {
appClassName: string;
appId: string;
appName: string;
basePath: string;
enableHistory: boolean;
header: {
tabs: number[];
displayText: boolean;
};
itemTapType: number;
shareEvent: string;
}
type GifsCacheState = {
gifs: Record<string, GfycatAPIItem>;
updating: boolean;
}
type GifsCategoriesState = {
cursor: string;
hasMore: boolean;
isFetching: boolean;
tagsDict: Record<string, boolean>;
tagsList: GfycatAPITag[];
}
type GifsSearchState = {
priorLocation: string | null;
resultsByTerm: Record<string, GifsResult>;
scrollPosition: number;
searchBarText: string;
searchText: string;
}
export type GifsResult = GfycatAPIPaginatedResponse & {
count: number;
currentPage: number;
didInvalidate: boolean;
found: number;
isFetching: boolean;
items: string[];
moreRemaining: boolean;
pages: Record<number, string[]>;
start: number;
}
export interface GfycatAPIPaginatedResponse {
cursor?: string;
gfycats: GfycatAPIItem[];
totalCount?: number;
}
export interface GfycatAPIItemResponse {
gfyItem: GfycatAPIItem;
}
export interface GfycatAPIItem {
anonymous?: boolean;
avgColor: string;
captionsUrl?: null;
content_urls: { [key: string]: GfycatAPIContent };
createDate: number;
description?: string;
dislikes?: number;
domainWhitelist?: any[];
duration?: number;
encoding?: boolean;
extraLemmas?: string;
finished?: boolean;
frameRate: number;
gatekeeper: number;
geoWhitelist?: any[];
gfyId: string;
gfyName: string;
gfyNumber?: string;
gfySlug?: string;
gif100px?: string;
gifSize?: number;
gifUrl: string;
hasAudio: boolean;
hasTransparency: boolean;
height: number;
languageCategories: string[];
languageText?: string;
likes: number;
max1mbGif?: string;
max2mbGif: string;
max5mbGif: string;
md5?: string;
miniPosterUrl: string;
miniUrl?: string;
mobileHeight?: number;
mobilePosterUrl?: string;
mobileUrl: string;
mobileWidth?: number;
mp4Size?: number;
mp4Url: string;
nsfw: boolean | number;
numFrames: number;
posterUrl: string;
published: number;
rating?: string;
ratio?: null;
sitename?: string;
source?: number;
tags: string[];
thumb100PosterUrl: string;
title?: string;
type?: number;
url?: string;
userData?: GfycatAPIUser | [];
userDisplayName?: string;
userName?: string;
username?: string;
userProfileImageUrl?: string;
views: number;
views5?: number;
webmSize?: number;
webmUrl?: string;
webpUrl?: string;
width: number;
}
export interface GfycatAPIContent {
width: number;
size: number;
url: string;
height: number;
}
export interface GfycatAPIUser {
createDate?: number;
description?: string;
followers: number;
following: number;
iframeProfileImageVisible?: boolean;
name: string;
profileImageUrl: string;
profileUrl?: string;
publishedGfycats?: number;
subscription?: number;
url?: string;
userid?: string;
username: string;
verified: boolean;
views: number;
}
export interface GfycatAPITag {
tagName: string;
gfyId: string;
}

View File

@ -29,7 +29,6 @@ import {ThreadsState} from './threads';
import {Typing} from './typing';
import {UsersState} from './users';
import {AppsState} from './apps';
import {GifsState} from './gifs';
export type GlobalState = {
entities: {
@ -61,7 +60,6 @@ export type GlobalState = {
pending: Set<string>;
};
schemes: SchemesState;
gifs: GifsState;
groups: GroupsState;
channelCategories: ChannelCategoriesState;
apps: AppsState;