From 95203a462e6ba45142954dcfb89b15be2bd061e0 Mon Sep 17 00:00:00 2001
From: apple502j <33279053+apple502j@users.noreply.github.com>
Date: Thu, 10 Jan 2019 19:02:59 +0900
Subject: [PATCH 1/9] Change Mobile Chrome supported ver to 63+
---
src/views/faq/l10n.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/views/faq/l10n.json b/src/views/faq/l10n.json
index 71617c3c0..0d9ba0167 100644
--- a/src/views/faq/l10n.json
+++ b/src/views/faq/l10n.json
@@ -24,7 +24,7 @@
"faq.requirementsDesktopSafari":"Safari (11+)",
"faq.requirementsDesktopIE":"Internet Explorer is NOT supported.",
"faq.requirementsTablet":"Tablet",
- "faq.requirementsTabletChrome":"Mobile Chrome (62+)",
+ "faq.requirementsTabletChrome":"Mobile Chrome (63+)",
"faq.requirementsTabletSafari":"Mobile Safari (11+)",
"faq.requirementsNote":"Note:",
"faq.requirementsNoteDesktop":"If your computer doesn’t meet these requirements, you can try the Scratch Desktop editor (see next item in FAQ). ",
From f7e89227578991b2c3e00797265e87f8eaec504a Mon Sep 17 00:00:00 2001
From: Paul Kaplan
Date: Thu, 10 Jan 2019 10:46:01 -0500
Subject: [PATCH 2/9] Allow loading more than 20 replies
---
package.json | 1 +
src/l10n.json | 2 +-
src/redux/preview.js | 28 ++++++++++++++-----
.../preview/comment/top-level-comment.jsx | 24 ++++++++--------
src/views/preview/presentation.jsx | 4 +++
src/views/preview/project-view.jsx | 11 ++++++++
6 files changed, 51 insertions(+), 19 deletions(-)
diff --git a/package.json b/package.json
index edd610a5b..c5135a36e 100644
--- a/package.json
+++ b/package.json
@@ -78,6 +78,7 @@
"lodash.defaultsdeep": "3.10.0",
"lodash.isarray": "3.0.4",
"lodash.merge": "3.3.2",
+ "lodash.mergewith": "4.6.1",
"lodash.omit": "3.1.0",
"lodash.range": "3.0.1",
"minilog": "2.0.8",
diff --git a/src/l10n.json b/src/l10n.json
index f8d8f3285..90eaeba70 100644
--- a/src/l10n.json
+++ b/src/l10n.json
@@ -237,7 +237,7 @@
"comments.post": "Post",
"comments.cancel": "Cancel",
"comments.lengthWarning": "{remainingCharacters, plural, one {1 character left} other {{remainingCharacters} characters left}}",
- "comments.seeMoreReplies": "{repliesCount, plural, one {See 1 more reply} other {See all {repliesCount} replies}}",
+ "comments.loadMoreReplies": "See more replies",
"comments.status.delbyusr": "Deleted by project owner",
"comments.status.censbyfilter": "Censored by filter",
"comments.status.delbyparentcomment": "Parent comment deleted",
diff --git a/src/redux/preview.js b/src/redux/preview.js
index 24b746ca0..18afb9b59 100644
--- a/src/redux/preview.js
+++ b/src/redux/preview.js
@@ -1,11 +1,13 @@
const defaults = require('lodash.defaults');
const keyMirror = require('keymirror');
const async = require('async');
-const merge = require('lodash.merge');
+const mergeWith = require('lodash.mergewith');
const api = require('../lib/api');
const log = require('../lib/log');
+const COMMENT_LIMIT = 20;
+
module.exports.Status = keyMirror({
FETCHED: null,
NOT_FETCHED: null,
@@ -149,7 +151,19 @@ module.exports.previewReducer = (state, action) => {
});
case 'SET_REPLIES':
return Object.assign({}, state, {
- replies: merge({}, state.replies, action.replies)
+ // Append new replies to the state.replies structure
+ replies: mergeWith({}, state.replies, action.replies, (replies, newReplies) => (
+ (replies || []).concat(newReplies || [])
+ )),
+ // Also set the `moreRepliesToLoad` property on the top-level comments
+ comments: state.comments.map(comment => {
+ if (action.replies[comment.id]) {
+ return Object.assign({}, comment, {
+ moreRepliesToLoad: action.replies[comment.id].length === COMMENT_LIMIT
+ });
+ }
+ return comment;
+ })
});
case 'SET_LOVED':
return Object.assign({}, state, {
@@ -448,7 +462,6 @@ module.exports.getFavedStatus = (id, username, token) => (dispatch => {
});
module.exports.getTopLevelComments = (id, offset, isAdmin, token) => (dispatch => {
- const COMMENT_LIMIT = 20;
dispatch(module.exports.setFetchStatus('comments', module.exports.Status.FETCHING));
api({
uri: `${isAdmin ? '/admin' : ''}/projects/${id}/comments`,
@@ -467,7 +480,7 @@ module.exports.getTopLevelComments = (id, offset, isAdmin, token) => (dispatch =
}
dispatch(module.exports.setFetchStatus('comments', module.exports.Status.FETCHED));
dispatch(module.exports.setComments(body));
- dispatch(module.exports.getReplies(id, body.map(comment => comment.id), isAdmin, token));
+ dispatch(module.exports.getReplies(id, body.map(comment => comment.id), 0, isAdmin, token));
// If we loaded a full page of comments, assume there are more to load.
// This will be wrong (1 / COMMENT_LIMIT) of the time, but does not require
@@ -503,17 +516,18 @@ module.exports.getCommentById = (projectId, commentId, isAdmin, token) => (dispa
// If the comment is not a reply, show it as top level and load replies
dispatch(module.exports.setFetchStatus('comments', module.exports.Status.FETCHED));
dispatch(module.exports.setComments([body]));
- dispatch(module.exports.getReplies(projectId, [body.id], isAdmin, token));
+ dispatch(module.exports.getReplies(projectId, [body.id], 0, isAdmin, token));
});
});
-module.exports.getReplies = (projectId, commentIds, isAdmin, token) => (dispatch => {
+module.exports.getReplies = (projectId, commentIds, offset, isAdmin, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('replies', module.exports.Status.FETCHING));
const fetchedReplies = {};
async.eachLimit(commentIds, 10, (parentId, callback) => {
api({
uri: `${isAdmin ? '/admin' : ''}/projects/${projectId}/comments/${parentId}/replies`,
- authentication: isAdmin ? token : null
+ authentication: isAdmin ? token : null,
+ params: {offset: offset || 0, limit: COMMENT_LIMIT}
}, (err, body) => {
if (err) {
return callback(`Error fetching comment replies: ${err}`);
diff --git a/src/views/preview/comment/top-level-comment.jsx b/src/views/preview/comment/top-level-comment.jsx
index 188150d7b..86b20b9ac 100644
--- a/src/views/preview/comment/top-level-comment.jsx
+++ b/src/views/preview/comment/top-level-comment.jsx
@@ -28,9 +28,11 @@ class TopLevelComment extends React.Component {
}
handleExpandThread () {
- this.setState({
- expanded: true
- });
+ if (this.state.expanded) {
+ this.props.onLoadMoreReplies(this.props.id, this.props.replies.length);
+ } else {
+ this.setState({expanded: true});
+ }
}
handleDeleteReply (replyId) {
@@ -79,6 +81,7 @@ class TopLevelComment extends React.Component {
datetimeCreated,
highlightedCommentId,
id,
+ moreRepliesToLoad,
onDelete,
onReport,
onRestore,
@@ -143,17 +146,13 @@ class TopLevelComment extends React.Component {
))}
}
- {!this.state.expanded && replies.length > 3 &&
+ {((!this.state.expanded && replies.length > 3) ||
+ (this.state.expanded && moreRepliesToLoad)) &&
-
+
}
@@ -178,8 +177,10 @@ TopLevelComment.propTypes = {
deletable: PropTypes.bool,
highlightedCommentId: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
id: PropTypes.number,
+ moreRepliesToLoad: PropTypes.bool,
onAddComment: PropTypes.func,
onDelete: PropTypes.func,
+ onLoadMoreReplies: PropTypes.func,
onReport: PropTypes.func,
onRestore: PropTypes.func,
parentId: PropTypes.number,
@@ -189,7 +190,8 @@ TopLevelComment.propTypes = {
};
TopLevelComment.defaultProps = {
- defaultExpanded: false
+ defaultExpanded: false,
+ moreRepliesToLoad: false
};
module.exports = TopLevelComment;
diff --git a/src/views/preview/presentation.jsx b/src/views/preview/presentation.jsx
index fdccd6c16..183099663 100644
--- a/src/views/preview/presentation.jsx
+++ b/src/views/preview/presentation.jsx
@@ -88,6 +88,7 @@ const PreviewPresentation = ({
onFavoriteClicked,
onGreenFlag,
onLoadMore,
+ onLoadMoreReplies,
onLoveClicked,
onOpenAdminPanel,
onRemix,
@@ -550,12 +551,14 @@ const PreviewPresentation = ({
highlightedCommentId={singleCommentId}
id={comment.id}
key={comment.id}
+ moreRepliesToLoad={comment.moreRepliesToLoad}
parentId={comment.parent_id}
projectId={projectId}
replies={replies && replies[comment.id] ? replies[comment.id] : []}
visibility={comment.visibility}
onAddComment={onAddComment}
onDelete={onDeleteComment}
+ onLoadMoreReplies={onLoadMoreReplies}
onReport={onReportComment}
onRestore={onRestoreComment}
/>
@@ -644,6 +647,7 @@ PreviewPresentation.propTypes = {
onFavoriteClicked: PropTypes.func,
onGreenFlag: PropTypes.func,
onLoadMore: PropTypes.func,
+ onLoadMoreReplies: PropTypes.func,
onLoveClicked: PropTypes.func,
onOpenAdminPanel: PropTypes.func,
onRemix: PropTypes.func,
diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx
index c6ed64a96..70cdb3cdf 100644
--- a/src/views/preview/project-view.jsx
+++ b/src/views/preview/project-view.jsx
@@ -60,6 +60,7 @@ class Preview extends React.Component {
'handleToggleStudio',
'handleFavoriteToggle',
'handleLoadMore',
+ 'handleLoadMoreReplies',
'handleLoveToggle',
'handleMessage',
'handlePopState',
@@ -440,6 +441,11 @@ class Preview extends React.Component {
this.props.getTopLevelComments(this.state.projectId, this.props.comments.length,
this.props.isAdmin, this.props.user && this.props.user.token);
}
+ handleLoadMoreReplies (commentId, offset) {
+ this.props.getMoreReplies(this.state.projectId, commentId, offset,
+ this.props.isAdmin, this.props.user && this.props.user.token
+ );
+ }
handleLoveToggle () {
if (!this.props.lovedLoaded) return;
@@ -644,6 +650,7 @@ class Preview extends React.Component {
onFavoriteClicked={this.handleFavoriteToggle}
onGreenFlag={this.handleGreenFlag}
onLoadMore={this.handleLoadMore}
+ onLoadMoreReplies={this.handleLoadMoreReplies}
onLoveClicked={this.handleLoveToggle}
onOpenAdminPanel={this.handleOpenAdminPanel}
onRemix={this.handleRemix}
@@ -736,6 +743,7 @@ Preview.propTypes = {
getCuratedStudios: PropTypes.func.isRequired,
getFavedStatus: PropTypes.func.isRequired,
getLovedStatus: PropTypes.func.isRequired,
+ getMoreReplies: PropTypes.func.isRequired,
getOriginalInfo: PropTypes.func.isRequired,
getParentInfo: PropTypes.func.isRequired,
getProjectInfo: PropTypes.func.isRequired,
@@ -948,6 +956,9 @@ const mapDispatchToProps = dispatch => ({
getCommentById: (projectId, commentId, isAdmin, token) => {
dispatch(previewActions.getCommentById(projectId, commentId, isAdmin, token));
},
+ getMoreReplies: (projectId, commentId, offset, isAdmin, token) => {
+ dispatch(previewActions.getReplies(projectId, [commentId], offset, isAdmin, token));
+ },
getFavedStatus: (id, username, token) => {
dispatch(previewActions.getFavedStatus(id, username, token));
},
From ccbaa60e59aafb7a429a1380a258cf2e5a51235e Mon Sep 17 00:00:00 2001
From: chrisgarrity
Date: Thu, 10 Jan 2019 10:50:37 -0500
Subject: [PATCH 3/9] =?UTF-8?q?Don=E2=80=99t=20allow=20remixing=20if=20the?=
=?UTF-8?q?=20project=20is=20not=20loaded?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Depends on https://github.com/LLK/scratch-gui/pull/4312
Adds new `isProjectLoaded` state to the project view, and disables the remix button until the project is loaded. Passes new callback to gui to be notified when the project is loaded.
---
src/views/preview/presentation.jsx | 10 ++++++++--
src/views/preview/preview.scss | 4 +++-
src/views/preview/project-view.jsx | 10 ++++++++++
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/views/preview/presentation.jsx b/src/views/preview/presentation.jsx
index fdccd6c16..45cc94a59 100644
--- a/src/views/preview/presentation.jsx
+++ b/src/views/preview/presentation.jsx
@@ -70,6 +70,7 @@ const PreviewPresentation = ({
isFullScreen,
isLoggedIn,
isNewScratcher,
+ isProjectLoaded,
isRemixing,
isScratcher,
isShared,
@@ -90,6 +91,7 @@ const PreviewPresentation = ({
onLoadMore,
onLoveClicked,
onOpenAdminPanel,
+ onProjectLoaded,
onRemix,
onRemixing,
onReportClicked,
@@ -250,10 +252,11 @@ const PreviewPresentation = ({
className={classNames([
'remix-button',
{
- remixing: isRemixing,
- spin: isRemixing
+ disabled: isRemixing || !isProjectLoaded,
+ remixing: isRemixing
}
])}
+ disabled={isRemixing || !isProjectLoaded}
title={intl.formatMessage({id: 'project.remixButton.altText'})}
onClick={onRemix}
>
@@ -301,6 +304,7 @@ const PreviewPresentation = ({
projectHost={projectHost}
projectId={projectId}
onGreenFlag={onGreenFlag}
+ onProjectLoaded={onProjectLoaded}
onRemixing={onRemixing}
onUpdateProjectId={onUpdateProjectId}
onUpdateProjectThumbnail={onUpdateProjectThumbnail}
@@ -623,6 +627,7 @@ PreviewPresentation.propTypes = {
isFullScreen: PropTypes.bool,
isLoggedIn: PropTypes.bool,
isNewScratcher: PropTypes.bool,
+ isProjectLoaded: PropTypes.bool,
isRemixing: PropTypes.bool,
isScratcher: PropTypes.bool,
isShared: PropTypes.bool,
@@ -646,6 +651,7 @@ PreviewPresentation.propTypes = {
onLoadMore: PropTypes.func,
onLoveClicked: PropTypes.func,
onOpenAdminPanel: PropTypes.func,
+ onProjectLoaded: PropTypes.func,
onRemix: PropTypes.func,
onRemixing: PropTypes.func,
onReportClicked: PropTypes.func.isRequired,
diff --git a/src/views/preview/preview.scss b/src/views/preview/preview.scss
index 9a6fce550..7a108a33a 100644
--- a/src/views/preview/preview.scss
+++ b/src/views/preview/preview.scss
@@ -283,9 +283,11 @@ $stage-width: 480px;
background-image: url("/svgs/project/remix-white.svg");
}
}
+ .remix-button.disabled {
+ opacity: .6;
+ }
.remix-button.remixing {
- opacity: .6;
&:before {
animation-name: remix-intro, remix-spin;
diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx
index c6ed64a96..f7270d80b 100644
--- a/src/views/preview/project-view.jsx
+++ b/src/views/preview/project-view.jsx
@@ -74,6 +74,7 @@ class Preview extends React.Component {
'handleAddToStudioClick',
'handleAddToStudioClose',
'handleGreenFlag',
+ 'handleProjectLoaded',
'handleRemix',
'handleSeeAllComments',
'handleSeeInside',
@@ -108,6 +109,7 @@ class Preview extends React.Component {
clientLoved: false,
extensions: [],
favoriteCount: 0,
+ isProjectLoaded: false,
isRemixing: false,
invalidProject: parts.length === 1,
justRemixed: false,
@@ -382,6 +384,11 @@ class Preview extends React.Component {
this.props.setFullScreen(fullScreen);
}
}
+ handleProjectLoaded () {
+ // Currently project view only needs to know when the project becomes loaded. It
+ // does not currently handle (or need to handle) the case where a project becomes unloaded.
+ this.setState({isProjectLoaded: true});
+ }
pushHistory (push) {
// update URI to match mode
const idPath = this.state.projectId ? `${this.state.projectId}/` : '';
@@ -611,6 +618,7 @@ class Preview extends React.Component {
isFullScreen={this.state.isFullScreen}
isLoggedIn={this.props.isLoggedIn}
isNewScratcher={this.props.isNewScratcher}
+ isProjectLoaded={this.state.isProjectLoaded}
isRemixing={this.state.isRemixing}
isScratcher={this.props.isScratcher}
isShared={this.props.isShared}
@@ -646,6 +654,7 @@ class Preview extends React.Component {
onLoadMore={this.handleLoadMore}
onLoveClicked={this.handleLoveToggle}
onOpenAdminPanel={this.handleOpenAdminPanel}
+ onProjectLoaded={this.handleProjectLoaded}
onRemix={this.handleRemix}
onRemixing={this.handleIsRemixing}
onReportClicked={this.handleReportClick}
@@ -691,6 +700,7 @@ class Preview extends React.Component {
onGreenFlag={this.handleGreenFlag}
onLogOut={this.props.handleLogOut}
onOpenRegistration={this.props.handleOpenRegistration}
+ onProjectLoaded={this.handleProjectLoaded}
onRemixing={this.handleIsRemixing}
onSetLanguage={this.handleSetLanguage}
onShare={this.handleShare}
From 1277ca48767e62b49e056ba2320808b69fce9081 Mon Sep 17 00:00:00 2001
From: Paul Kaplan
Date: Thu, 10 Jan 2019 10:58:34 -0500
Subject: [PATCH 4/9] Make "See more replies" only the width of the replies
column
---
src/views/preview/comment/comment.scss | 28 +++++++++----------
.../preview/comment/top-level-comment.jsx | 18 ++++++------
2 files changed, 22 insertions(+), 24 deletions(-)
diff --git a/src/views/preview/comment/comment.scss b/src/views/preview/comment/comment.scss
index 98e55ef6c..cff4c131b 100644
--- a/src/views/preview/comment/comment.scss
+++ b/src/views/preview/comment/comment.scss
@@ -235,22 +235,20 @@
.replies {
width: calc(100% - 4rem);
+}
- &.collapsed .comment {
- &:last-child {
- &:after {
- position: absolute;
- bottom: 0;
- background: linear-gradient(
- $ui-light-primary-transparent,
- $ui-light-primary
- );
- width: 100%;
- height: 100%;
- content: "";
- pointer-events: none;
- }
- }
+.replies.collapsed > .comment:last-of-type {
+ &:after {
+ position: absolute;
+ bottom: 0;
+ background: linear-gradient(
+ $ui-light-primary-transparent,
+ $ui-light-primary
+ );
+ width: 100%;
+ height: 100%;
+ content: "";
+ pointer-events: none;
}
}
diff --git a/src/views/preview/comment/top-level-comment.jsx b/src/views/preview/comment/top-level-comment.jsx
index 86b20b9ac..ecc15208e 100644
--- a/src/views/preview/comment/top-level-comment.jsx
+++ b/src/views/preview/comment/top-level-comment.jsx
@@ -144,17 +144,17 @@ class TopLevelComment extends React.Component {
onRestore={this.handleRestoreReply}
/>
))}
+ {((!this.state.expanded && replies.length > 3) ||
+ (this.state.expanded && moreRepliesToLoad)) &&
+
+
+
+ }
}
- {((!this.state.expanded && replies.length > 3) ||
- (this.state.expanded && moreRepliesToLoad)) &&
-
-
-
- }
);
}
From e2c743445f4a4f3893f5c44a81b25eacf396feed Mon Sep 17 00:00:00 2001
From: Paul Kaplan
Date: Thu, 10 Jan 2019 10:59:35 -0500
Subject: [PATCH 5/9] Add unit test for setReplies action in preview reducer
---
test/unit/redux/preview-test.js | 34 +++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/test/unit/redux/preview-test.js b/test/unit/redux/preview-test.js
index 46c6f7d87..0c75c27ff 100644
--- a/test/unit/redux/preview-test.js
+++ b/test/unit/redux/preview-test.js
@@ -128,3 +128,37 @@ tap.test('addNewComment, reply comment', t => {
t.equal(state.replies.id1[2].id, 'new comment');
t.end();
});
+
+tap.test('setReplies', t => {
+ // setReplies should append new replies
+ state = reducer(commentState, Preview.setReplies({
+ id1: {id: 'id6'}
+ }));
+ t.equal(state.replies.id1[2].id, 'id6');
+ t.equal(state.comments[0].moreRepliesToLoad, false);
+
+ // setReplies can add replies to a comment that didn't have any
+ state = reducer(state, Preview.setReplies({
+ id2: {id: 'id7'}
+ }));
+ t.equal(state.replies.id1.length, 3);
+ t.equal(state.replies.id2.length, 1);
+ t.equal(state.replies.id2[0].id, 'id7');
+ t.equal(state.comments[0].moreRepliesToLoad, false);
+ t.equal(state.comments[1].moreRepliesToLoad, false);
+
+ // Getting 20 (COMMENT_LIMIT) replies sets moreRepliesToLoad to true
+ state = reducer(state, Preview.setReplies({
+ id3: (new Array(20)).map((_, i) => ({id: `id${i + 1}`}))
+ }));
+ t.equal(state.comments[0].moreRepliesToLoad, false);
+ t.equal(state.comments[1].moreRepliesToLoad, false);
+ t.equal(state.comments[2].moreRepliesToLoad, true);
+
+ // Getting one more reply sets moreRepliesToLoad back to false
+ state = reducer(state, Preview.setReplies({
+ id3: {id: 'id21'}
+ }));
+ t.equal(state.comments[2].moreRepliesToLoad, false);
+ t.end();
+});
From 16391f25ee3236448ac09a5ee647b364c21b4e25 Mon Sep 17 00:00:00 2001
From: Paul Kaplan
Date: Thu, 10 Jan 2019 13:49:07 -0500
Subject: [PATCH 6/9] Strip out duplicates from replies and comments.
Fixes https://github.com/LLK/scratch-www/issues/2575
---
package.json | 1 +
src/redux/preview.js | 5 +++--
test/unit/redux/preview-test.js | 18 +++++++++++++++---
3 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/package.json b/package.json
index c5135a36e..91eef6fa8 100644
--- a/package.json
+++ b/package.json
@@ -81,6 +81,7 @@
"lodash.mergewith": "4.6.1",
"lodash.omit": "3.1.0",
"lodash.range": "3.0.1",
+ "lodash.uniqby": "4.7.0",
"minilog": "2.0.8",
"node-dir": "0.1.16",
"node-sass": "4.6.1",
diff --git a/src/redux/preview.js b/src/redux/preview.js
index 18afb9b59..12a06ba7b 100644
--- a/src/redux/preview.js
+++ b/src/redux/preview.js
@@ -2,6 +2,7 @@ const defaults = require('lodash.defaults');
const keyMirror = require('keymirror');
const async = require('async');
const mergeWith = require('lodash.mergewith');
+const uniqBy = require('lodash.uniqby');
const api = require('../lib/api');
const log = require('../lib/log');
@@ -102,7 +103,7 @@ module.exports.previewReducer = (state, action) => {
});
case 'SET_COMMENTS':
return Object.assign({}, state, {
- comments: [...state.comments, ...action.items] // TODO: consider a different way of doing this?
+ comments: uniqBy(state.comments.concat(action.items), 'id')
});
case 'UPDATE_COMMENT':
if (action.topLevelCommentId) {
@@ -153,7 +154,7 @@ module.exports.previewReducer = (state, action) => {
return Object.assign({}, state, {
// Append new replies to the state.replies structure
replies: mergeWith({}, state.replies, action.replies, (replies, newReplies) => (
- (replies || []).concat(newReplies || [])
+ uniqBy((replies || []).concat(newReplies || []), 'id')
)),
// Also set the `moreRepliesToLoad` property on the top-level comments
comments: state.comments.map(comment => {
diff --git a/test/unit/redux/preview-test.js b/test/unit/redux/preview-test.js
index 0c75c27ff..24a91ce84 100644
--- a/test/unit/redux/preview-test.js
+++ b/test/unit/redux/preview-test.js
@@ -59,9 +59,9 @@ tap.test('setComments', t => {
// Initial value
t.deepEqual(initialState.comments, []);
- state = reducer(initialState, Preview.setComments([1, 2]));
- state = reducer(state, Preview.setComments([3, 4]));
- t.deepEqual(state.comments, [1, 2, 3, 4]);
+ state = reducer(initialState, Preview.setComments([{id: 1}, {id: 2}]));
+ state = reducer(state, Preview.setComments([{id: 3}, {id: 4}]));
+ t.deepEqual(state.comments, [{id: 1}, {id: 2}, {id: 3}, {id: 4}]);
t.end();
});
@@ -80,6 +80,13 @@ const commentState = {
}
};
+tap.test('setComments, discards duplicates', t => {
+ state = reducer(commentState, Preview.setComments([{id: 'id1'}]));
+ // Does not increase the number of comments, still 3
+ t.equal(state.comments.length, 3);
+ t.end();
+});
+
tap.test('setCommentDeleted, top level comment', t => {
state = reducer(commentState, Preview.setCommentDeleted('id2'));
t.equal(state.comments[1].visibility, 'deleted');
@@ -137,6 +144,11 @@ tap.test('setReplies', t => {
t.equal(state.replies.id1[2].id, 'id6');
t.equal(state.comments[0].moreRepliesToLoad, false);
+ // setReplies should ignore duplicates, do the same as above again
+ t.equal(state.replies.id1.length, 3);
+ state = reducer(state, Preview.setReplies({id1: {id: 'id6'}}));
+ t.equal(state.replies.id1.length, 3);
+
// setReplies can add replies to a comment that didn't have any
state = reducer(state, Preview.setReplies({
id2: {id: 'id7'}
From e9899a7acb1245c7b5d86ce4ce4c4e49478f5e03 Mon Sep 17 00:00:00 2001
From: chrisgarrity
Date: Thu, 10 Jan 2019 14:38:36 -0500
Subject: [PATCH 7/9] =?UTF-8?q?Bump=20gui=20version=E2=80=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
so that https://github.com/LLK/scratch-www/pull/2656 can land (disable remixing until project loaded)
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index edd610a5b..3f2d9fa13 100644
--- a/package.json
+++ b/package.json
@@ -100,7 +100,7 @@
"redux": "3.5.2",
"redux-thunk": "2.0.1",
"sass-loader": "6.0.6",
- "scratch-gui": "0.1.0-prerelease.20190109203727",
+ "scratch-gui": "0.1.0-prerelease.20190102131553",
"scratch-l10n": "latest",
"scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master",
"slick-carousel": "1.6.0",
From 2018f8534a954f58f2fe068e41265f26567dd2a8 Mon Sep 17 00:00:00 2001
From: Christopher Willis-Ford
Date: Thu, 10 Jan 2019 15:19:51 -0800
Subject: [PATCH 8/9] Update Scratch Desktop download links to v1.2.1
---
src/views/download/download.jsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/views/download/download.jsx b/src/views/download/download.jsx
index 2ad476009..873708a1a 100644
--- a/src/views/download/download.jsx
+++ b/src/views/download/download.jsx
@@ -114,8 +114,8 @@ class Download extends React.Component {
className="download-button"
href={
this.state.OS === OS_ENUM.WINDOWS ?
- 'https://downloads.scratch.mit.edu/desktop/Scratch%20Desktop%20Setup%201.2.0.exe' :
- 'https://downloads.scratch.mit.edu/desktop/Scratch%20Desktop-1.2.0.dmg'
+ 'https://downloads.scratch.mit.edu/desktop/Scratch%20Desktop%20Setup%201.2.1.exe' :
+ 'https://downloads.scratch.mit.edu/desktop/Scratch%20Desktop-1.2.1.dmg'
}
>
From 40e26ab636214af35e0b7753cac12ac33cb01733 Mon Sep 17 00:00:00 2001
From: Ben Wheeler
Date: Fri, 11 Jan 2019 09:29:00 -0500
Subject: [PATCH 9/9] bump gui version so that scratch-gui #4319
bump gui version so that scratch-gui #4319 can land (resolve name conflict in project-fetcher-hoc)
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index c3852b435..05b9a0a86 100644
--- a/package.json
+++ b/package.json
@@ -102,7 +102,7 @@
"redux": "3.5.2",
"redux-thunk": "2.0.1",
"sass-loader": "6.0.6",
- "scratch-gui": "0.1.0-prerelease.20190102131553",
+ "scratch-gui": "0.1.0-prerelease.20190111141703",
"scratch-l10n": "latest",
"scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master",
"slick-carousel": "1.6.0",