Merge branch 'master' into update-readme

This commit is contained in:
Wyatt Johnson
2017-08-15 14:54:29 -06:00
committed by GitHub
43 changed files with 609 additions and 481 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ export const fetchAssets = (skip = '', limit = '', search = '', sort = '', filte
// Update an asset state
// Get comments to fill each of the three lists on the mod queue
export const updateAssetState = (id, closedAt) => (dispatch) => {
dispatch({type: UPDATE_ASSET_STATE_REQUEST});
dispatch({type: UPDATE_ASSET_STATE_REQUEST, id, closedAt});
return coralApi(`/assets/${id}/status`, {method: 'PUT', body: {closedAt}})
.then(() => dispatch({type: UPDATE_ASSET_STATE_SUCCESS}))
.catch((error) => {
+3 -3
View File
@@ -93,21 +93,21 @@ const validation = (formData, dispatch, next) => {
};
export const submitSettings = () => (dispatch, getState) => {
const settingsFormData = getState().install.toJS().data.settings;
const settingsFormData = getState().install.data.settings;
validation(settingsFormData, dispatch, function() {
dispatch(nextStep());
});
};
export const submitUser = () => (dispatch, getState) => {
const userFormData = getState().install.toJS().data.user;
const userFormData = getState().install.data.user;
validation(userFormData, dispatch, function() {
dispatch(nextStep());
});
};
export const finishInstall = () => (dispatch, getState) => {
const data = getState().install.toJS().data;
const data = getState().install.data;
dispatch(installRequest());
return coralApi('/setup', {method: 'POST', body: data})
.then(() => {
+1 -1
View File
@@ -42,7 +42,7 @@ export const updateDomainlist = (listName, list) => {
};
export const saveSettingsToServer = () => (dispatch, getState) => {
let settings = getState().settings.toJS();
let settings = getState().settings;
if (settings.charCount) {
settings.charCount = parseInt(settings.charCount);
}
+2 -4
View File
@@ -74,10 +74,8 @@ class LayoutContainer extends Component {
}
const mapStateToProps = (state) => ({
auth: state.auth.toJS(),
TALK_RECAPTCHA_PUBLIC: state.config
.get('data')
.get('TALK_RECAPTCHA_PUBLIC', null)
auth: state.auth,
TALK_RECAPTCHA_PUBLIC: state.config.data.TALK_RECAPTCHA_PUBLIC,
});
const mapDispatchToProps = (dispatch) => ({
@@ -169,8 +169,8 @@ const mapStateToProps = (state) => ({
selectedCommentIds: state.userDetail.selectedCommentIds,
statuses: state.userDetail.statuses,
activeTab: state.userDetail.activeTab,
bannedWords: state.settings.toJS().wordlist.banned,
suspectWords: state.settings.toJS().wordlist.suspect,
bannedWords: state.settings.wordlist.banned,
suspectWords: state.settings.wordlist.suspect,
});
const mapDispatchToProps = (dispatch) => ({
+28 -23
View File
@@ -1,35 +1,40 @@
import {Map, List, fromJS} from 'immutable';
import * as actions from '../constants/assets';
import update from 'immutability-helper';
const initialState = Map({
byId: Map(),
ids: List(),
assets: List()
});
const initialState = {
byId: {},
ids: [],
assets: []
};
export default function assets (state = initialState, action) {
switch (action.type) {
case actions.FETCH_ASSETS_SUCCESS:
return replaceAssets(action, state);
case actions.FETCH_ASSETS_SUCCESS: {
const assets = action.assets.reduce((prev, curr) => {
prev[curr.id] = curr;
return prev;
}, {});
return update(state, {
byId: {$set: assets},
count: {$set: action.count},
ids: {$set: Object.keys(assets)},
});
}
case actions.UPDATE_ASSET_STATE_REQUEST:
return state
.setIn(['byId', action.id, 'closedAt'], action.closedAt);
return update(state, {
byId: {
[action.id]: {
closedAt: {$set: action.closedAt},
},
},
});
case actions.UPDATE_ASSETS:
return state
.set('assets', List(action.assets));
return update(state, {
assets: {$set: action.assets},
});
default:
return state;
}
}
const replaceAssets = (action, state) => {
const assets = fromJS(action.assets.reduce((prev, curr) => {
prev[curr.id] = curr;
return prev;
}, {}));
return state
.set('byId', assets)
.set('count', action.count)
.set('ids', List(assets.keys()));
};
+40 -20
View File
@@ -1,43 +1,63 @@
import {Map} from 'immutable';
import * as actions from '../constants/auth';
const initialState = Map({
const initialState = {
loggedIn: false,
user: null,
loginError: null,
loginMaxExceeded: false,
passwordRequestSuccess: null
});
};
export default function auth (state = initialState, action) {
switch (action.type) {
case actions.CHECK_LOGIN_REQUEST:
return state
.set('loadingUser', true);
return {
...state,
loadingUser: true,
};
case actions.CHECK_LOGIN_FAILURE:
return state
.set('loggedIn', false)
.set('loadingUser', false)
.set('user', null);
return {
...state,
loggedIn: false,
loadingUser: false,
user: null,
};
case actions.CHECK_LOGIN_SUCCESS:
return state
.set('loggedIn', true)
.set('loadingUser', false)
.set('user', action.user);
return {
...state,
loggedIn: true,
loadingUser: false,
user: action.user,
};
case actions.LOGOUT:
return initialState;
case actions.LOGIN_SUCCESS:
return state.set('loginMaxExceeded', false).set('loginError', null);
return {
...state,
loginMaxExceeded: false,
loginError: null,
};
case actions.LOGIN_FAILURE:
return state.set('loginError', action.message);
return {
...state,
loginError: action.message,
};
case actions.FETCH_FORGOT_PASSWORD_REQUEST:
return state.set('passwordRequestSuccess', null);
return {
...state,
passwordRequestSuccess: null,
};
case actions.FETCH_FORGOT_PASSWORD_SUCCESS:
return state.set('passwordRequestSuccess', 'If you have a registered account, a password reset link was sent to that email.');
return {
...state,
passwordRequestSuccess: 'If you have a registered account, a password reset link was sent to that email.',
};
case actions.LOGIN_MAXIMUM_EXCEEDED:
return state
.set('loginMaxExceeded', true)
.set('loginError', action.message);
return {
...state,
loginMaxExceeded: true,
loginError: action.message,
};
default :
return state;
}
+57 -44
View File
@@ -1,5 +1,3 @@
import {Map} from 'immutable';
import {
FETCH_COMMENTERS_REQUEST,
FETCH_COMMENTERS_FAILURE,
@@ -13,8 +11,8 @@ import {
HIDE_REJECT_USERNAME_DIALOG
} from '../constants/community';
const initialState = Map({
community: Map(),
const initialState = {
community: {},
isFetchingPeople: false,
errorPeople: '',
accounts: [],
@@ -22,72 +20,87 @@ const initialState = Map({
ascPeople: false,
totalPagesPeople: 0,
pagePeople: 0,
user: Map({}),
user: {},
banDialog: false,
rejectUsernameDialog: false
});
};
export default function community (state = initialState, action) {
switch (action.type) {
case FETCH_COMMENTERS_REQUEST :
return state
.set('isFetchingPeople', true);
return {
...state,
isFetchingPeople: true,
};
case FETCH_COMMENTERS_FAILURE :
return state
.set('isFetchingPeople', false)
.set('errorPeople', action.error);
return {
...state,
isFetchingPeople: false,
errorPeople: action.error,
};
case FETCH_COMMENTERS_SUCCESS : {
const {accounts, type, page, count, limit, totalPages, ...rest} = action; // eslint-disable-line
return state
.merge({
isFetchingPeople: false,
errorPeople: '',
pagePeople: page,
countPeople: count,
limitPeople: limit,
totalPagesPeople: totalPages,
...rest
})
.set('accounts', accounts); // Sets to normal array
return {
...state,
isFetchingPeople: false,
errorPeople: '',
pagePeople: page,
countPeople: count,
limitPeople: limit,
totalPagesPeople: totalPages,
...rest,
accounts, // Sets to normal array
};
}
case SET_ROLE : {
const commenters = state.get('accounts');
const commenters = state.accounts;
const idx = commenters.findIndex((el) => el.id === action.id);
commenters[idx].roles[0] = action.role;
return state.set('accounts', commenters.map((id) => id));
return {
...state,
accounts: commenters.map((id) => id),
};
}
case SET_COMMENTER_STATUS: {
const commenters = state.get('accounts');
const commenters = state.accounts;
const idx = commenters.findIndex((el) => el.id === action.id);
commenters[idx].status = action.status;
return state.set('accounts', commenters.map((id) => id));
return {
...state,
accounts: commenters.map((id) => id),
};
}
case SORT_UPDATE :
return state
.set('fieldPeople', action.sort.field)
.set('ascPeople', !state.get('ascPeople'));
return {
...state,
fieldPeople: action.sort.field,
ascPeople: !state.ascPeople,
};
case HIDE_BANUSER_DIALOG:
return state
.set('banDialog', false);
return {
...state,
banDialog: false,
};
case SHOW_BANUSER_DIALOG:
return state
.merge({
user: Map(action.user),
banDialog: true
});
return {
...state,
user: action.user,
banDialog: true,
};
case HIDE_REJECT_USERNAME_DIALOG:
return state
.set('rejectUsernameDialog', false);
return {
...state,
rejectUsernameDialog: false,
};
case SHOW_REJECT_USERNAME_DIALOG:
return state
.merge({
user: Map(action.user),
rejectUsernameDialog: true
});
return {
...state,
user: action.user,
rejectUsernameDialog: true
};
default :
return state;
}
+7 -6
View File
@@ -1,15 +1,16 @@
import {Map} from 'immutable';
import * as actions from '../actions/config';
const initialState = Map({
data: Map({})
});
const initialState = {
data: {}
};
export default function config (state = initialState, action) {
switch (action.type) {
case actions.CONFIG_UPDATED:
return state.set('data', Map(action.data));
return {
...state,
data: action.data,
};
default:
return state;
}
+82 -49
View File
@@ -1,30 +1,29 @@
import {Map, List} from 'immutable';
import * as actions from '../constants/install';
import update from 'immutability-helper';
const initialState = Map({
const initialState = {
isLoading: false,
data: Map({
settings: Map({
data: {
settings: {
organizationName: '',
domains: Map({
whitelist: List()
})
}),
user: Map({
domains: {
whitelist: [],
}
},
user: {
username: '',
email: '',
password: '',
confirmPassword: ''
})
}),
errors: Map({
}
},
errors: {
organizationName: '',
username: '',
email: '',
password: '',
confirmPassword: ''
}),
},
showErrors: false,
hasError: false,
error: null,
@@ -44,57 +43,91 @@ const initialState = Map({
installRequest: null,
installRequestError: null,
alreadyInstalled: false
});
};
export default function install (state = initialState, action) {
switch (action.type) {
case actions.NEXT_STEP:
return state
.set('step', state.get('step') + 1);
return {
...state,
step: state.step + 1,
};
case actions.PREVIOUS_STEP:
return state
.set('step', state.get('step') - 1);
return {
...state,
step: state.step - 1,
};
case actions.GO_TO_STEP:
return state
.set('step', action.step);
return {
...state,
step: action.step,
};
case actions.UPDATE_PERMITTED_DOMAINS_SETTINGS:
return state
.setIn(['data', 'settings', 'domains', 'whitelist'], action.value);
return update(state, {
data: {
settings: {
domains: {
whitelist: {$set: action.value},
},
},
},
});
case actions.UPDATE_FORMDATA_SETTINGS:
return state
.setIn(['data', 'settings', action.name], action.value);
return update(state, {
data: {
settings: {
[action.name]: {$set: action.value},
},
},
});
case actions.UPDATE_FORMDATA_USER:
return state
.setIn(['data', 'user', action.name], action.value);
return update(state, {
data: {
user: {
[action.name]: {$set: action.value},
},
},
});
case actions.HAS_ERROR:
return state
.merge({
hasError: true,
showErrors: true
});
return {
...state,
hasError: true,
showErrors: true,
};
case actions.ADD_ERROR:
return state
.setIn(['errors', action.name], action.error);
return update(state, {
errors: {
[action.name]: {$set: action.error},
},
});
case actions.CLEAR_ERRORS:
return state
.set('errors', Map());
return {
...state,
errors: {},
};
case actions.INSTALL_REQUEST:
return state
.set('isLoading', true);
return {
...state,
isLoading: true,
};
case actions.INSTALL_SUCCESS:
return state
.set('isLoading', false)
.set('installRequest', 'SUCCESS');
return {
...state,
isLoading: false,
installRequest: 'SUCCESS',
};
case actions.INSTALL_FAILURE:
return state
.merge({
isLoading: false,
installRequest: 'FAILURE',
installRequestError: action.error
});
return {
...state,
isLoading: false,
installRequest: 'FAILURE',
installRequestError: action.error
};
case actions.CHECK_INSTALL_SUCCESS:
return state
.set('alreadyInstalled', action.installed);
return {
...state,
alreadyInstalled: action.installed,
};
default :
return state;
}
+31 -14
View File
@@ -1,37 +1,54 @@
import {fromJS} from 'immutable';
import * as actions from '../constants/moderation';
const initialState = fromJS({
const initialState = {
singleView: false,
modalOpen: false,
storySearchVisible: false,
storySearchString: '',
shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show',
sortOrder: 'REVERSE_CHRONOLOGICAL',
});
};
export default function moderation (state = initialState, action) {
switch (action.type) {
case actions.MODERATION_CLEAR_STATE:
return initialState;
case actions.TOGGLE_MODAL:
return state
.set('modalOpen', action.open);
return {
...state,
modalOpen: action.open,
};
case actions.SINGLE_VIEW:
return state
.set('singleView', !state.get('singleView'));
return {
...state,
singleView: !state.singleView,
};
case actions.HIDE_SHORTCUTS_NOTE:
return state
.set('shortcutsNoteVisible', 'hide');
return {
...state,
shortcutsNoteVisible: 'hide',
};
case actions.SHOW_STORY_SEARCH:
return state.set('storySearchVisible', true);
return {
...state,
storySearchVisible: true,
};
case actions.HIDE_STORY_SEARCH:
return state.set('storySearchVisible', false);
return {
...state,
storySearchVisible: false,
};
case actions.STORY_SEARCH_CHANGE_VALUE:
return state.set('storySearchString', action.value);
return {
...state,
storySearchString: action.value,
};
case actions.SET_SORT_ORDER:
return state.set('sortOrder', action.order);
default :
return {
...state,
sortOrder: action.order,
};
default:
return state;
}
}
+49 -32
View File
@@ -1,5 +1,5 @@
import {Map, List} from 'immutable';
import * as actions from '../actions/settings';
import update from 'immutability-helper';
// this is initialized here because
// currently you have to reload the dashboard to get new stats
@@ -10,63 +10,80 @@ const DASHBOARD_WINDOW_MINUTES = 5;
let then = new Date();
then.setMinutes(then.getMinutes() - DASHBOARD_WINDOW_MINUTES);
const initialState = Map({
wordlist: Map({
banned: List(),
suspect: List()
}),
const initialState = {
wordlist: {
banned: [],
suspect: []
},
dashboardWindowStart: then.toISOString(),
dashboardWindowEnd: new Date().toISOString(),
domains: Map({
whitelist: List()
}),
domains: {
whitelist: []
},
saveSettingsError: null,
fetchSettingsError: null,
fetchingSettings: false
});
};
export default function settings (state = initialState, action) {
switch (action.type) {
case actions.SETTINGS_LOADING:
return state
.set('fetchingSettings', true)
.set('fetchSettingsError', null);
return {
...state,
fetchingSettings: true,
fetchSettingsError: null,
};
case actions.SETTINGS_RECEIVED:
return state.merge({
return {
...state,
fetchingSettings: false,
fetchSettingsError: null,
...action.settings
});
};
case actions.SETTINGS_FETCH_ERROR:
return state
.set('fetchingSettings', false)
.set('fetchSettingsError', action.error);
return {
...state,
fetchingSettings: false,
fetchSettingsError: action.error,
};
case actions.SETTINGS_UPDATED:
return state.merge({
return {
...state,
fetchingSettings: false,
fetchSettingsError: null,
...action.settings
});
};
case actions.SAVE_SETTINGS_LOADING:
return state
.set('fetchingSettings', true)
.set('saveSettingsError', null);
return {
...state,
fetchingSettings: true,
saveSettingsError: null,
};
case actions.SAVE_SETTINGS_SUCCESS:
return state.merge({
return {
...state,
fetchingSettings: false,
fetchSettingsError: null,
...action.settings
});
};
case actions.SAVE_SETTINGS_FAILED:
return state
.set('fetchingSettings', false)
.set('fetchSettingsError', action.error);
return {
...state,
fetchingSettings: false,
fetchSettingsError: action.error,
};
case actions.WORDLIST_UPDATED:
return state
.setIn(['wordlist', action.listName], action.list);
return update(state, {
wordList: {
[action.listName]: {$set: action.list},
}
});
case actions.DOMAINLIST_UPDATED:
return state
.setIn(['domains', action.listName], action.list);
return update(state, {
domains: {
[action.listName]: {$set: action.list},
}
});
default:
return state;
}
@@ -87,8 +87,8 @@ export const withCommunityQuery = withQuery(gql`
});
const mapStateToProps = (state) => ({
community: state.community.toJS(),
currentUser: state.auth.toJS().user,
community: state.community,
currentUser: state.auth.user,
});
const mapDispatchToProps = (dispatch) =>
@@ -23,7 +23,7 @@ class TableContainer extends Component {
}
const mapStateToProps = (state) => ({
commenters: state.community.get('accounts'),
commenters: state.community.accounts,
});
const mapDispatchToProps = (dispatch) =>
@@ -23,8 +23,8 @@ class ConfigureContainer extends Component {
}
const mapStateToProps = (state) => ({
auth: state.auth.toJS(),
settings: state.settings.toJS()
auth: state.auth,
settings: state.settings
});
const mapDispatchToProps = (dispatch) =>
@@ -54,8 +54,8 @@ export const witDashboardQuery = withQuery(gql`
const mapStateToProps = (state) => {
return {
settings: state.settings.toJS(),
moderation: state.moderation.toJS()
settings: state.settings,
moderation: state.moderation
};
};
@@ -35,7 +35,7 @@ InstallContainer.contextTypes = {
};
const mapStateToProps = (state) => ({
install: state.install.toJS()
install: state.install
});
const mapDispatchToProps = (dispatch) =>
@@ -376,9 +376,9 @@ const withQueueCountPolling = withQuery(gql`
});
const mapStateToProps = (state) => ({
moderation: state.moderation.toJS(),
settings: state.settings.toJS(),
auth: state.auth.toJS(),
moderation: state.moderation,
settings: state.settings,
auth: state.auth,
});
const mapDispatchToProps = (dispatch) => ({
@@ -12,7 +12,7 @@ class StoriesContainer extends Component {
}
const mapStateToProps = (state) => ({
assets: state.assets.toJS()
assets: state.assets
});
const mapDispatchToProps = (dispatch) =>
@@ -119,7 +119,7 @@ class ConfigureStreamContainer extends Component {
}
const mapStateToProps = (state) => ({
asset: state.asset.toJS()
asset: state.asset
});
const mapDispatchToProps = (dispatch) => ({
@@ -170,7 +170,7 @@ export const withEmbedQuery = withQuery(EMBED_QUERY, {
});
const mapStateToProps = (state) => ({
auth: state.auth.toJS(),
auth: state.auth,
commentId: state.stream.commentId,
assetId: state.stream.assetId,
assetUrl: state.stream.assetUrl,
@@ -10,7 +10,6 @@ import {
import * as authActions from 'coral-framework/actions/auth';
import * as notificationActions from 'coral-framework/actions/notification';
import {editName} from 'coral-framework/actions/user';
import {setActiveReplyBox, setActiveTab, viewAllComments} from '../actions/stream';
import Stream from '../components/Stream';
import Comment from './Comment';
@@ -26,7 +25,7 @@ import {
} from '../graphql/utils';
import omit from 'lodash/omit';
const {showSignInDialog} = authActions;
const {showSignInDialog, editName} = authActions;
const {addNotification} = notificationActions;
class StreamContainer extends React.Component {
@@ -298,7 +297,7 @@ const fragments = {
};
const mapStateToProps = (state) => ({
auth: state.auth.toJS(),
auth: state.auth,
refetching: state.embed.refetching,
commentCountCache: state.stream.commentCountCache,
activeReplyBox: state.stream.activeReplyBox,
+10 -6
View File
@@ -147,13 +147,11 @@ const extension = {
__typename: 'Comment',
user: {
__typename: 'User',
id: auth.toJS().user.id,
username: auth.toJS().user.username
id: auth.user.id,
username: auth.user.username
},
created_at: new Date().toISOString(),
body,
parent_id,
asset_id,
action_summaries: [],
tags: tags.map((tag) => ({
tag: {
@@ -162,15 +160,21 @@ const extension = {
__typename: 'Tag'
},
assigned_by: {
id: auth.toJS().user.id,
id: auth.user.id,
__typename: 'User'
},
__typename: 'TagLink'
})),
status: 'NONE',
replyCount: 0,
asset: {
__typename: 'Asset',
id: asset_id,
title: '',
url: '',
},
parent: parent_id
? {id: parent_id}
? {__typename: 'Comment', id: parent_id}
: null,
replies: {
__typename: 'CommentConnection',
+2 -2
View File
@@ -13,7 +13,7 @@ const updateAssetSettingsSuccess = (settings) => ({type: actions.UPDATE_ASSET_SE
const updateAssetSettingsFailure = (error) => ({type: actions.UPDATE_ASSET_SETTINGS_FAILURE, error});
export const updateConfiguration = (newConfig) => (dispatch, getState) => {
const assetId = getState().asset.toJS().id;
const assetId = getState().asset.id;
dispatch(updateAssetSettingsRequest());
coralApi(`/assets/${assetId}/settings`, {method: 'PUT', body: newConfig})
.then(() => {
@@ -27,7 +27,7 @@ export const updateConfiguration = (newConfig) => (dispatch, getState) => {
};
export const updateOpenStream = (closedBody) => (dispatch, getState) => {
const assetId = getState().asset.toJS().id;
const assetId = getState().asset.id;
dispatch(fetchAssetRequest());
coralApi(`/assets/${assetId}/status`, {method: 'PUT', body: closedBody})
.then(() => {
+24 -3
View File
@@ -4,6 +4,7 @@ import * as actions from '../constants/auth';
import * as Storage from '../helpers/storage';
import coralApi, {base} from '../helpers/request';
import pym from '../services/pym';
import {addNotification} from '../actions/notification';
import {resetWebsocket} from 'coral-framework/services/client';
import t from 'coral-framework/services/i18n';
@@ -220,7 +221,7 @@ const signUpSuccess = (user) => ({type: actions.FETCH_SIGNUP_SUCCESS, user});
const signUpFailure = (error) => ({type: actions.FETCH_SIGNUP_FAILURE, error});
export const fetchSignUp = (formData) => (dispatch, getState) => {
const redirectUri = getState().auth.toJS().redirectUri;
const redirectUri = getState().auth.redirectUri;
dispatch(signUpRequest());
coralApi('/users', {
@@ -257,7 +258,7 @@ const forgotPasswordFailure = (error) => ({
export const fetchForgotPassword = (email) => (dispatch, getState) => {
dispatch(forgotPasswordRequest(email));
const redirectUri = getState().auth.toJS().redirectUri;
const redirectUri = getState().auth.redirectUri;
coralApi('/account/password/reset', {
method: 'POST',
body: {email, loc: redirectUri}
@@ -351,7 +352,7 @@ const verifyEmailFailure = () => ({
});
export const requestConfirmEmail = (email) => (dispatch, getState) => {
const redirectUri = getState().auth.toJS().redirectUri;
const redirectUri = getState().auth.redirectUri;
dispatch(verifyEmailRequest());
return coralApi('/users/resend-verify', {
method: 'POST',
@@ -378,3 +379,23 @@ export const setRedirectUri = (uri) => ({
type: actions.SET_REDIRECT_URI,
uri,
});
//==============================================================================
// Edit Username
//==============================================================================
const editUsernameFailure = (error) => ({type: actions.EDIT_USERNAME_FAILURE, error});
const editUsernameSuccess = () => ({type: actions.EDIT_USERNAME_SUCCESS});
export const editName = (username) => (dispatch) => {
return coralApi('/account/username', {method: 'PUT', body: {username}})
.then(() => {
dispatch(editUsernameSuccess());
dispatch(addNotification('success', t('framework.success_name_update')));
})
.catch((error) => {
console.error(error);
const errorMessage = error.translation_key ? t(`error.${error.translation_key}`) : error.toString();
dispatch(editUsernameFailure(errorMessage));
});
};
-21
View File
@@ -1,21 +0,0 @@
import {addNotification} from '../actions/notification';
import coralApi from '../helpers/request';
import * as actions from '../constants/auth';
import t from 'coral-framework/services/i18n';
const editUsernameFailure = (error) => ({type: actions.EDIT_USERNAME_FAILURE, error});
const editUsernameSuccess = () => ({type: actions.EDIT_USERNAME_SUCCESS});
export const editName = (username) => (dispatch) => {
return coralApi('/account/username', {method: 'PUT', body: {username}})
.then(() => {
dispatch(editUsernameSuccess());
dispatch(addNotification('success', t('framework.success_name_update')));
})
.catch((error) => {
console.error(error);
const errorMessage = error.translation_key ? t(`error.${error.translation_key}`) : error.toString();
dispatch(editUsernameFailure(errorMessage));
});
};
@@ -1,3 +0,0 @@
export const MULTIPLE_ASSETS_REQUEST = 'MULTIPLE_ASSETS_REQUEST';
export const MULTIPLE_ASSETS_SUCCESS = 'MULTIPLE_ASSETS_SUCCESS';
export const MULTIPLE_ASSSETS_FAILURE = 'MULTIPLE_ASSSETS_FAILURE';
-10
View File
@@ -1,10 +0,0 @@
export const EDIT_NAME_REQUEST = 'EDIT_NAME_REQUEST';
export const EDIT_NAME_SUCCESS = 'EDIT_NAME_SUCCESS';
export const EDIT_NAME_FAILURE = 'EDIT_NAME_FAILURE';
export const COMMENTS_BY_USER_REQUEST = 'COMMENTS_BY_USER_REQUEST';
export const COMMENTS_BY_USER_SUCCESS = 'COMMENTS_BY_USER_SUCCESS';
export const COMMENTS_BY_USER_FAILURE = 'COMMENTS_BY_USER_FAILURE';
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const UPDATE_USERNAME = 'UPDATE_USERNAME';
export const IGNORE_USER_SUCCESS = 'IGNORE_USER_SUCCESS';
export const STOP_IGNORING_USER_SUCCESS = 'STOP_IGNORING_USER_SUCCESS';
+11 -8
View File
@@ -1,24 +1,27 @@
import {Map} from 'immutable';
import * as actions from '../constants/asset';
const initialState = Map({
const initialState = {
closedAt: null,
settings: null,
title: null,
url: null,
features: Map({}),
features: {},
status: 'open',
moderation: null
});
};
export default function asset (state = initialState, action) {
switch (action.type) {
case actions.FETCH_ASSET_SUCCESS:
return state
.merge(action.asset);
return {
...state,
...action.asset,
};
case actions.UPDATE_ASSET_SETTINGS_SUCCESS:
return state
.setIn(['settings'], action.settings);
return {
...state,
settings: action.settings,
};
default:
return state;
}
+180 -101
View File
@@ -1,8 +1,7 @@
import {Map, fromJS} from 'immutable';
import * as actions from '../constants/auth';
import pym from 'coral-framework/services/pym';
const initialState = Map({
const initialState = {
isLoading: false,
loggedIn: false,
user: null,
@@ -21,27 +20,34 @@ const initialState = Map({
fromSignUp: false,
requireEmailConfirmation: false,
redirectUri: pym.parentUrl || location.href,
});
};
const purge = (user) => {
const {settings, profiles, ...userData} = user; // eslint-disable-line
return fromJS(userData);
const {settings, ...userData} = user; // eslint-disable-line
return userData;
};
export default function auth (state = initialState, action) {
switch (action.type) {
case actions.FOCUS_SIGNIN_DIALOG:
return state
.set('signInDialogFocus', true);
return {
...state,
signInDialogFocus: true,
};
case actions.BLUR_SIGNIN_DIALOG:
return state
.set('signInDialogFocus', false);
case actions.SHOW_SIGNIN_DIALOG :
return state
.set('showSignInDialog', true)
.set('signInDialogFocus', true);
return {
...state,
signInDialogFocus: false,
};
case actions.SHOW_SIGNIN_DIALOG:
return {
...state,
showSignInDialog: true,
signInDialogFocus: true,
};
case actions.HIDE_SIGNIN_DIALOG :
return state.merge(Map({
return {
...state,
isLoading: false,
showSignInDialog: false,
signInDialogFocus: false,
@@ -53,125 +59,198 @@ export default function auth (state = initialState, action) {
emailVerificationSuccess: false,
emailVerificationLoading: false,
successSignUp: false
}));
case actions.SHOW_CREATEUSERNAME_DIALOG :
return state
.set('showCreateUsernameDialog', true);
case actions.HIDE_CREATEUSERNAME_DIALOG :
return state.merge(Map({
showCreateUsernameDialog: false
}));
case actions.CREATE_USERNAME_SUCCESS :
return state.merge(Map({
};
case actions.SHOW_CREATEUSERNAME_DIALOG:
return {
...state,
showCreateUsernameDialog: true,
};
case actions.HIDE_CREATEUSERNAME_DIALOG:
return {
...state,
showCreateUsernameDialog: false,
error: ''
}));
case actions.CREATE_USERNAME_FAILURE :
return state
.set('error', action.error);
case actions.CHANGE_VIEW :
return state
.set('error', '')
.set('view', action.view);
};
case actions.CREATE_USERNAME_SUCCESS:
return {
...state,
showCreateUsernameDialog: false,
error: '',
};
case actions.CREATE_USERNAME_FAILURE:
return {
...state,
error: action.error,
};
case actions.CHANGE_VIEW:
return {
...state,
error: action.error,
view: action.view,
};
case actions.CLEAN_STATE:
return initialState;
case actions.FETCH_SIGNIN_REQUEST:
return state
.set('isLoading', true);
return {
...state,
isLoading: true,
};
case actions.CHECK_LOGIN_FAILURE:
return state
.set('checkedInitialLogin', true)
.set('loggedIn', false)
.set('user', null);
return {
...state,
checkedInitialLogin: true,
loggedIn: false,
user: null,
};
case actions.CHECK_LOGIN_SUCCESS:
return state
.set('checkedInitialLogin', true)
.set('loggedIn', true)
.set('user', purge(action.user));
return {
...state,
checkedInitialLogin: true,
loggedIn: true,
user: purge(action.user),
};
case actions.FETCH_SIGNIN_SUCCESS:
return state
.set('loggedIn', true)
.set('user', purge(action.user));
return {
...state,
loggedIn: true,
user: purge(action.user),
};
case actions.FETCH_SIGNIN_FAILURE:
return state
.set('isLoading', false)
.set('error', action.error)
.set('user', null);
return {
...state,
isLoading: false,
error: action.error,
user: null,
};
case actions.FETCH_SIGNUP_FACEBOOK_REQUEST:
return state
.set('fromSignUp', true);
return {
...state,
fromSignUp: true,
};
case actions.FETCH_SIGNIN_FACEBOOK_REQUEST:
return state
.set('fromSignUp', false);
return {
...state,
fromSignUp: false,
};
case actions.FETCH_SIGNIN_FACEBOOK_SUCCESS:
return state
.set('user', purge(action.user))
.set('loggedIn', true);
return {
...state,
loggedIn: true,
user: purge(action.user),
};
case actions.FETCH_SIGNIN_FACEBOOK_FAILURE:
return state
.set('error', action.error)
.set('user', null);
return {
...state,
error: action.error,
user: null,
};
case actions.FETCH_SIGNUP_REQUEST:
return state
.set('isLoading', true);
return {
...state,
isLoading: true,
};
case actions.FETCH_SIGNUP_FAILURE:
return state
.set('error', action.error)
.set('isLoading', false);
return {
...state,
error: action.error,
isLoading: false,
};
case actions.FETCH_SIGNUP_SUCCESS:
return state
.set('isLoading', false)
.set('successSignUp', true);
return {
...state,
isLoading: false,
successSignUp: true,
};
case actions.LOGOUT:
return state
.set('user', null)
.set('isLoading', false)
.set('loggedIn', false);
return {
...state,
user: null,
isLoading: false,
loggedIn: false,
};
case actions.INVALID_FORM:
return state
.set('error', action.error);
return {
...state,
error: action.error,
};
case actions.VALID_FORM:
return state
.set('error', '');
return {
...state,
error: '',
};
case actions.FETCH_FORGOT_PASSWORD_SUCCESS:
return state
.set('passwordRequestFailure', null)
.set('passwordRequestSuccess', 'If you have a registered account, a password reset link was sent to that email');
return {
...state,
passwordRequestFailure: null,
passwordRequestSuccess: 'If you have a registered account, a password reset link was sent to that email',
};
case actions.FETCH_FORGOT_PASSWORD_FAILURE:
return state
.set('passwordRequestFailure', 'There was an error sending your password reset email. Please try again soon!')
.set('passwordRequestSuccess', null);
return {
...state,
passwordRequestFailure: 'There was an error sending your password reset email. Please try again soon!',
passwordRequestSuccess: null,
};
case actions.UPDATE_USERNAME:
return state
.setIn(['user', 'username'], action.username);
return {
...state,
user: {
...state.user,
username: action.username,
}
};
case actions.VERIFY_EMAIL_FAILURE:
return state
.set('emailVerificationFailure', true)
.set('emailVerificationLoading', false);
return {
...state,
emailVerificationFailure: true,
emailVerificationLoading: false,
};
case actions.VERIFY_EMAIL_REQUEST:
return state.set('emailVerificationLoading', true);
return {
...state,
emailVerificationLoading: true,
};
case actions.VERIFY_EMAIL_SUCCESS:
return state
.set('emailVerificationSuccess', true)
.set('emailVerificationLoading', false);
return {
...state,
emailVerificationSuccess: true,
emailVerificationLoading: false,
};
case actions.SET_REQUIRE_EMAIL_VERIFICATION:
return state
.set('requireEmailConfirmation', action.required);
return {
...state,
requireEmailConfirmation: action.required,
};
case actions.SET_REDIRECT_URI:
return state
.set('redirectUri', action.uri);
return {
...state,
redirectUri: action.uri,
};
case 'APOLLO_SUBSCRIPTION_RESULT':
if (action.operationName === 'UserBanned' && state.getIn(['user', 'id']) === action.variables.user_id) {
return state
.mergeIn(['user'], action.result.data.userBanned);
return {
...state,
user: {
...state.user,
...action.result.data.userBanned,
},
};
}
if (action.operationName === 'UserSuspended' && state.getIn(['user', 'id']) === action.variables.user_id) {
return state
.mergeIn(['user'], action.result.data.userSuspended);
return {
...state,
user: {
...state.user,
...action.result.data.userSuspended,
},
};
}
if (action.operationName === 'UsernameRejected' && state.getIn(['user', 'id']) === action.variables.user_id) {
return state
.mergeIn(['user'], action.result.data.usernameRejected);
return {
...state,
user: {
...state.user,
...action.result.data.usernameRejected,
},
};
}
return state;
default :
-2
View File
@@ -1,11 +1,9 @@
import auth from './auth';
import user from './user';
import asset from './asset';
import {reducer as commentBox} from '../../talk-plugin-commentbox';
export default {
auth,
user,
asset,
commentBox,
};
-43
View File
@@ -1,43 +0,0 @@
import {Map} from 'immutable';
import * as authActions from '../constants/auth';
import * as actions from '../constants/user';
import * as assetActions from '../constants/assets';
const initialState = Map({
username: '',
profiles: [],
settings: {},
myComments: [],
myAssets: [], // the assets from which myComments (above) originated
});
const purge = (user) => {
const {_id, created_at, updated_at, __v, roles, ...userData} = user; // eslint-disable-line
return userData;
};
export default function user (state = initialState, action) {
switch (action.type) {
case authActions.CHECK_LOGIN_SUCCESS:
return state.merge(Map(purge(action.user)));
case authActions.CHECK_LOGIN_FAILURE:
return initialState;
case authActions.FETCH_SIGNIN_SUCCESS:
return state.merge(Map(purge(action.user)));
case authActions.FETCH_SIGNIN_FAILURE:
return initialState;
case authActions.FETCH_SIGNIN_FACEBOOK_SUCCESS:
return state.merge(Map(purge(action.user)));
case authActions.FETCH_SIGNIN_FACEBOOK_FAILURE:
return initialState;
case actions.SAVE_BIO_SUCCESS:
return state.set('settings', action.settings);
case actions.COMMENTS_BY_USER_SUCCESS:
return state.set('myComments', action.comments);
case assetActions.MULTIPLE_ASSETS_SUCCESS:
return state.set('myAssets', action.assets);
case actions.LOGOUT_SUCCESS:
return initialState;
}
return state;
}
@@ -51,7 +51,7 @@ class ProfileContainer extends Component {
};
render() {
const {auth, asset, showSignInDialog, stopIgnoringUser} = this.props;
const {auth, auth: {user}, asset, showSignInDialog, stopIgnoringUser} = this.props;
const {me} = this.props.root;
const loading = [1, 2, 4].indexOf(this.props.data.networkStatus) >= 0;
@@ -63,14 +63,14 @@ class ProfileContainer extends Component {
return <Spinner />;
}
const localProfile = this.props.user.profiles.find(
const localProfile = user.profiles.find(
(p) => p.provider === 'local'
);
const emailAddress = localProfile && localProfile.id;
return (
<div>
<h2>{this.props.user.username}</h2>
<h2>{user.username}</h2>
{emailAddress ? <p>{emailAddress}</p> : null}
{me.ignoredUsers && me.ignoredUsers.length
@@ -138,9 +138,8 @@ const withProfileQuery = withQuery(
`);
const mapStateToProps = (state) => ({
user: state.user.toJS(),
asset: state.asset.toJS(),
auth: state.auth.toJS()
asset: state.asset,
auth: state.auth
});
const mapDispatchToProps = (dispatch) =>
-9
View File
@@ -6,7 +6,6 @@ permalink: /docs/architecture/client
## The Stack
- [React](#react)
- [Redux](#redux)
- [ImmutableJS](#immutablejs)
## The Architecture
@@ -96,14 +95,6 @@ We use [Apollo](http://www.apollodata.com/) to handle graph requests and handle
## Redux
We use [Redux](http://redux.js.org/) to handle the auth state.
## ImmutableJS
We use Immutable JS to maintain our state immutable.
We found some really good tradeoffs while building Talk.
[How to use ImmutableJS and how we use it with Talk](https://facebook.github.io/immutable-js/docs/#/)
## Test
[How we do testing at Coral with Talk]({{ "/docs/development/tools" | absolute_url }})
+2 -3
View File
@@ -116,7 +116,7 @@
"passport-local": "^1.0.0",
"prop-types": "^15.5.10",
"query-strings": "^0.0.1",
"react-apollo": "^1.1.0",
"react-apollo": "^1.4.12",
"react-input-autosize": "^1.1.4",
"react-recaptcha": "^2.2.6",
"react-toastify": "^1.5.0",
@@ -136,7 +136,7 @@
"yamljs": "^0.2.10"
},
"devDependencies": {
"apollo-client": "^1.0.4",
"apollo-client": "^1.9.1",
"autoprefixer": "^6.5.2",
"babel-cli": "^6.24.0",
"babel-core": "^6.24.0",
@@ -180,7 +180,6 @@
"hammerjs": "^2.0.8",
"history": "^3.0.0",
"ignore-styles": "^5.0.1",
"immutable": "^3.8.1",
"imports-loader": "^0.7.1",
"istanbul": "^1.1.0-alpha.1",
"jsdom": "^9.8.3",
+1 -1
View File
@@ -363,7 +363,7 @@ export default (reaction) => (WrappedComponent) => {
);
const mapStateToProps = (state) => ({
user: state.auth.toJS().user,
user: state.auth.user,
});
const mapDispatchToProps = (dispatch) =>
+1 -1
View File
@@ -84,7 +84,7 @@ export default (tag) => (WrappedComponent) => {
}
const mapStateToProps = (state) => ({
user: state.auth.toJS().user,
user: state.auth.user,
});
const mapDispatchToProps = (dispatch) =>
@@ -122,7 +122,7 @@ class ChangeUsernameContainer extends React.Component {
}
const mapStateToProps = ({auth}) => ({
auth: auth.toJS()
auth: auth
});
const mapDispatchToProps = (dispatch) =>
@@ -16,7 +16,7 @@ const SignInButton = ({loggedIn, showSignInDialog}) => (
);
const mapStateToProps = ({auth}) => ({
loggedIn: auth.toJS().loggedIn
loggedIn: auth.loggedIn
});
const mapDispatchToProps = (dispatch) =>
@@ -176,7 +176,7 @@ class SignInContainer extends React.Component {
}
const mapStateToProps = (state) => ({
auth: state.auth.toJS()
auth: state.auth
});
const mapDispatchToProps = (dispatch) =>
@@ -22,8 +22,8 @@ const UserBox = ({loggedIn, user, logout, onShowProfile}) => (
);
const mapStateToProps = ({auth}) => ({
loggedIn: auth.toJS().loggedIn,
user: auth.toJS().user
loggedIn: auth.loggedIn,
user: auth.user
});
const mapDispatchToProps = (dispatch) =>
@@ -91,7 +91,7 @@ const COMMENT_UNFEATURED_SUBSCRIPTION = gql`
`;
const mapStateToProps = (state) => ({
user: state.auth.toJS().user,
user: state.auth.user,
});
export default connect(mapStateToProps, null)(ModSubscription);
+48 -40
View File
@@ -9,10 +9,6 @@
git-url-parse "^6.0.2"
shelljs "^0.7.0"
"@types/async@^2.0.31":
version "2.0.40"
resolved "https://registry.yarnpkg.com/@types/async/-/async-2.0.40.tgz#ac02de68e66c004a61b7cb16df8b1db3a254cca9"
"@types/express-serve-static-core@*":
version "4.0.44"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.0.44.tgz#a1c3bd5d80e93c72fba91a03f5412c47f21d4ae7"
@@ -26,18 +22,18 @@
"@types/express-serve-static-core" "*"
"@types/serve-static" "*"
"@types/graphql@0.10.2":
version "0.10.2"
resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.10.2.tgz#d7c79acbaa17453b6681c80c34b38fcb10c4c08c"
"@types/graphql@^0.8.5", "@types/graphql@^0.8.6":
version "0.8.6"
resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.8.6.tgz#b34fb880493ba835b0c067024ee70130d6f9bb68"
"@types/graphql@^0.9.0", "@types/graphql@^0.9.1":
"@types/graphql@^0.9.1":
version "0.9.1"
resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.1.tgz#b04ebe84bc997cc60dbea2ed4d0d4342c737f99d"
"@types/isomorphic-fetch@0.0.33":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/isomorphic-fetch/-/isomorphic-fetch-0.0.33.tgz#3ea1b86f8b73e6a7430d01d4dbd5b1f63fd72718"
"@types/mime@*":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-0.0.29.tgz#fbcfd330573b912ef59eeee14602bface630754b"
@@ -203,20 +199,27 @@ anymatch@^1.3.0:
arrify "^1.0.0"
micromatch "^2.1.5"
apollo-client@^1.0.2, apollo-client@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.0.4.tgz#af75db8cdd27e08a835ddfb39807849e178540f9"
apollo-client@^1.4.0, apollo-client@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.9.1.tgz#9e6a383605572c755038cf5d7fdac9382bcdc040"
dependencies:
graphql "^0.9.3"
apollo-link-core "^0.5.0"
graphql "^0.10.0"
graphql-anywhere "^3.0.1"
graphql-tag "^2.0.0"
redux "^3.4.0"
symbol-observable "^1.0.2"
whatwg-fetch "^2.0.0"
optionalDependencies:
"@types/async" "^2.0.31"
"@types/graphql" "^0.9.0"
"@types/isomorphic-fetch" "0.0.33"
"@types/graphql" "0.10.2"
apollo-link-core@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/apollo-link-core/-/apollo-link-core-0.5.0.tgz#dc87da1aaa63b029321ae70938dc26257f5ab8c6"
dependencies:
graphql "^0.10.3"
graphql-tag "^2.4.2"
zen-observable-ts "^0.4.0"
app-module-path@^2.2.0:
version "2.2.0"
@@ -3711,6 +3714,10 @@ graphql-tag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.0.0.tgz#f3efe3b4d64f33bfe8479ae06a461c9d72f2a6fe"
graphql-tag@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.4.2.tgz#6a63297d8522d03a2b72d26f1b239aab343840cd"
graphql-tools@^0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-0.10.1.tgz#274aa338d50b1c0b3ed6936eafd8ed3a19ed1828"
@@ -3721,13 +3728,19 @@ graphql-tools@^0.10.1:
optionalDependencies:
"@types/graphql" "^0.8.5"
graphql@^0.10.0, graphql@^0.10.3:
version "0.10.5"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.10.5.tgz#c9be17ca2bdfdbd134077ffd9bbaa48b8becd298"
dependencies:
iterall "^1.1.0"
graphql@^0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.7.2.tgz#cc894a32823399b8a0cb012b9e9ecad35cd00f72"
dependencies:
iterall "1.0.2"
graphql@^0.9.1, graphql@^0.9.3:
graphql@^0.9.1:
version "0.9.3"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.9.3.tgz#71fc0fa331bffb9c20678485861cfb370803118e"
dependencies:
@@ -3876,6 +3889,10 @@ hoist-non-react-statics@^1.0.0, hoist-non-react-statics@^1.0.3, hoist-non-react-
version "1.2.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
hoist-non-react-statics@^2.2.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.2.2.tgz#c0eca5a7d5a28c5ada3107eb763b01da6bfa81fb"
home-or-tmp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
@@ -3996,11 +4013,11 @@ iconv-lite@0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
iconv-lite@0.4.15, iconv-lite@^0.4.5, iconv-lite@~0.4.13:
iconv-lite@0.4.15:
version "0.4.15"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
iconv-lite@^0.4.17:
iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13:
version "0.4.18"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
@@ -4034,10 +4051,6 @@ immutability-helper@^2.2.0:
dependencies:
invariant "^2.2.0"
immutable@^3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2"
imports-loader@^0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.7.1.tgz#f204b5f34702a32c1db7d48d89d5e867a0441253"
@@ -4531,7 +4544,7 @@ iterall@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.0.3.tgz#e0b31958f835013c323ff0b10943829ac69aa4b7"
iterall@^1.1.1:
iterall@^1.1.0, iterall@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.1.1.tgz#f7f0af11e9a04ec6426260f5019d9fcca4d50214"
@@ -6912,14 +6925,14 @@ react-addons-test-utils@^15.4.2:
fbjs "^0.8.4"
object-assign "^4.1.0"
react-apollo@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-1.1.1.tgz#136a6be6e0ed7bfa5292e67073e1829fe12e1e17"
react-apollo@^1.4.12:
version "1.4.12"
resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-1.4.12.tgz#0cacbdd335acec4c1079feb48047df1c43f77bdf"
dependencies:
apollo-client "^1.0.2"
apollo-client "^1.4.0"
graphql-anywhere "^3.0.0"
graphql-tag "^2.0.0"
hoist-non-react-statics "^1.2.0"
hoist-non-react-statics "^2.2.0"
invariant "^2.2.1"
lodash.flatten "^4.2.0"
lodash.isequal "^4.1.1"
@@ -6927,10 +6940,8 @@ react-apollo@^1.1.0:
lodash.pick "^4.4.0"
object-assign "^4.0.1"
prop-types "^15.5.8"
optionalDependencies:
react-dom "0.14.x || 15.* || ^15.0.0"
"react-dom@0.14.x || 15.* || ^15.0.0", react-dom@^15.3.1, react-dom@^15.4.2:
react-dom@^15.3.1, react-dom@^15.4.2:
version "15.5.4"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.4.tgz#ba0c28786fd52ed7e4f2135fe0288d462aef93da"
dependencies:
@@ -7869,14 +7880,7 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
string-width@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e"
dependencies:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^3.0.0"
string-width@^2.1.0:
string-width@^2.0.0, string-width@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
dependencies:
@@ -8816,3 +8820,7 @@ yauzl@^2.5.0:
dependencies:
buffer-crc32 "~0.2.3"
fd-slicer "~1.0.1"
zen-observable-ts@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.4.0.tgz#a74bc9fe59747948a577bd513d438e70fcfae7e2"