From 9aec3e6b818539f0c2818e7d6a47416ea35e57b8 Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Tue, 13 Mar 2018 12:18:16 +0100 Subject: [PATCH 01/22] Add rethinkdb-changefeed-reconnect-pkg --- .../rethinkdb-changefeed-reconnect_vx.x.x.js | 74 +++++++++++++++++++ iris/package.json | 1 + iris/yarn.lock | 6 ++ package.json | 1 + yarn.lock | 6 ++ 5 files changed, 88 insertions(+) create mode 100644 flow-typed/npm/rethinkdb-changefeed-reconnect_vx.x.x.js diff --git a/flow-typed/npm/rethinkdb-changefeed-reconnect_vx.x.x.js b/flow-typed/npm/rethinkdb-changefeed-reconnect_vx.x.x.js new file mode 100644 index 0000000000..3df6f6fba5 --- /dev/null +++ b/flow-typed/npm/rethinkdb-changefeed-reconnect_vx.x.x.js @@ -0,0 +1,74 @@ +// flow-typed signature: 592c0e5852cd969e5602279b98fb79c2 +// flow-typed version: <>/rethinkdb-changefeed-reconnect_v0.3.2/flow_v0.66.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'rethinkdb-changefeed-reconnect' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'rethinkdb-changefeed-reconnect' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'rethinkdb-changefeed-reconnect/example/example.babel' { + declare module.exports: any; +} + +declare module 'rethinkdb-changefeed-reconnect/example/example' { + declare module.exports: any; +} + +declare module 'rethinkdb-changefeed-reconnect/example/index' { + declare module.exports: any; +} + +declare module 'rethinkdb-changefeed-reconnect/lib/__tests__/index.test' { + declare module.exports: any; +} + +declare module 'rethinkdb-changefeed-reconnect/lib/index' { + declare module.exports: any; +} + +declare module 'rethinkdb-changefeed-reconnect/src/__tests__/index.test' { + declare module.exports: any; +} + +declare module 'rethinkdb-changefeed-reconnect/src/index' { + declare module.exports: any; +} + +// Filename aliases +declare module 'rethinkdb-changefeed-reconnect/example/example.babel.js' { + declare module.exports: $Exports<'rethinkdb-changefeed-reconnect/example/example.babel'>; +} +declare module 'rethinkdb-changefeed-reconnect/example/example.js' { + declare module.exports: $Exports<'rethinkdb-changefeed-reconnect/example/example'>; +} +declare module 'rethinkdb-changefeed-reconnect/example/index.js' { + declare module.exports: $Exports<'rethinkdb-changefeed-reconnect/example/index'>; +} +declare module 'rethinkdb-changefeed-reconnect/lib/__tests__/index.test.js' { + declare module.exports: $Exports<'rethinkdb-changefeed-reconnect/lib/__tests__/index.test'>; +} +declare module 'rethinkdb-changefeed-reconnect/lib/index.js' { + declare module.exports: $Exports<'rethinkdb-changefeed-reconnect/lib/index'>; +} +declare module 'rethinkdb-changefeed-reconnect/src/__tests__/index.test.js' { + declare module.exports: $Exports<'rethinkdb-changefeed-reconnect/src/__tests__/index.test'>; +} +declare module 'rethinkdb-changefeed-reconnect/src/index.js' { + declare module.exports: $Exports<'rethinkdb-changefeed-reconnect/src/index'>; +} diff --git a/iris/package.json b/iris/package.json index a01cfe9732..0aa08ec1bc 100644 --- a/iris/package.json +++ b/iris/package.json @@ -101,6 +101,7 @@ "redraft": "0.8.0", "redux": "^3.6.0", "redux-thunk": "^2.2.0", + "rethinkdb-changefeed-reconnect": "^0.3.2", "rethinkdb-inspector": "^0.3.3", "rethinkdb-migrate": "^1.1.0", "rethinkdbdash": "^2.3.29", diff --git a/iris/yarn.lock b/iris/yarn.lock index 7115273e21..2a97c87316 100644 --- a/iris/yarn.lock +++ b/iris/yarn.lock @@ -6200,6 +6200,12 @@ resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" +rethinkdb-changefeed-reconnect@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/rethinkdb-changefeed-reconnect/-/rethinkdb-changefeed-reconnect-0.3.2.tgz#2999f5313205ab35d9ac2d1b0533765ee3376923" + dependencies: + babel-runtime "^6.18.0" + rethinkdb-inspector@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/rethinkdb-inspector/-/rethinkdb-inspector-0.3.3.tgz#f0d88c66d17e0234b5518ca51cd8c272cb787003" diff --git a/package.json b/package.json index e93ed2d9ad..ebe913243e 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,7 @@ "redraft": "0.8.0", "redux": "^3.6.0", "redux-thunk": "^2.2.0", + "rethinkdb-changefeed-reconnect": "^0.3.2", "rethinkdb-inspector": "^0.3.3", "rethinkdb-migrate": "^1.1.0", "rethinkdbdash": "^2.3.29", diff --git a/yarn.lock b/yarn.lock index 06e95ebc0b..53d3b01db4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9065,6 +9065,12 @@ ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" +rethinkdb-changefeed-reconnect@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/rethinkdb-changefeed-reconnect/-/rethinkdb-changefeed-reconnect-0.3.2.tgz#2999f5313205ab35d9ac2d1b0533765ee3376923" + dependencies: + babel-runtime "^6.18.0" + rethinkdb-inspector@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/rethinkdb-inspector/-/rethinkdb-inspector-0.3.3.tgz#f0d88c66d17e0234b5518ca51cd8c272cb787003" From 6f752934c49817b950f841f262ab0125157f24b4 Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Tue, 13 Mar 2018 12:18:20 +0100 Subject: [PATCH 02/22] Implement auto-reconnecting changefeeds ...and properly type iris/models/thread and impacted modules. --- iris/models/community.js | 3 +- iris/models/directMessageThread.js | 15 ++++-- iris/models/message.js | 11 ++-- iris/models/notification.js | 28 +++++++--- iris/models/thread.js | 20 ++++--- iris/models/utils.js | 63 +++++++++++----------- iris/queries/community/topAndNewThreads.js | 2 +- iris/queries/meta/topThreads.js | 2 +- 8 files changed, 90 insertions(+), 54 deletions(-) diff --git a/iris/models/community.js b/iris/models/community.js index def6fc13e6..6397b9c1cc 100644 --- a/iris/models/community.js +++ b/iris/models/community.js @@ -9,6 +9,7 @@ import { } from 'shared/bull/queues'; import { removeMemberInChannel } from './usersChannels'; import type { DBCommunity } from 'shared/types'; +import type { Timeframe } from './utils'; export const getCommunityById = (id: string): Promise => { return db @@ -589,7 +590,7 @@ export const getThreadCount = (communityId: string) => { export const getCommunityGrowth = async ( table: string, - range: string, + range: Timeframe, field: string, communityId: string, filter?: mixed diff --git a/iris/models/directMessageThread.js b/iris/models/directMessageThread.js index bb505259b9..dda7f6ed41 100644 --- a/iris/models/directMessageThread.js +++ b/iris/models/directMessageThread.js @@ -1,6 +1,6 @@ //@flow const { db } = require('./db'); -import { NEW_DOCUMENTS, eachAsyncNewValue } from './utils'; +import { NEW_DOCUMENTS, createChangefeed } from './utils'; export type DBDirectMessageThread = { createdAt: Date, @@ -80,8 +80,8 @@ const hasChanged = (field: string) => .ne(db.row('new_val')(field)); const THREAD_LAST_ACTIVE_CHANGED = hasChanged('threadLastActive'); -const listenToUpdatedDirectMessageThreads = (cb: Function): Function => { - return db +const getUpdatedDirectMessageThreadChangefeed = () => + db .table('directMessageThreads') .changes({ includeInitial: false, @@ -92,7 +92,14 @@ const listenToUpdatedDirectMessageThreads = (cb: Function): Function => { right: ['id', 'createdAt', 'threadId', 'lastActive', 'lastSeen'], }) .zip() - .run(eachAsyncNewValue(cb)); + .run(); + +const listenToUpdatedDirectMessageThreads = (cb: Function): Function => { + return createChangefeed( + getUpdatedDirectMessageThreadChangefeed, + cb, + 'listenToUpdatedDirectMessageThreads' + ); }; // prettier-ignore diff --git a/iris/models/message.js b/iris/models/message.js index 4121ef6ce4..5cedbdf302 100644 --- a/iris/models/message.js +++ b/iris/models/message.js @@ -6,7 +6,7 @@ import { processReputationEventQueue, _adminProcessToxicMessageQueue, } from 'shared/bull/queues'; -import { NEW_DOCUMENTS, eachAsyncNewValue } from './utils'; +import { NEW_DOCUMENTS, createChangefeed } from './utils'; import { setThreadLastActive } from './thread'; export type MessageTypes = 'text' | 'media'; @@ -149,14 +149,17 @@ export const storeMessage = ( }); }; -export const listenToNewMessages = (cb: Function): Function => { - return db +const getNewMessageChangefeed = () => + db .table('messages') .changes({ includeInitial: false, }) .filter(NEW_DOCUMENTS)('new_val') - .run(eachAsyncNewValue(cb)); + .run(); + +export const listenToNewMessages = (cb: Function): Function => { + return createChangefeed(getNewMessageChangefeed, cb, 'listenToNewMessages'); }; export const getMessageCount = (threadId: string): Promise => { diff --git a/iris/models/notification.js b/iris/models/notification.js index f7a3e91f93..e0bae8794b 100644 --- a/iris/models/notification.js +++ b/iris/models/notification.js @@ -1,6 +1,6 @@ // @flow const { db } = require('./db'); -import { NEW_DOCUMENTS, eachAsyncNewValue } from './utils'; +import { NEW_DOCUMENTS, createChangefeed } from './utils'; export const getNotificationsByUser = ( userId: string, @@ -62,8 +62,8 @@ const hasChanged = (field: string) => const MODIFIED_AT_CHANGED = hasChanged('entityAddedAt'); -export const listenToNewNotifications = (cb: Function): Function => { - return db +const getNewNotificationsChangefeed = () => + db .table('usersNotifications') .changes({ includeInitial: false, @@ -75,11 +75,18 @@ export const listenToNewNotifications = (cb: Function): Function => { }) .zip() .filter(row => row('context')('type').ne('DIRECT_MESSAGE_THREAD')) - .run(eachAsyncNewValue(cb)); + .run(); + +export const listenToNewNotifications = (cb: Function): Function => { + return createChangefeed( + getNewNotificationsChangefeed, + cb, + 'listenToNewNotifications' + ); }; -export const listenToNewDirectMessageNotifications = (cb: Function) => { - return db +const getNewDirectMessageNotificationsChangefeed = () => + db .table('usersNotifications') .changes({ includeInitial: false, @@ -91,5 +98,12 @@ export const listenToNewDirectMessageNotifications = (cb: Function) => { }) .zip() .filter(row => row('context')('type').eq('DIRECT_MESSAGE_THREAD')) - .run(eachAsyncNewValue(cb)); + .run(); + +export const listenToNewDirectMessageNotifications = (cb: Function) => { + return createChangefeed( + getNewDirectMessageNotificationsChangefeed, + cb, + 'listenToNewDirectMessageNotifications' + ); }; diff --git a/iris/models/thread.js b/iris/models/thread.js index f6a346533d..fc5252f30e 100644 --- a/iris/models/thread.js +++ b/iris/models/thread.js @@ -6,11 +6,12 @@ import { sendThreadNotificationQueue, _adminProcessToxicThreadQueue, } from 'shared/bull/queues'; -const { NEW_DOCUMENTS, parseRange, eachAsyncNewValue } = require('./utils'); +const { NEW_DOCUMENTS, parseRange, createChangefeed } = require('./utils'); import { deleteMessagesInThread } from '../models/message'; import { turnOffAllThreadNotifications } from '../models/usersThreads'; import type { PaginationOptions } from '../utils/paginate-arrays'; import type { DBThread } from 'shared/types'; +import type { Timeframe } from './utils'; export const getThread = (threadId: string): Promise => { return db @@ -90,7 +91,7 @@ export const getThreadsByCommunity = ( export const getThreadsByCommunityInTimeframe = ( communityId: string, - range: string + range: Timeframe ): Promise> => { const { current } = parseRange(range); return db @@ -102,7 +103,7 @@ export const getThreadsByCommunityInTimeframe = ( }; export const getThreadsInTimeframe = ( - range: string + range: Timeframe ): Promise> => { const { current } = parseRange(range); return db @@ -505,12 +506,19 @@ const hasChanged = (field: string) => .ne(db.row('new_val')(field)); const LAST_ACTIVE_CHANGED = hasChanged('lastActive'); -export const listenToUpdatedThreads = (cb: Function): Function => { - return db +const getUpdatedThreadsChangefeed = () => + db .table('threads') .changes({ includeInitial: false, }) .filter(NEW_DOCUMENTS.or(LAST_ACTIVE_CHANGED))('new_val') - .run(eachAsyncNewValue(cb)); + .run(); + +export const listenToUpdatedThreads = (cb: Function): Function => { + return createChangefeed( + getUpdatedThreadsChangefeed, + cb, + 'listenToUpdatedThreads' + ); }; diff --git a/iris/models/utils.js b/iris/models/utils.js index 81d0823072..2350efb034 100644 --- a/iris/models/utils.js +++ b/iris/models/utils.js @@ -1,42 +1,45 @@ -const { db } = require('./db'); +// @flow +const debug = require('debug')('iris:models:utils'); +import processChangefeed from 'rethinkdb-changefeed-reconnect'; +import { db } from './db'; +import Raven from 'shared/raven'; +import type { Cursor } from 'rethinkdbdash'; export const NEW_DOCUMENTS = db .row('old_val') .eq(null) .and(db.not(db.row('new_val').eq(null))); -export const eachAsyncNewValue = (cb: Function) => ( - err?: Error, - cursor: Cursor +export const createChangefeed = ( + getChangefeed: () => Promise, + callback: (arg: any) => void, + name?: string ) => { - if (err) throw err; - cursor - .eachAsync(data => { - // Call the passed callback with the message directly - cb(data); - }) - .catch(err => { + return processChangefeed( + getChangefeed, + callback, + err => { console.error(err); - try { - cursor.close(); - } catch (err) {} - }); -}; - -export const listenToNewDocumentsIn = (table, cb) => { - return ( - db - .table(table) - .changes({ - includeInitial: false, - }) - // Filter to only include newly inserted messages in the changefeed - .filter(NEW_DOCUMENTS) - .run(eachAsyncNewValue(cb)) + Raven.captureException(err); + }, + { + changefeedName: name, + attemptDelay: 60000, + maxAttempts: Infinity, + logger: { + // Ignore log and info logs in production + log: debug, + info: debug, + warn: console.warn.bind(console), + error: console.error.bind(console), + }, + } ); }; -export const parseRange = timeframe => { +export type Timeframe = 'daily' | 'weekly' | 'monthly' | 'quarterly'; + +export const parseRange = (timeframe?: Timeframe) => { switch (timeframe) { case 'daily': { return { current: 60 * 60 * 24, previous: 60 * 60 * 24 * 2 }; @@ -56,7 +59,7 @@ export const parseRange = timeframe => { } }; -export const getAu = (range: string) => { +export const getAu = (range: Timeframe) => { const { current } = parseRange(range); return db .table('users') @@ -68,7 +71,7 @@ export const getAu = (range: string) => { export const getGrowth = async ( table: string, - range: string, + range: Timeframe, field: string, filter: ?mixed ) => { diff --git a/iris/queries/community/topAndNewThreads.js b/iris/queries/community/topAndNewThreads.js index 8f13b6373a..aa16bacec2 100644 --- a/iris/queries/community/topAndNewThreads.js +++ b/iris/queries/community/topAndNewThreads.js @@ -15,7 +15,7 @@ export default ({ id }: DBCommunity, __: any, { user }: GraphQLContext) => { return new UserError('You must be signed in to continue.'); } - return getThreadsByCommunityInTimeframe(id, 'week').then(async threads => { + return getThreadsByCommunityInTimeframe(id, 'weekly').then(async threads => { if (!threads) return { topThreads: [], newThreads: [] }; const messageCountPromises = threads.map(async ({ id }) => ({ diff --git a/iris/queries/meta/topThreads.js b/iris/queries/meta/topThreads.js index 450433c3d9..db20ba954d 100644 --- a/iris/queries/meta/topThreads.js +++ b/iris/queries/meta/topThreads.js @@ -7,7 +7,7 @@ import { getMessageCount } from '../../models/message'; export default async (_: any, __: any, { user }: GraphQLContext) => { if (!isAdmin(user.id)) return null; - const threads = await getThreadsInTimeframe('week'); + const threads = await getThreadsInTimeframe('weekly'); const messageCountPromises = threads.map(async ({ id, ...thread }) => ({ id, From cb79bc1cbc50a1addc10c934811c88053d16e3cc Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Tue, 13 Mar 2018 13:25:21 -0700 Subject: [PATCH 03/22] Fix feeds on user profiles --- iris/models/thread.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iris/models/thread.js b/iris/models/thread.js index fc5252f30e..96c632c16c 100644 --- a/iris/models/thread.js +++ b/iris/models/thread.js @@ -131,7 +131,7 @@ export const getViewableThreadsByUser = async ( const getCurrentUsersChannelIds = db .table('usersChannels') .getAll(currentUser, { index: 'userId' }) - .filter({ isBlocked: false }) + .filter({ isBlocked: false, isMember: true }) .map(userChannel => userChannel('channelId')) .run(); @@ -201,7 +201,7 @@ export const getViewableParticipantThreadsByUser = async ( const getCurrentUsersChannelIds = db .table('usersChannels') .getAll(currentUser, { index: 'userId' }) - .filter({ isBlocked: false }) + .filter({ isBlocked: false, isMember: true }) .map(userChannel => userChannel('channelId')) .run(); @@ -258,6 +258,7 @@ export const getPublicParticipantThreadsByUser = ( return db .table('usersThreads') .getAll(evalUser, { index: 'userId' }) + .filter({ isParticipant: true }) .eqJoin('threadId', db.table('threads')) .without({ left: [ From cb6a81049848c6e7317c773f95d76a45fd462ce9 Mon Sep 17 00:00:00 2001 From: uberbryn Date: Tue, 13 Mar 2018 14:15:53 -0700 Subject: [PATCH 04/22] Updates thread status colors, giving New Thread and New Message indicators different values. --- src/views/dashboard/components/inboxThread.js | 21 ++++++++-------- src/views/dashboard/style.js | 24 +++++++++++++++---- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/views/dashboard/components/inboxThread.js b/src/views/dashboard/components/inboxThread.js index 224add4285..3353c0de8b 100644 --- a/src/views/dashboard/components/inboxThread.js +++ b/src/views/dashboard/components/inboxThread.js @@ -16,8 +16,9 @@ import { ThreadTitle, AttachmentsContainer, ThreadMeta, - MetaText, - MetaTextPill, + StatusText, + NewThreadPill, + NewMessagePill, LockedTextPill, MiniLinkPreview, } from '../style'; @@ -54,13 +55,13 @@ class InboxThread extends React.Component { if (!data) return null; const defaultMessageCountString = ( - + {messageCount === 0 ? `${messageCount} messages` : messageCount > 1 ? `${messageCount} messages` : `${messageCount} message`} - + ); if (isLocked) { @@ -80,9 +81,9 @@ class InboxThread extends React.Component { } return ( - + New thread! - + ); } @@ -90,9 +91,9 @@ class InboxThread extends React.Component { if (active) return defaultMessageCountString; return ( - + New messages! - + ); } @@ -229,11 +230,11 @@ class WatercoolerThreadPure extends React.Component { )} {messageCount > 0 && ( - + {messageCount > 1 ? `${messageCount} messages` : `${messageCount} message`} - + )} diff --git a/src/views/dashboard/style.js b/src/views/dashboard/style.js index d3eb1e11a4..73634c6685 100644 --- a/src/views/dashboard/style.js +++ b/src/views/dashboard/style.js @@ -505,7 +505,7 @@ export const EmptyParticipantHead = styled.span` } `; -export const MetaText = styled.span` +export const StatusText = styled.span` font-size: 14px; color: ${props => props.new @@ -525,11 +525,11 @@ export const MetaText = styled.span` } `; -export const MetaTextPill = styled(MetaText)` +const StatusPill = styled(StatusText)` color: ${props => props.active ? props.theme.brand.alt : props.theme.text.reverse}; background: ${props => - props.active ? props.theme.text.reverse : props.theme.warn.alt}; + props.active ? props.theme.text.reverse : props.theme.brand.alt}; border-radius: 20px; padding: 0 12px; font-size: 11px; @@ -539,11 +539,25 @@ export const MetaTextPill = styled(MetaText)` align-items: center; `; -export const LockedTextPill = styled(MetaTextPill)` +export const NewThreadPill = styled(StatusPill)` + color: ${props => + props.active ? props.theme.brand.alt : props.theme.text.reverse}; + background: ${props => + props.active ? props.theme.text.reverse : props.theme.success.alt}; +`; + +export const NewMessagePill = styled(StatusPill)` + color: ${props => + props.active ? props.theme.brand.alt : props.theme.text.reverse}; + background: ${props => + props.active ? props.theme.text.reverse : props.theme.warn.alt}; +`; + +export const LockedTextPill = styled(StatusPill)` color: ${props => props.active ? props.theme.brand.alt : props.theme.text.alt}; background: ${props => - props.active ? props.theme.text.reverse : props.theme.bg.border}; + props.active ? props.theme.brand.wash : props.theme.bg.border}; `; export const MetaCommunityName = styled(Link)` From 2c0bab8d98168a3ffbdad25d01dc6a1cb62e4844 Mon Sep 17 00:00:00 2001 From: uberbryn Date: Tue, 13 Mar 2018 14:25:29 -0700 Subject: [PATCH 05/22] Changes locked thread copy from frozen. Adds an icon so it's a little more friendly. --- src/components/upsell/index.js | 2 ++ src/components/upsell/style.js | 5 +++++ src/views/thread/index.js | 10 ++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/upsell/index.js b/src/components/upsell/index.js index a926b54e24..5e80273b0c 100644 --- a/src/components/upsell/index.js +++ b/src/components/upsell/index.js @@ -73,10 +73,12 @@ type NullStateProps = { bg?: ?string, heading?: string, copy?: string, + icon?: string, children?: React.Node, }; export const NullState = (props: NullStateProps) => ( + {props.icon && } {props.heading && {props.heading}} {props.copy && {props.copy}} {props.children} diff --git a/src/components/upsell/style.js b/src/components/upsell/style.js index 4e3cddb352..3dcacbec04 100644 --- a/src/components/upsell/style.js +++ b/src/components/upsell/style.js @@ -133,6 +133,11 @@ export const NullCol = styled(FlexCol)` align-items: center; position: relative; align-self: center; + + > div { + color: ${props => props.theme.text.alt}; + margin-bottom: 8px; + } `; export const NullRow = styled(FlexRow)` diff --git a/src/views/thread/index.js b/src/views/thread/index.js index 16a0510760..1102ce9999 100644 --- a/src/views/thread/index.js +++ b/src/views/thread/index.js @@ -414,7 +414,10 @@ class ThreadContainer extends React.Component { {!isEditing && isLocked && ( - + )} @@ -490,7 +493,10 @@ class ThreadContainer extends React.Component { {!isEditing && isLocked && ( - + )} From 28254d165787e393b2eb85a07ae0517a254bab34 Mon Sep 17 00:00:00 2001 From: uberbryn Date: Tue, 13 Mar 2018 14:33:35 -0700 Subject: [PATCH 06/22] quickfixes a case where contents of the thread bar could overflow bc they were too long for the container --- src/views/thread/components/actionBar.js | 6 +-- src/views/thread/style.js | 49 +++++++++++++++++------- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/views/thread/components/actionBar.js b/src/views/thread/components/actionBar.js index f7593f9025..b6e3fd4090 100644 --- a/src/views/thread/components/actionBar.js +++ b/src/views/thread/components/actionBar.js @@ -150,9 +150,7 @@ class ActionBar extends React.Component { loading={notificationStateLoading} onClick={this.toggleNotification} > - {thread.receiveNotifications - ? 'Following conversation' - : 'Follow conversation'} + {thread.receiveNotifications ? 'Subscribed' : 'Notify me'} ) : ( @@ -162,7 +160,7 @@ class ActionBar extends React.Component { tipText={'Get notified about replies'} tipLocation={'top-right'} > - Follow conversation + Notify me )} diff --git a/src/views/thread/style.js b/src/views/thread/style.js index 2c4e91a2be..da03fe913b 100644 --- a/src/views/thread/style.js +++ b/src/views/thread/style.js @@ -110,8 +110,9 @@ export const ChatInputWrapper = styled(FlexCol)` export const DetailViewWrapper = styled(FlexCol)` background-image: ${({ theme }) => - `linear-gradient(to right, ${theme.bg.wash}, ${theme.bg - .default} 15%, ${theme.bg.default} 85%, ${theme.bg.wash})`}; + `linear-gradient(to right, ${theme.bg.wash}, ${theme.bg.default} 15%, ${ + theme.bg.default + } 85%, ${theme.bg.wash})`}; flex: auto; justify-content: flex-start; align-items: center; @@ -164,7 +165,9 @@ export const ContextRow = styled(FlexRow)` align-content: flex-start; `; -export const EditDone = styled.div`position: relative;`; +export const EditDone = styled.div` + position: relative; +`; export const DropWrap = styled(FlexCol)` width: 32px; @@ -242,12 +245,20 @@ export const Byline = styled.div` font-size: 14px; `; -export const BylineMeta = styled(FlexCol)`margin-left: 12px;`; +export const BylineMeta = styled(FlexCol)` + margin-left: 12px; +`; -export const AuthorAvatar = styled(Avatar)`cursor: pointer;`; +export const AuthorAvatar = styled(Avatar)` + cursor: pointer; +`; -export const AuthorNameLink = styled(Link)`display: flex;`; -export const AuthorNameNoLink = styled.div`display: flex;`; +export const AuthorNameLink = styled(Link)` + display: flex; +`; +export const AuthorNameNoLink = styled.div` + display: flex; +`; export const AuthorName = styled(H3)` font-weight: 500; max-width: 100%; @@ -319,7 +330,9 @@ export const Timestamp = styled.span` } `; -export const Edited = styled(Timestamp)`margin-left: 4px;`; +export const Edited = styled(Timestamp)` + margin-left: 4px; +`; export const ChatWrapper = styled.div` width: 100%; @@ -518,10 +531,16 @@ export const PillLinkPinned = styled.div` `; export const PillLabel = styled.span` - ${props => props.isPrivate && css`position: relative;`}; + ${props => + props.isPrivate && + css` + position: relative; + `}; `; -export const Lock = styled.span`margin-right: 4px;`; +export const Lock = styled.span` + margin-right: 4px; +`; export const PinIcon = styled.span` margin-right: 4px; margin-left: -2px; @@ -556,7 +575,7 @@ export const FollowButton = styled(Button)` &:hover { background: ${props => props.theme.bg.default}; - color: ${props => props.theme.text.default}; + color: ${props => props.theme.brand.alt}; } @media (max-width: 768px) { @@ -696,7 +715,9 @@ export const RelatedCount = styled.p` color: ${props => props.theme.text.alt}; `; -export const Label = styled.p`font-size: 14px;`; +export const Label = styled.p` + font-size: 14px; +`; export const WatercoolerDescription = styled.h4` font-size: 18px; @@ -727,4 +748,6 @@ export const WatercoolerTitle = styled.h3` margin-bottom: 8px; `; -export const WatercoolerAvatar = styled(Avatar)`margin-bottom: 16px;`; +export const WatercoolerAvatar = styled(Avatar)` + margin-bottom: 16px; +`; From 6b6d62f7c44aab34918acfb2e408f79679ac5ee6 Mon Sep 17 00:00:00 2001 From: uberbryn Date: Tue, 13 Mar 2018 14:45:07 -0700 Subject: [PATCH 07/22] Removes tooltips from dropdown menu and moves their content to labels. Reverses mediaquery that was causing duplicate button. Sets appropriate colors for dropdown items in actionbar. --- src/views/thread/components/actionBar.js | 42 ++++++++++-------------- src/views/thread/style.js | 14 ++++++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/views/thread/components/actionBar.js b/src/views/thread/components/actionBar.js index b6e3fd4090..68ef63bd57 100644 --- a/src/views/thread/components/actionBar.js +++ b/src/views/thread/components/actionBar.js @@ -224,19 +224,19 @@ class ActionBar extends React.Component { onClick={this.toggleFlyout} /> - + {thread.receiveNotifications - ? 'Unfollow conversation' - : 'Follow conversation'} + ? 'Subscribed' + : 'Notify me'} @@ -244,12 +244,10 @@ class ActionBar extends React.Component { - + )} @@ -262,15 +260,11 @@ class ActionBar extends React.Component { hoverColor={ isPinned ? 'warn.default' : 'special.default' } - tipText={ - isPinned - ? 'Un-pin thread' - : `Pin in ${thread.community.name}` - } - tipLocation="top-left" onClick={this.props.togglePinThread} > - + )} @@ -278,10 +272,10 @@ class ActionBar extends React.Component { - Change channel + Move thread @@ -293,14 +287,14 @@ class ActionBar extends React.Component { icon={ thread.isLocked ? 'private' : 'private-unlocked' } - hoverColor="space.alt" - tipText={ - thread.isLocked ? 'Unlock chat' : 'Lock chat' + hoverColor={ + thread.isLocked ? 'success.default' : 'warn.alt' } - tipLocation="top-left" onClick={this.props.threadLock} > - + )} @@ -311,9 +305,7 @@ class ActionBar extends React.Component { diff --git a/src/views/thread/style.js b/src/views/thread/style.js index da03fe913b..2746e45c7f 100644 --- a/src/views/thread/style.js +++ b/src/views/thread/style.js @@ -226,10 +226,18 @@ export const FlyoutRow = styled(FlexRow)` } } - ${p => - p.hideBelow && + ${props => + props.hideBelow && + css` + @media (max-width: ${props.hideBelow}px) { + display: none; + } + `}; + + ${props => + props.hideAbove && css` - @media screen and (max-width: ${p.hideBelow}px) { + @media (min-width: ${props.hideAbove}px) { display: none; } `}; From 947b16b2a530f78b89362c44d33c5ca0369e6657 Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Tue, 13 Mar 2018 16:24:41 -0700 Subject: [PATCH 08/22] Log in to sign in copy --- src/components/loginButtonSet/facebook.js | 10 ++-------- src/components/loginButtonSet/github.js | 10 ++-------- src/components/loginButtonSet/google.js | 10 ++-------- src/components/loginButtonSet/index.js | 6 ------ src/components/loginButtonSet/twitter.js | 10 ++-------- src/components/modals/ChatInputLoginModal/index.js | 4 ++-- src/components/upsell/index.js | 2 +- src/views/communityLogin/index.js | 2 +- src/views/login/index.js | 2 +- src/views/splash/nav.js | 4 ++-- src/views/userSettings/index.js | 2 +- 11 files changed, 16 insertions(+), 46 deletions(-) diff --git a/src/components/loginButtonSet/facebook.js b/src/components/loginButtonSet/facebook.js index 48f5181aba..eefb21bf2a 100644 --- a/src/components/loginButtonSet/facebook.js +++ b/src/components/loginButtonSet/facebook.js @@ -5,19 +5,13 @@ import { FacebookButton, Label, A } from './style'; import Icon from '../icons'; export const FacebookSigninButton = (props: ButtonProps) => { - const { - verb = 'Sign in', - href, - preferred, - showAfter, - onClickHandler, - } = props; + const { href, preferred, showAfter, onClickHandler } = props; return ( onClickHandler && onClickHandler('facebook')} href={href}> - + ); diff --git a/src/components/loginButtonSet/github.js b/src/components/loginButtonSet/github.js index 25d79d631e..624d38cba6 100644 --- a/src/components/loginButtonSet/github.js +++ b/src/components/loginButtonSet/github.js @@ -5,19 +5,13 @@ import { GithubButton, Label, A } from './style'; import Icon from '../icons'; export const GithubSigninButton = (props: ButtonProps) => { - const { - verb = 'Sign in', - href, - preferred, - showAfter, - onClickHandler, - } = props; + const { href, preferred, showAfter, onClickHandler } = props; return ( onClickHandler && onClickHandler('github')} href={href}> - + ); diff --git a/src/components/loginButtonSet/google.js b/src/components/loginButtonSet/google.js index 871d9f86b5..f207e249f5 100644 --- a/src/components/loginButtonSet/google.js +++ b/src/components/loginButtonSet/google.js @@ -5,19 +5,13 @@ import { GoogleButton, Label, A } from './style'; import Icon from '../icons'; export const GoogleSigninButton = (props: ButtonProps) => { - const { - verb = 'Sign in', - href, - preferred, - showAfter, - onClickHandler, - } = props; + const { href, preferred, showAfter, onClickHandler } = props; return ( onClickHandler && onClickHandler('google')} href={href}> - + ); diff --git a/src/components/loginButtonSet/index.js b/src/components/loginButtonSet/index.js index 59dcf9b558..5ef5def30f 100644 --- a/src/components/loginButtonSet/index.js +++ b/src/components/loginButtonSet/index.js @@ -32,8 +32,6 @@ class LoginButtonSet extends React.Component { render() { const { redirectPath, location, signinType } = this.props; - const verb = signinType === 'login' ? 'Log in ' : 'Sign in '; - let r; if (location) { const searchObj = queryString.parse(this.props.location.search); @@ -60,7 +58,6 @@ class LoginButtonSet extends React.Component { href={`${SERVER_URL}/auth/twitter${postAuthRedirectPath}`} preferred={nonePreferred ? true : preferredSigninMethod === 'twitter'} showAfter={preferredSigninMethod === 'twitter'} - verb={verb} /> { nonePreferred ? true : preferredSigninMethod === 'facebook' } showAfter={preferredSigninMethod === 'facebook'} - verb={verb} /> { href={`${SERVER_URL}/auth/google${postAuthRedirectPath}`} preferred={nonePreferred ? true : preferredSigninMethod === 'google'} showAfter={preferredSigninMethod === 'google'} - verb={verb} /> { href={`${SERVER_URL}/auth/github${postAuthRedirectPath}`} preferred={nonePreferred ? true : preferredSigninMethod === 'github'} showAfter={preferredSigninMethod === 'github'} - verb={verb} /> ); diff --git a/src/components/loginButtonSet/twitter.js b/src/components/loginButtonSet/twitter.js index 2f032d6825..2ad68f3bab 100644 --- a/src/components/loginButtonSet/twitter.js +++ b/src/components/loginButtonSet/twitter.js @@ -5,19 +5,13 @@ import { TwitterButton, Label, A } from './style'; import Icon from '../icons'; export const TwitterSigninButton = (props: ButtonProps) => { - const { - verb = 'Sign in', - href, - preferred, - showAfter, - onClickHandler, - } = props; + const { href, preferred, showAfter, onClickHandler } = props; return ( onClickHandler && onClickHandler('twitter')} href={href}> - + ); diff --git a/src/components/modals/ChatInputLoginModal/index.js b/src/components/modals/ChatInputLoginModal/index.js index ef7da9c8ee..d3abe4bab4 100644 --- a/src/components/modals/ChatInputLoginModal/index.js +++ b/src/components/modals/ChatInputLoginModal/index.js @@ -32,7 +32,7 @@ class ChatInputLoginModal extends React.Component { /* TODO(@mxstbr): Fix this */ ariaHideApp={false} isOpen={isOpen} - contentLabel={'Log in or sign up'} + contentLabel={'Sign in'} onRequestClose={this.close} shouldCloseOnOverlayClick={true} style={styles} @@ -42,7 +42,7 @@ class ChatInputLoginModal extends React.Component { We pass the closeModal dispatch into the container to attach the action to the 'close' icon in the top right corner of all modals */} - + { Already have an account?{' '} this.toggleSigningIn('login')}> {' '} - Log in + Sign in diff --git a/src/views/communityLogin/index.js b/src/views/communityLogin/index.js index 48db335baf..20e13aa8d6 100644 --- a/src/views/communityLogin/index.js +++ b/src/views/communityLogin/index.js @@ -53,7 +53,7 @@ export class Login extends React.Component { src={community.profilePhoto} /> - Log in to the {community.name} community + Sign in to the {community.name} community {brandedLogin.message && brandedLogin.message.length > 0 ? brandedLogin.message diff --git a/src/views/login/index.js b/src/views/login/index.js index 354a829d44..5492cac5cb 100644 --- a/src/views/login/index.js +++ b/src/views/login/index.js @@ -26,7 +26,7 @@ export class Login extends React.Component { const viewSubtitle = signinType === 'login' - ? "We're happy to see you again - log in below to get back into the conversation!" + ? "We're happy to see you again - sign in below to get back into the conversation!" : 'Spectrum is a place where communities can share, discuss, and grow together. Sign in below to get in on the conversation.'; return ( diff --git a/src/views/splash/nav.js b/src/views/splash/nav.js index c375a1f656..36bbf3d6c1 100644 --- a/src/views/splash/nav.js +++ b/src/views/splash/nav.js @@ -80,7 +80,7 @@ class Nav extends Component { ) : ( - + )} @@ -123,7 +123,7 @@ class Nav extends Component { ) : ( - Log in + Sign in )} diff --git a/src/views/userSettings/index.js b/src/views/userSettings/index.js index ccdd924329..5bf58c7e65 100644 --- a/src/views/userSettings/index.js +++ b/src/views/userSettings/index.js @@ -53,7 +53,7 @@ class UserSettings extends React.Component { Date: Tue, 13 Mar 2018 16:31:37 -0700 Subject: [PATCH 09/22] Make all textareas auto height --- admin/src/components/formElements/style.js | 3 ++- src/components/formElements/style.js | 3 ++- src/components/loginButtonSet/index.js | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/admin/src/components/formElements/style.js b/admin/src/components/formElements/style.js index d16f4c83f5..b50f52a0ac 100644 --- a/admin/src/components/formElements/style.js +++ b/admin/src/components/formElements/style.js @@ -1,5 +1,6 @@ import styled, { css } from 'styled-components'; import { FlexRow, Transition } from '../globals'; +import Textarea from 'react-textarea-autosize'; export const StyledLabel = styled.label` display: flex; @@ -98,7 +99,7 @@ export const StyledInput = styled.input` } `; -export const StyledTextArea = styled.textarea` +export const StyledTextArea = styled(Textarea)` flex: 1 0 auto; width: 100%; background: ${({ theme }) => theme.bg.default}; diff --git a/src/components/formElements/style.js b/src/components/formElements/style.js index 1668c62261..a51a5367e1 100644 --- a/src/components/formElements/style.js +++ b/src/components/formElements/style.js @@ -1,5 +1,6 @@ import styled, { css } from 'styled-components'; import { FlexRow, Transition, hexa, zIndex } from '../globals'; +import Textarea from 'react-textarea-autosize'; export const StyledLabel = styled.label` display: flex; @@ -100,7 +101,7 @@ export const StyledInput = styled.input` } `; -export const StyledTextArea = styled.textarea` +export const StyledTextArea = styled(Textarea)` flex: 1 0 auto; width: 100%; background: ${({ theme }) => theme.bg.default}; diff --git a/src/components/loginButtonSet/index.js b/src/components/loginButtonSet/index.js index 5ef5def30f..633575feb8 100644 --- a/src/components/loginButtonSet/index.js +++ b/src/components/loginButtonSet/index.js @@ -13,7 +13,6 @@ import { GithubSigninButton } from './github'; type Props = { redirectPath: ?string, location: Object, - signinType: string, }; export type ButtonProps = { @@ -30,7 +29,7 @@ class LoginButtonSet extends React.Component { }; render() { - const { redirectPath, location, signinType } = this.props; + const { redirectPath, location } = this.props; let r; if (location) { From dd956a5e0d77e742adffd36f62a666fcfc816cfc Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Tue, 13 Mar 2018 16:45:20 -0700 Subject: [PATCH 10/22] Fix channel auth flow via branded login --- src/components/loginButtonSet/index.js | 1 - src/views/channel/index.js | 8 ++++++-- src/views/communityLogin/index.js | 8 ++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/components/loginButtonSet/index.js b/src/components/loginButtonSet/index.js index 633575feb8..43bee2cd14 100644 --- a/src/components/loginButtonSet/index.js +++ b/src/components/loginButtonSet/index.js @@ -20,7 +20,6 @@ export type ButtonProps = { href: string, preferred: boolean, showAfter: boolean, - verb: ?string, }; class LoginButtonSet extends React.Component { diff --git a/src/views/channel/index.js b/src/views/channel/index.js index 2bfbf875e5..5b0c71a723 100644 --- a/src/views/channel/index.js +++ b/src/views/channel/index.js @@ -124,12 +124,16 @@ class ChannelView extends React.Component { }/${channel.slug}` : `/login?r=${CLIENT_URL}/${channel.community.slug}/${channel.slug}`; + const redirectPath = `${CLIENT_URL}/${channel.community.slug}/${ + channel.slug + }`; + // if the channel is private but the user isn't logged in, redirect to the login page if (!isLoggedIn && channel.isPrivate) { if (channel.community.brandedLogin.isEnabled) { - return ; + return ; } else { - return ; + return ; } } diff --git a/src/views/communityLogin/index.js b/src/views/communityLogin/index.js index 20e13aa8d6..6bd3715503 100644 --- a/src/views/communityLogin/index.js +++ b/src/views/communityLogin/index.js @@ -28,6 +28,7 @@ type Props = { ...$Exact, history: Object, match: Object, + redirectPath: ?string, }; export class Login extends React.Component { @@ -35,7 +36,7 @@ export class Login extends React.Component { this.props.history.push(`/${this.props.match.params.communitySlug}`); }; render() { - const { data: { community }, isLoading } = this.props; + const { data: { community }, isLoading, redirectPath } = this.props; if (community && community.id) { const { brandedLogin } = community; @@ -60,7 +61,10 @@ export class Login extends React.Component { : 'Spectrum is a place where communities can share, discuss, and grow together. Sign in below to get in on the conversation.'} - + By using Spectrum, you agree to our{' '} From 6f2108769e0e6159b277c4a7e2d8e40cd8da075d Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Tue, 13 Mar 2018 16:54:47 -0700 Subject: [PATCH 11/22] Cache and network queries to handle joining and leaving communities --- .../graphql/queries/user/getCurrentUserEverythingFeed.js | 3 +++ shared/graphql/queries/user/getUserCommunityConnection.js | 3 ++- src/views/dashboard/components/communityList.js | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/shared/graphql/queries/user/getCurrentUserEverythingFeed.js b/shared/graphql/queries/user/getCurrentUserEverythingFeed.js index c521a3238d..b20e3bdf89 100644 --- a/shared/graphql/queries/user/getCurrentUserEverythingFeed.js +++ b/shared/graphql/queries/user/getCurrentUserEverythingFeed.js @@ -33,6 +33,9 @@ export const getCurrentUserEverythingQuery = gql` `; const getCurrentUserEverythingOptions = { + options: () => ({ + fetchPolicy: 'cache-and-network', + }), props: ({ ownProps, data: { diff --git a/shared/graphql/queries/user/getUserCommunityConnection.js b/shared/graphql/queries/user/getUserCommunityConnection.js index 5b5cb8a457..0d6fa5001c 100644 --- a/shared/graphql/queries/user/getUserCommunityConnection.js +++ b/shared/graphql/queries/user/getUserCommunityConnection.js @@ -40,12 +40,13 @@ const getUserCommunityConnectionOptions = { variables: { id, }, + fetchPolicy: 'cache-and-network', }), }; export const getCurrentUserCommunityConnection = graphql( getCurrentUserCommunityConnectionQuery, - { options: { fetchPolicy: 'cache-first' } } + { options: { fetchPolicy: 'cache-and-network' } } ); export const getUserCommunityConnection = graphql( diff --git a/src/views/dashboard/components/communityList.js b/src/views/dashboard/components/communityList.js index 4a3f0e2059..b047ddbbe1 100644 --- a/src/views/dashboard/components/communityList.js +++ b/src/views/dashboard/components/communityList.js @@ -68,8 +68,11 @@ class CommunityList extends React.Component { changedActiveCommunity || changedActiveChannel || changedCommunitiesAmount - ) + ) { + console.log('1'); return true; + } + console.log('2'); return false; } @@ -81,6 +84,8 @@ class CommunityList extends React.Component { return bc <= ac ? -1 : 1; }); + console.log('sorted communities render', sortedCommunities); + return ( From 2e9d865f66f6b5cfe5eec86118c0436971483e55 Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 10:32:24 +0100 Subject: [PATCH 12/22] Add danger-plugin-no-console This should help prevent us from shipping console.logs Source for the plugin: https://github.com/withspectrum/danger-plugin-no-console --- dangerfile.js | 3 + .../npm/danger-plugin-no-console_vx.x.x.js | 95 +++++++++++++++++++ package.json | 1 + yarn.lock | 6 ++ 4 files changed, 105 insertions(+) create mode 100644 flow-typed/npm/danger-plugin-no-console_vx.x.x.js diff --git a/dangerfile.js b/dangerfile.js index 7b60d69edb..dd41bc2e77 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -4,6 +4,7 @@ import { warn, fail, message, markdown, schedule, danger } from 'danger'; import yarn from 'danger-plugin-yarn'; import jest from 'danger-plugin-jest'; import noTestShortcuts from 'danger-plugin-no-test-shortcuts'; +import noConsole from 'danger-plugin-no-console'; const APP_FOLDERS = [ 'admin', @@ -64,3 +65,5 @@ jest(); noTestShortcuts({ testFilePredicate: filePath => filePath.endsWith('.test.js'), }); + +schedule(noConsole({ whitelist: ['error'] })); diff --git a/flow-typed/npm/danger-plugin-no-console_vx.x.x.js b/flow-typed/npm/danger-plugin-no-console_vx.x.x.js new file mode 100644 index 0000000000..0a6a630ad4 --- /dev/null +++ b/flow-typed/npm/danger-plugin-no-console_vx.x.x.js @@ -0,0 +1,95 @@ +// flow-typed signature: be735722bffb485a8cf54a7c7080821a +// flow-typed version: <>/danger-plugin-no-console_v1.x/flow_v0.66.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'danger-plugin-no-console' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'danger-plugin-no-console' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'danger-plugin-no-console/dist/index' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/inherited-summary' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/inner-link' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/manual' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/patch-for-local' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/prettify/prettify' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/pretty-print' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/search_index' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/search' { + declare module.exports: any; +} + +declare module 'danger-plugin-no-console/docs/script/test-summary' { + declare module.exports: any; +} + +// Filename aliases +declare module 'danger-plugin-no-console/dist/index.js' { + declare module.exports: $Exports<'danger-plugin-no-console/dist/index'>; +} +declare module 'danger-plugin-no-console/docs/script/inherited-summary.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/inherited-summary'>; +} +declare module 'danger-plugin-no-console/docs/script/inner-link.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/inner-link'>; +} +declare module 'danger-plugin-no-console/docs/script/manual.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/manual'>; +} +declare module 'danger-plugin-no-console/docs/script/patch-for-local.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/patch-for-local'>; +} +declare module 'danger-plugin-no-console/docs/script/prettify/prettify.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/prettify/prettify'>; +} +declare module 'danger-plugin-no-console/docs/script/pretty-print.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/pretty-print'>; +} +declare module 'danger-plugin-no-console/docs/script/search_index.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/search_index'>; +} +declare module 'danger-plugin-no-console/docs/script/search.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/search'>; +} +declare module 'danger-plugin-no-console/docs/script/test-summary.js' { + declare module.exports: $Exports<'danger-plugin-no-console/docs/script/test-summary'>; +} diff --git a/package.json b/package.json index 67e55256a4..993d337d9c 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "cross-env": "^5.0.5", "danger": "^3.1.8", "danger-plugin-jest": "^1.1.0", + "danger-plugin-no-console": "^1.0.0", "danger-plugin-yarn": "^1.2.1", "eslint": "^4.15.0", "eslint-plugin-flowtype": "^2.39.1", diff --git a/yarn.lock b/yarn.lock index 590df70402..fe2720afdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2801,6 +2801,12 @@ danger-plugin-jest@^1.1.0: optionalDependencies: serve "^5.1.5" +danger-plugin-no-console@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/danger-plugin-no-console/-/danger-plugin-no-console-1.0.0.tgz#7ba7107cbc28cc72c0ae5d0c359056364c31cd23" + optionalDependencies: + esdoc "^0.5.2" + danger-plugin-no-test-shortcuts@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/danger-plugin-no-test-shortcuts/-/danger-plugin-no-test-shortcuts-2.0.0.tgz#02dbb72455819454d36cd5952e2ff0f47df810da" From c2acb6645e90327e109f621bcbeaf19bbe3d21ec Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 10:33:19 +0100 Subject: [PATCH 13/22] Add file with console.log This is a test for the danger-plugin-no-console --- shared/cookie-utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/cookie-utils.js b/shared/cookie-utils.js index 7ecf6317c8..b3d7f2cc4e 100644 --- a/shared/cookie-utils.js +++ b/shared/cookie-utils.js @@ -4,6 +4,8 @@ import jwt from 'jsonwebtoken'; export const cookieKeygrip = new Keygrip([process.env.SESSION_COOKIE_SECRET]); +console.log('danger should fail this commit'); + export const getCookies = ({ userId }: { userId: string }) => { // The value of our "session" cookie const session = new Buffer( From 92c908eaebd36ad3b7f370bbfaca21a8ac1837fd Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 10:44:36 +0100 Subject: [PATCH 14/22] Remove console.log --- shared/cookie-utils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/shared/cookie-utils.js b/shared/cookie-utils.js index b3d7f2cc4e..7ecf6317c8 100644 --- a/shared/cookie-utils.js +++ b/shared/cookie-utils.js @@ -4,8 +4,6 @@ import jwt from 'jsonwebtoken'; export const cookieKeygrip = new Keygrip([process.env.SESSION_COOKIE_SECRET]); -console.log('danger should fail this commit'); - export const getCookies = ({ userId }: { userId: string }) => { // The value of our "session" cookie const session = new Buffer( From 8e76f1600bdde2f8bec6a492cae87ec675e87227 Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 14:33:26 +0100 Subject: [PATCH 15/22] Add danger-plugin-flow This will put a warning in a PR with every touched file (i.e. every file that was either modified or added) that doesn't have a `@flow` pragma at the top of it to ensure we stay on top of our typing! --- dangerfile.js | 8 +++++ flow-typed/npm/danger-plugin-flow_vx.x.x.js | 39 +++++++++++++++++++++ package.json | 1 + yarn.lock | 10 +++++- 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 flow-typed/npm/danger-plugin-flow_vx.x.x.js diff --git a/dangerfile.js b/dangerfile.js index 7b60d69edb..c0324a412a 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -3,6 +3,7 @@ import path from 'path'; import { warn, fail, message, markdown, schedule, danger } from 'danger'; import yarn from 'danger-plugin-yarn'; import jest from 'danger-plugin-jest'; +import flow from 'danger-plugin-flow'; import noTestShortcuts from 'danger-plugin-no-test-shortcuts'; const APP_FOLDERS = [ @@ -64,3 +65,10 @@ jest(); noTestShortcuts({ testFilePredicate: filePath => filePath.endsWith('.test.js'), }); + +schedule( + flow({ + // Don't fail the build, only warn the submitter + warn: true, + }) +); diff --git a/flow-typed/npm/danger-plugin-flow_vx.x.x.js b/flow-typed/npm/danger-plugin-flow_vx.x.x.js new file mode 100644 index 0000000000..271c742ab7 --- /dev/null +++ b/flow-typed/npm/danger-plugin-flow_vx.x.x.js @@ -0,0 +1,39 @@ +// flow-typed signature: 45f3a6b6919397f3ea67b75c1a9601bf +// flow-typed version: <>/danger-plugin-flow_vx.x.x/flow_v0.66.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'danger-plugin-flow' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'danger-plugin-flow' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'danger-plugin-flow/dist/index' { + declare module.exports: any; +} + +declare module 'danger-plugin-flow/dist/index.test' { + declare module.exports: any; +} + +// Filename aliases +declare module 'danger-plugin-flow/dist/index.js' { + declare module.exports: $Exports<'danger-plugin-flow/dist/index'>; +} +declare module 'danger-plugin-flow/dist/index.test.js' { + declare module.exports: $Exports<'danger-plugin-flow/dist/index.test'>; +} diff --git a/package.json b/package.json index 67e55256a4..b83adfb40c 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "cookie-session": "^2.0.0-beta.3", "cors": "^2.8.3", "css.escape": "^1.5.1", + "danger-plugin-flow": "^1.1.0", "danger-plugin-no-test-shortcuts": "^2.0.0", "dataloader": "^1.3.0", "debounce": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index 590df70402..4b9cdbf3cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2793,6 +2793,14 @@ damerau-levenshtein@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" +danger-plugin-flow@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/danger-plugin-flow/-/danger-plugin-flow-1.1.0.tgz#201289346c1dbc99edd436cfa51e2b69024043ef" + dependencies: + micromatch "^3.1.9" + optionalDependencies: + esdoc "^0.5.2" + danger-plugin-jest@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/danger-plugin-jest/-/danger-plugin-jest-1.1.0.tgz#9b53e14a0483e6de5a65f8d58fbb6a8121a948d4" @@ -7401,7 +7409,7 @@ micromatch@^2.1.5, micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.0.4, micromatch@^3.1.4: +micromatch@^3.0.4, micromatch@^3.1.4, micromatch@^3.1.9: version "3.1.9" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89" dependencies: From 23f930443f52763d31e3c1c098cad3cc0a26d072 Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 14:36:35 +0100 Subject: [PATCH 16/22] Add untyped file to make danger fail --- src/untyped-file.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/untyped-file.js diff --git a/src/untyped-file.js b/src/untyped-file.js new file mode 100644 index 0000000000..a4b2d85dac --- /dev/null +++ b/src/untyped-file.js @@ -0,0 +1 @@ +console.log('no flow pragma here!'); From 10d0cb03c625695070478e26a6ad80026c27928f Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 14:45:13 +0100 Subject: [PATCH 17/22] Fix checkbox autolabelling --- dangerfile.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dangerfile.js b/dangerfile.js index c0324a412a..28f39e338c 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -18,7 +18,7 @@ const APP_FOLDERS = [ 'src', 'vulcan', ]; -const CHECKBOXES = /^- \[x\] *(.*)?$/gim; +const CHECKBOXES = /^\s*-\s*\[x\]\s*(.+?)$/gim; const possibleAutoLabels = { wip: 'WIP: Building', 'needs testing': 'WIP: Needs Testing', @@ -37,10 +37,13 @@ schedule(async () => { const checkedBoxes = pr.body.match(CHECKBOXES); if (!checkedBoxes || checkedBoxes.length === 0) return; - const matches = checkedBoxes.map(result => result[1]); + const matches = checkedBoxes + .map(result => new RegExp(CHECKBOXES.source, 'mi').exec(result)) + .filter(Boolean) + .map(res => res[1]); - const matchingLabels = matches.filter(match => - Object.keys(possibleAutoLabels).includes(match.toLowerCase()) + const matchingLabels = matches.filter( + match => Object.keys(possibleAutoLabels).indexOf(match.toLowerCase()) > -1 ); if (!matchingLabels || matchingLabels.length === 0) return; From 3f8946354fbbd91657c3105f37075f62fdc279ee Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 14:46:34 +0100 Subject: [PATCH 18/22] Add flow-typed to blacklist --- dangerfile.js | 1 + src/untyped-file.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/untyped-file.js diff --git a/dangerfile.js b/dangerfile.js index 28f39e338c..9978b95fbb 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -73,5 +73,6 @@ schedule( flow({ // Don't fail the build, only warn the submitter warn: true, + blacklist: ['flow-typed/**/*.js', 'public/**/*.js'], }) ); diff --git a/src/untyped-file.js b/src/untyped-file.js deleted file mode 100644 index a4b2d85dac..0000000000 --- a/src/untyped-file.js +++ /dev/null @@ -1 +0,0 @@ -console.log('no flow pragma here!'); From d439e6bac305f21737902f9f0829a8a38ad94db9 Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 15:16:50 +0100 Subject: [PATCH 19/22] Fix auto-labelling --- dangerfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dangerfile.js b/dangerfile.js index 9978b95fbb..342471fa61 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -32,9 +32,9 @@ if (danger.github.pr.body.length < 10) { // Add automatic labels to the PR schedule(async () => { - const pr = danger.github.pr; + const pr = danger.github.thisPR; const api = danger.github.api; - const checkedBoxes = pr.body.match(CHECKBOXES); + const checkedBoxes = danger.github.pr.body.match(CHECKBOXES); if (!checkedBoxes || checkedBoxes.length === 0) return; const matches = checkedBoxes From 5fd0fc2f3a2daf0c2201a78dfc7062716ad537f4 Mon Sep 17 00:00:00 2001 From: Maximilian Stoiber Date: Wed, 14 Mar 2018 15:19:02 +0100 Subject: [PATCH 20/22] Add contributing.md and explain auto labelling --- CONTRIBUTING.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..6b9cb05220 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing + +## Auto labelling + +The PR template contains a section that looks something like this: + +``` + +``` + +If you check one of these boxes the corresponding label will automatically be applied to the PR by our bot. For example ticking "WIP" will assign the "WIP: Building" label: + + +``` +- [x] WIP +``` From 4dec8841e31f8581d85806b6276533086c7a517c Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Wed, 14 Mar 2018 11:31:17 -0700 Subject: [PATCH 21/22] Remove console logs --- src/views/dashboard/components/communityList.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/views/dashboard/components/communityList.js b/src/views/dashboard/components/communityList.js index b047ddbbe1..ece66f8b59 100644 --- a/src/views/dashboard/components/communityList.js +++ b/src/views/dashboard/components/communityList.js @@ -69,10 +69,8 @@ class CommunityList extends React.Component { changedActiveChannel || changedCommunitiesAmount ) { - console.log('1'); return true; } - console.log('2'); return false; } @@ -84,8 +82,6 @@ class CommunityList extends React.Component { return bc <= ac ? -1 : 1; }); - console.log('sorted communities render', sortedCommunities); - return ( From 1161f68021ceced21392be9f740869b8251c736f Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Wed, 14 Mar 2018 12:23:15 -0700 Subject: [PATCH 22/22] Update danger version --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b83adfb40c..1e7ce2a865 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "cookie-session": "^2.0.0-beta.3", "cors": "^2.8.3", "css.escape": "^1.5.1", - "danger-plugin-flow": "^1.1.0", + "danger-plugin-flow": "^1.2.1", "danger-plugin-no-test-shortcuts": "^2.0.0", "dataloader": "^1.3.0", "debounce": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index 4b9cdbf3cd..f0b91e7ac2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2793,9 +2793,9 @@ damerau-levenshtein@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" -danger-plugin-flow@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/danger-plugin-flow/-/danger-plugin-flow-1.1.0.tgz#201289346c1dbc99edd436cfa51e2b69024043ef" +danger-plugin-flow@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/danger-plugin-flow/-/danger-plugin-flow-1.2.1.tgz#0f1e77aaf82887cc60adca4bb512c6efa0c4e1bc" dependencies: micromatch "^3.1.9" optionalDependencies: