Commit 69b8b863 authored by Quoc Huy Nguyen Dinh's avatar Quoc Huy Nguyen Dinh
Browse files

Merge branch 'develop' into '145-remove-gpt'

# Conflicts:
#   src/app/components/cards/PostsList.jsx
#   src/app/components/pages/CommunityRoles.jsx
#   src/server/server.js
parents 8627755d 108cd66a
......@@ -4,6 +4,7 @@
"@babel/plugin-transform-runtime",
["@babel/plugin-proposal-decorators", { "legacy": true }],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-modules-commonjs"
"@babel/plugin-transform-modules-commonjs",
"babel-plugin-transform-class-properties"
]
}
......@@ -40,6 +40,8 @@ find node_modules/eslint-config-airbnb -name '*.js'|xargs sed -i "s/': 2/': 1/"
"no-nested-ternary": [
0
],
"import/no-dynamic-require": 1,
"global-require": 1,
"prefer-destructuring": 0,
"react/no-unused-state": 1,
"no-unused-expressions": 1,
......@@ -48,6 +50,7 @@ find node_modules/eslint-config-airbnb -name '*.js'|xargs sed -i "s/': 2/': 1/"
"no-undef": 2,
"no-case-declarations": 0,
"no-underscore-dangle": 0,
"no-inner-declarations": 1,
"camelcase": [
0
],
......
......@@ -9,3 +9,5 @@ vendor/*
tmp/*
.vagrant
lib
*.bk
docs
......@@ -43,7 +43,7 @@ variables:
run-unit-tests:
stage: test
image: node:12.16.2
image: node:12.22.6
tags:
- public-runner-docker
only:
......@@ -57,7 +57,7 @@ run-unit-tests:
run-eslint:
stage: test
image: node:12.16.2
image: node:12.22.6
tags:
- public-runner-docker
only:
......
import '@storybook/addon-knobs/register';
import 'storybook-addon-intl/register';
\ No newline at end of file
import { addDecorator, configure } from '@storybook/react';
import { setIntlConfig, withIntl } from 'storybook-addon-intl';
import tt from 'counterpart';
import { addLocaleData } from 'react-intl';
import en from 'react-intl/locale-data/en';
import es from 'react-intl/locale-data/es';
import ru from 'react-intl/locale-data/ru';
import fr from 'react-intl/locale-data/fr';
import it from 'react-intl/locale-data/it';
import ko from 'react-intl/locale-data/ko';
import zh from 'react-intl/locale-data/zh';
import pl from 'react-intl/locale-data/pl';
addLocaleData([...en, ...es, ...ru, ...fr, ...it, ...ko, ...zh, ...pl]);
tt.registerTranslations('en', require('counterpart/locales/en'));
tt.registerTranslations('en', require('app/locales/en.json'));
tt.registerTranslations('es', require('app/locales/counterpart/es'));
tt.registerTranslations('es', require('app/locales/es.json'));
tt.registerTranslations('ru', require('counterpart/locales/ru'));
tt.registerTranslations('ru', require('app/locales/ru.json'));
tt.registerTranslations('fr', require('app/locales/counterpart/fr'));
tt.registerTranslations('fr', require('app/locales/fr.json'));
tt.registerTranslations('it', require('app/locales/counterpart/it'));
tt.registerTranslations('it', require('app/locales/it.json'));
tt.registerTranslations('ko', require('app/locales/counterpart/ko'));
tt.registerTranslations('ko', require('app/locales/ko.json'));
tt.registerTranslations('zh', require('app/locales/counterpart/zh'));
tt.registerTranslations('zh', require('app/locales/zh.json'));
tt.registerTranslations('pl', require('app/locales/counterpart/pl'));
tt.registerTranslations('pl', require('app/locales/pl.json'));
const getMessages = (locale) => {
tt.setLocale(locale)
return tt('g')
}
setIntlConfig({
locales: ['en', 'es', 'ru', 'fr', 'it', 'ko', 'zh', 'pl'],
defaultLocale: 'en',
getMessages
});
addDecorator(withIntl);
const req = require.context('../src/app/components', true, /story\.jsx$/);
function loadStories() {
req.keys().forEach(req);
}
configure(loadStories, module);
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const css_loaders = [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }
];
const scss_loaders = [
{ loader: 'css-loader' },
{ loader: 'postcss-loader' },
{
loader: 'sass-loader',
options: {
sourceMap: true,
data: '@import "app";',
includePaths: [
path.join(__dirname, '../src/app/assets/stylesheets'),
]
}
},
];
module.exports = {
stories: [
// "../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-knobs",
"storybook-addon-intl/register",
'@storybook/addon-postcss',
{
name: '@storybook/addon-postcss',
options: {
postcssLoaderOptions: {
implementation: require('postcss'),
},
},
},
],
webpackFinal: async (config, { configType }) => {
config.resolve = {
alias: {
assets: path.resolve(__dirname, '../src/app/assets/'),
app: path.resolve(__dirname, '../src/app/'),
},
extensions: ['.js', '.json', '.jsx'],
modules: [
path.resolve(__dirname, '../src'),
'node_modules'
]
};
config.module = {
rules: [
{test: /\.(jpe?g|png)/, use: 'url-loader?limit=4096'},
// {test: /\.json$/, use: 'json-loader'},
{test: /\.js$|\.jsx$/, exclude: /node_modules/, use: 'babel-loader'},
{test: /\.svg$/, use: 'svg-inline-loader'},
{
test: /\.css$/,
use: css_loaders
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: scss_loaders
})
},
]
};
return {
...config,
};
},
}
module.exports = {
plugins: [
require('autoprefixer'),
],
};
import React from 'react';
import '!style-loader!css-loader!sass-loader!../src/app/assets/stylesheets/app.scss';
const { addDecorator, configure } = require('@storybook/react');
const { setIntlConfig, withIntl } = require('storybook-addon-intl');
const tt = require('counterpart');
const { addLocaleData } = require('react-intl');
const en = require('react-intl/locale-data/en');
const es = require('react-intl/locale-data/es');
const ru = require('react-intl/locale-data/ru');
const fr = require('react-intl/locale-data/fr');
const it = require('react-intl/locale-data/it');
const ko = require('react-intl/locale-data/ko');
const zh = require('react-intl/locale-data/zh');
const pl = require('react-intl/locale-data/pl');
const { addons, mockChannel } = require('@storybook/addons');
addons.setChannel(mockChannel());
addLocaleData([...en, ...es, ...ru, ...fr, ...it, ...ko, ...zh, ...pl]);
tt.registerTranslations('en', require('counterpart/locales/en'));
tt.registerTranslations('en', require('../src/app/locales/en.json'));
tt.registerTranslations('es', require('../src/app/locales/counterpart/es'));
tt.registerTranslations('es', require('../src/app/locales/es.json'));
tt.registerTranslations('ru', require('counterpart/locales/ru'));
tt.registerTranslations('ru', require('../src/app/locales/ru.json'));
tt.registerTranslations('fr', require('../src/app/locales/counterpart/fr'));
tt.registerTranslations('fr', require('../src/app/locales/fr.json'));
tt.registerTranslations('it', require('../src/app/locales/counterpart/it'));
tt.registerTranslations('it', require('../src/app/locales/it.json'));
tt.registerTranslations('ko', require('../src/app/locales/counterpart/ko'));
tt.registerTranslations('ko', require('../src/app/locales/ko.json'));
tt.registerTranslations('zh', require('../src/app/locales/counterpart/zh'));
tt.registerTranslations('zh', require('../src/app/locales/zh.json'));
tt.registerTranslations('pl', require('../src/app/locales/counterpart/pl'));
tt.registerTranslations('pl', require('../src/app/locales/pl.json'));
const getMessages = (locale) => {
tt.setLocale(locale)
return tt('g')
}
setIntlConfig({
locales: ['en', 'es', 'ru', 'fr', 'it', 'ko', 'zh', 'pl'],
defaultLocale: 'en',
getMessages
});
const container = {
display: 'table',
position: 'absolute',
height: '100%',
width: '100%',
};
const middle = {
display: 'table-cell',
verticalAlign: 'middle',
};
const center = {
marginLeft: 'auto',
marginRight: 'auto',
//border: 'solid black',
width: '300px',
};
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
export const decorators = [
(Story) => (
<div style={container}>
<div style={middle}>
<div style={center}>
<Story/>
</div>
</div>
</div>
),
withIntl,
];
require('@babel/register');
module.exports = require('../webpack/storybook.config.js');
FROM node:12.16.2 as development
FROM node:12.22.6 as development
WORKDIR /var/app
......@@ -18,7 +18,7 @@ FROM development as dependencies
RUN yarn install --non-interactive --frozen-lockfile --ignore-optional --production
### BUILD MINIFIED PRODUCTION ##
FROM node:12.16.2-alpine as production
FROM node:12.22.6-alpine as production
WORKDIR /var/app
......
MIT License
Copyright (c) 2021 hive
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.
......@@ -20,9 +20,10 @@
"start": "NODE_OPTIONS=\"--trace-warnings\" NODE_ENV=development babel-node ./webpack/dev-server.js",
"debug": "NODE_OPTIONS=\"--trace-warnings\" NODE_ENV=development webpack --config ./webpack/debug.config.js && rm -rf ./lib && babel src --source-maps --out-dir lib -D && node --inspect-brk lib/server/index.js",
"checktranslations": "node scripts/check_translations.js",
"storybook": "start-storybook -p 9001 -c .storybook",
"storybook": "start-storybook --no-manager-cache -p 6006",
"storybook-build": "build-storybook -c .storybook -o docs",
"build:analyze": "webpack-bundle-analyzer --port 4200 dist/stats.json"
"build:analyze": "webpack-bundle-analyzer --port 4200 dist/stats.json",
"build:storybook": "build-storybook"
},
"author": "HiveBlog",
"license": "MIT",
......@@ -160,13 +161,18 @@
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.12.1",
"@storybook/addon-actions": "^6.3.8",
"@storybook/addon-essentials": "^6.3.8",
"@storybook/addon-knobs": "^6.3.1",
"@storybook/addon-links": "^6.3.8",
"@storybook/addon-postcss": "^2.0.0",
"@storybook/react": "^6.3.8",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "10.1.0",
"babel-jest": "^23.4.2",
"babel-loader": "8.1.0",
"babel-plugin-react-intl": "2.3.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-inline-environment-variables": "0.2.0",
"css-loader": "5.0.1",
"dev-ip": "1.0.1",
......
/*global $STM_Config*/
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
......@@ -50,15 +51,17 @@ class App extends React.Component {
}
shouldComponentUpdate(nextProps, nextState) {
const { pathname, new_visitor, nightmodeEnabled, showAnnouncement } = this.props;
const {
pathname, new_visitor, nightmodeEnabled, showAnnouncement
} = this.props;
const n = nextProps;
return (
pathname !== n.pathname ||
new_visitor !== n.new_visitor ||
this.state.showBanner !== nextState.showBanner ||
this.state.showCallout !== nextState.showCallout ||
nightmodeEnabled !== n.nightmodeEnabled ||
showAnnouncement !== n.showAnnouncement
pathname !== n.pathname
|| new_visitor !== n.new_visitor
|| this.state.showBanner !== nextState.showBanner
|| this.state.showCallout !== nextState.showCallout
|| nightmodeEnabled !== n.nightmodeEnabled
|| showAnnouncement !== n.showAnnouncement
);
}
......@@ -67,14 +70,15 @@ class App extends React.Component {
};
render() {
const { params, children, new_visitor, nightmodeEnabled, viewMode, pathname, category, order } = this.props;
const {
params, children, new_visitor, nightmodeEnabled, viewMode, pathname, category, order,
} = this.props;
const whistleView = viewMode === VIEW_MODE_WHISTLE;
const headerHidden = whistleView;
const params_keys = Object.keys(params);
const ip =
pathname === '/' ||
(params_keys.length === 2 && params_keys[0] === 'order' && params_keys[1] === 'category');
const ip = pathname === '/'
|| (params_keys.length === 2 && params_keys[0] === 'order' && params_keys[1] === 'category');
const alert = this.props.error;
let callout = null;
if (this.state.showCallout && alert) {
......@@ -92,15 +96,13 @@ class App extends React.Component {
callout = (
<div className="App__announcement row">
<div className="column">
<div className={classNames('callout success', { alert }, { warning }, { success })}>
<div className={classNames('callout success', { alert })}>
<CloseButton onClick={() => this.setState({ showCallout: false })} />
<ul>
<li>
/*
<a href="https://steemit.com/steemit/@steemitblog/steemit-com-is-now-open-source">
...STORY TEXT...
</a>
*/
</li>
</ul>
</div>
......@@ -112,7 +114,7 @@ class App extends React.Component {
callout = (
<div className="App__announcement row">
<div className="column">
<div className={classNames('callout warning', { alert }, { warning }, { success })}>
<div className={classNames('callout warning', { alert })}>
<CloseButton onClick={() => this.setState({ showCallout: false })} />
<p>{tt('g.read_only_mode')}</p>
</div>
......@@ -161,17 +163,14 @@ App.propTypes = {
export default connect(
(state, ownProps) => {
const current_user = state.user.get('current');
const current_account_name = current_user ? current_user.get('username') : state.offchain.get('account');
return {
viewMode: state.app.get('viewMode'),
error: state.app.get('error'),
new_visitor:
!state.user.get('current') &&
!state.offchain.get('user') &&
!state.offchain.get('account') &&
state.offchain.get('new_visit'),
!state.user.get('current')
&& !state.offchain.get('user')
&& !state.offchain.get('account')
&& state.offchain.get('new_visit'),
nightmodeEnabled: state.app.getIn(['user_preferences', 'nightmode']),
pathname: ownProps.location.pathname,
......
......@@ -23,7 +23,6 @@
@import "./elements/TagList";
@import "./elements/Reputation";
@import "./elements/Reblog";
@import "./elements/YoutubePreview";
@import "./elements/ShareMenu";
@import "./elements/Author/styles";
@import "./elements/AuthorDropdown";
......
import React, { PureComponent } from 'react';
import Autocomplete from 'react-autocomplete';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import { validate_account_name } from 'app/utils/ChainValidation';
import { List, Set } from 'immutable';
import tt from 'counterpart';
......
......@@ -6,7 +6,7 @@ import ReplyEditor from 'app/components/elements/ReplyEditor';
import MuteButton from 'app/components/elements/MuteButton';
import FlagButton from 'app/components/elements/FlagButton';
import MarkdownViewer from 'app/components/cards/MarkdownViewer';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
// import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import Voting from 'app/components/elements/Voting';
import { connect } from 'react-redux';
import { Link } from 'react-router';
......
import React from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Component } from 'react';
import Remarkable from 'remarkable';
import sanitizeConfig, { noImageText } from 'app/utils/SanitizeConfig';
import sanitize from 'sanitize-html';
......@@ -134,6 +134,7 @@ class MarkdownViewer extends Component {
chk += s.charCodeAt(i) * (i + 1);
}
// eslint-disable-next-line no-bitwise
return (chk & 0xffffffff).toString(16);
}
......@@ -146,6 +147,7 @@ class MarkdownViewer extends Component {
sections.push(markdown);
if (section === '') {
// eslint-disable-next-line no-continue
continue;
}
}
......@@ -155,23 +157,24 @@ class MarkdownViewer extends Component {
idx += 1;
}
const cn =
'Markdown' +
(this.props.className ? ` ${this.props.className}` : '') +
(html ? ' html' : '') +
(large ? '' : ' MarkdownViewer--small');
const cn = 'Markdown'
+ (this.props.className ? ` ${this.props.className}` : '')
+ (html ? ' html' : '')
+ (large ? '' : ' MarkdownViewer--small');
return (
<div className={'MarkdownViewer ' + cn}>
{sections}
{noImageActive && allowNoImage && (
<div
key={'hidden-content'}
role="link"
tabIndex={0}
key="hidden-content"
onClick={this.onAllowNoImage}
className="MarkdownViewer__negative_group"
>
{tt('markdownviewer_jsx.images_were_hidden_due_to_low_ratings')}
<button style={{ marginBottom: 0 }} className="button hollow tiny float-right">
<button type="button" style={{ marginBottom: 0 }} className="button hollow tiny float-right">
{tt('g.show')}
</button>
</div>
......
......@@ -7,9 +7,10 @@ export default class NotFoundMessage extends React.Component {
<div className="NotFound float-center">
<div>
<Icon name="hive" size="4x" />
<h4 className="NotFound__header">Sorry! This page doesn't exist.</h4>
<h4 className="NotFound__header">Sorry! This page doesn&aquote;t exist.</h4>
<p>
Not to worry. You can head back to{' '}
Not to worry. You can head back to
{' '}
<a style={{ fontWeight: 800 }} href="/">
our homepage
</a>
......
......@@ -47,7 +47,8 @@ const highlightText = (text, highlight) => {
<span key={i} style={part.toLowerCase() === highlight.toLowerCase() ? { fontWeight: 'bold' } : {}}>
{part}
</span>
))}{' '}
))}
{' '}
</span>
);
};
......@@ -89,10 +90,6 @@ class NotificationsList extends React.Component {
mentions: ['mention'],
};
constructor() {
super();
}
componentWillMount() {
const { username, getAccountNotifications } = this.props;
if (username) {
......@@ -137,7 +134,7 @@ class NotificationsList extends React.Component {
} else {
notificationElement.classList.remove('even');
}
} else if (this.notificationFilterToTypes.hasOwnProperty(notificationFilter)) {
} else if (Object.prototype.hasOwnProperty.call(this.notificationFilterToTypes, notificationFilter)) {
const notificationTypes = this.notificationFilterToTypes[notificationFilter];
let matchType = false;
......@@ -196,13 +193,13 @@ class NotificationsList extends React.Component {
const renderItem = (item) => {