Skip to content
This repository was archived by the owner on Oct 11, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0d4cac9
Hacky plaintext chatinput
Dec 14, 2018
97c9fbf
Update to latest React
Dec 14, 2018
84eb575
Rewrite chat input with hooks
Dec 14, 2018
ed08f6b
Add support for sending DM thread messages and creating new DM threads
Dec 14, 2018
26c7124
Quoted message support
Dec 14, 2018
160e813
Make media messages work
Dec 14, 2018
1eff87e
"Blur" optimistic responses"
Dec 17, 2018
dad3f36
Revert ""Blur" optimistic responses""
Dec 17, 2018
7a7ba8d
Parse markdown to draftjs in optimistic responses
Dec 17, 2018
2e9d461
Add localStorage persistance of latest chatInput content
Dec 18, 2018
603434f
Fix dm thread creation
Dec 18, 2018
6be1f93
Switch to same markdown draftjs conversion library on backend
Dec 18, 2018
16afe50
Merge branch 'alpha' into plaintext-spike
Dec 18, 2018
2d2b676
Add missing dep to api
Dec 18, 2018
255ac28
Merge branch 'alpha' of github.com:withspectrum/spectrum into plainte…
brianlovin Dec 18, 2018
9e3e8ca
Silence flow errors on new react features
brianlovin Dec 18, 2018
4711c0e
Fix chatInput focussing
Dec 19, 2018
abda1d4
Fix sending plaintext messages
Dec 19, 2018
359e601
Remove unnecessary double-read of attached media
Dec 19, 2018
460fa50
Resolve React warnings
Dec 19, 2018
d8e9cc8
Fix creating new DM thread
Dec 19, 2018
7f6388c
Revert "Fix creating new DM thread"
Dec 19, 2018
71350d7
Merge branch 'alpha' into plaintext-spike
Dec 19, 2018
d16b5c2
Fix flow
Dec 19, 2018
2b54407
Merge alpha and fix conflicts
brianlovin Dec 19, 2018
60c3465
Better network disabled styling on input
brianlovin Dec 19, 2018
e74d018
Fix styling if quote-replying and uploading media at same time
brianlovin Dec 19, 2018
d1c4909
Focus chatinput on quote message click
Dec 21, 2018
3a59362
Fix media messages arriving after text messages
Dec 21, 2018
0df7df4
Handle websocket connection states
Dec 21, 2018
58b4404
Fix flow
Jan 7, 2019
4cb998b
Remove unused variables from chatInput
Jan 7, 2019
3bfb20c
Explicitly target chat input from e2e tests
Jan 7, 2019
0c9f8b8
Move data-cy="chat-input" to actual input
Jan 7, 2019
890a715
Merge branch 'alpha' into plaintext-spike
Jan 7, 2019
b4fc98d
Use .clear() instead of .type() in e2e tests
Jan 7, 2019
243d2c7
Remove .only in thread_spec, fix /new/thread tests
Jan 7, 2019
a327a86
Upgrade to draft-js-import-markdown@latest to fix code blocks
Jan 8, 2019
721dfb7
Make plaintext message editing work
Jan 8, 2019
6a7c792
edit in plaintext on the frontend
Jan 8, 2019
10ceda8
Fix flow
Jan 8, 2019
06a2f9e
Fix editing e2e test
Jan 8, 2019
6d7d814
Match input font weight to rendered message font weight
brianlovin Jan 8, 2019
3adc352
Remove invalid dataCy dom node property
brianlovin Jan 8, 2019
f62c8c6
Change editor to allow multiline messages
brianlovin Jan 8, 2019
156ceb7
Remove empty line while editing
Jan 9, 2019
470bae2
Fix incorrect focussing on chat input while editing message
Jan 9, 2019
7b51155
Make single line breaks work!
Jan 10, 2019
1d59e09
Focus the edit message input when edit message button is clicked
brianlovin Jan 11, 2019
af78603
Fenced code blocks while editing
Jan 14, 2019
d6fbf52
Merge branch 'alpha' into plaintext-spike
Jan 14, 2019
7888aaf
Merge branch 'alpha' into plaintext-spike
Jan 15, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions api/mutations/message/addMessage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import { markdownToDraft } from 'markdown-draft-js';
import { stateFromMarkdown } from 'draft-js-import-markdown';
import { convertToRaw } from 'draft-js';
import type { GraphQLContext } from '../../';
import UserError from '../../utils/UserError';
import { uploadImage } from '../../utils/file-storage';
Expand Down Expand Up @@ -87,7 +88,13 @@ export default requireAuth(async (_: any, args: Input, ctx: GraphQLContext) => {

if (message.messageType === 'text') {
message.content.body = JSON.stringify(
markdownToDraft(message.content.body)
convertToRaw(
stateFromMarkdown(message.content.body, {
parserOptions: {
breaks: true,
},
})
)
);
message.messageType = 'draftjs';
}
Expand Down
90 changes: 86 additions & 4 deletions api/mutations/message/editMessage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// @flow
import type { GraphQLContext } from '../../';
import { convertToRaw } from 'draft-js';
import { stateFromMarkdown } from 'draft-js-import-markdown';
import UserError from '../../utils/UserError';
import {
getMessage,
Expand All @@ -18,6 +20,7 @@ import { trackQueue } from 'shared/bull/queues';
type Args = {
input: {
id: string,
messageType?: 'draftjs' | 'text' | 'media',
content: {
body: string,
},
Expand All @@ -26,7 +29,7 @@ type Args = {

export default requireAuth(async (_: any, args: Args, ctx: GraphQLContext) => {
const {
input: { id, content },
input: { id, content, messageType },
} = args;
const { user, loaders } = ctx;

Expand All @@ -43,15 +46,85 @@ export default requireAuth(async (_: any, args: Args, ctx: GraphQLContext) => {
return new UserError('This message does not exist.');
}

if (content.body === message.content.body) {
return message;
let body = content.body;
if (messageType === 'text') {
body = JSON.stringify(
convertToRaw(
stateFromMarkdown(body, {
parserOptions: {
breaks: true,
},
})
)
);
messageType === 'draftjs';
}

const eventFailed =
message.threadType === 'story'
? events.MESSAGE_EDITED_FAILED
: events.DIRECT_MESSAGE_EDITED_FAILED;

if (messageType === 'draftjs') {
let parsed;
try {
parsed = JSON.parse(body);
} catch (err) {
trackQueue.add({
userId: user.id,
event: eventFailed,
properties: {
reason: 'invalid draftjs data',
message,
},
});

return new UserError(
'Please provide serialized raw DraftJS content state as content.body'
);
}
if (!parsed.blocks || !Array.isArray(parsed.blocks) || !parsed.entityMap) {
trackQueue.add({
userId: user.id,
event: eventFailed,
properties: {
reason: 'invalid draftjs data',
message,
},
});

return new UserError(
'Please provide serialized raw DraftJS content state as content.body'
);
}
if (
parsed.blocks.some(
({ type }) =>
!type ||
(type !== 'unstyled' &&
type !== 'code-block' &&
type !== 'blockquote')
)
) {
trackQueue.add({
userId: user.id,
event: eventFailed,
properties: {
reason: 'invalid draftjs data',
message,
},
});

return new UserError(
'Invalid DraftJS block type specified. Supported block types: "unstyled", "code-block".'
);
}
}

if (body === message.content.body) {
return message;
}

if (message.senderId !== user.id) {
trackQueue.add({
userId: user.id,
Expand All @@ -65,5 +138,14 @@ export default requireAuth(async (_: any, args: Args, ctx: GraphQLContext) => {
return new UserError('You can only edit your own messages.');
}

return editMessage(args.input, user.id);
return editMessage(
{
...args.input,
content: {
body,
},
messageType,
},
user.id
);
});
8 changes: 6 additions & 2 deletions api/mutations/thread/publishThread.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow
const debug = require('debug')('api:mutations:thread:publish-thread');
import stringSimilarity from 'string-similarity';
import { markdownToDraft } from 'markdown-draft-js';
import { stateFromMarkdown } from 'draft-js-import-markdown';
import type { GraphQLContext } from '../../';
import UserError from '../../utils/UserError';
import { uploadImage } from '../../utils/file-storage';
Expand Down Expand Up @@ -71,7 +71,11 @@ export default requireAuth(
type = 'DRAFTJS';
if (thread.content.body) {
thread.content.body = JSON.stringify(
markdownToDraft(thread.content.body)
stateFromMarkdown(thread.content.body, {
parserOptions: {
breaks: true,
},
})
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"draft-js-embed-plugin": "^1.2.0",
"draft-js-focus-plugin": "2.0.0-rc2",
"draft-js-image-plugin": "2.0.0-rc8",
"draft-js-import-markdown": "^1.2.3",
"draft-js-linkify-plugin": "^2.0.0-beta1",
"draft-js-markdown-plugin": "^1.4.4",
"draft-js-plugins-editor": "^2.1.1",
Expand Down Expand Up @@ -76,7 +77,6 @@
"lodash": "^4.17.11",
"lodash.intersection": "^4.4.0",
"longjohn": "^0.2.12",
"markdown-draft-js": "^0.6.3",
"moment": "^2.23.0",
"node-env-file": "^0.1.8",
"node-localstorage": "^1.3.1",
Expand Down
1 change: 1 addition & 0 deletions api/types/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const Message = /* GraphQL */ `

input EditMessageInput {
id: ID!
messageType: MessageTypes!
content: MessageContentInput
}

Expand Down
35 changes: 27 additions & 8 deletions api/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3495,6 +3495,22 @@ draft-js-image-plugin@2.0.0-rc8:
prop-types "^15.5.8"
union-class-names "^1.0.0"

draft-js-import-element@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/draft-js-import-element/-/draft-js-import-element-1.2.1.tgz#9a6a56d74690d48d35d8d089564e6d710b4926eb"
integrity sha512-T/eCDkaU8wrTCH6c+/2BE7Vx/11GABRNU/UBiHM4D903LNFar8UfjElehpiKVf+F4rxi8dfhvTgaWrpWDfX4MA==
dependencies:
draft-js-utils "^1.2.0"
synthetic-dom "^1.2.0"

draft-js-import-markdown@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/draft-js-import-markdown/-/draft-js-import-markdown-1.2.3.tgz#71ffc8eee1530f0349c22273681fbcb3c659c0c0"
integrity sha512-NPcXwWSsIA+uwASzdJWLQM4y+xW1vTDtDdIDHCHfP76i9cx8zYpH75GW8Ezz8L9SW2qetNcFW056Hj2yxRZ+2g==
dependencies:
draft-js-import-element "^1.2.1"
synthetic-dom "^1.2.0"

draft-js-linkify-plugin@^2.0.0-beta1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/draft-js-linkify-plugin/-/draft-js-linkify-plugin-2.0.1.tgz#28978b53640ce64c639cd2821a54c24de9f79c3f"
Expand Down Expand Up @@ -3570,6 +3586,11 @@ draft-js-prism@ngs/draft-js-prism#6edb31c3805dd1de3fb897cc27fced6bac1bafbb:
immutable "*"
prismjs "^1.5.0"

draft-js-utils@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/draft-js-utils/-/draft-js-utils-1.2.0.tgz#f5cb23eb167325ffed3d79882fdc317721d2fd12"
integrity sha1-9csj6xZzJf/tPXmIL9wxdyHS/RI=

draft-js@0.x, draft-js@^0.10.4, draft-js@^0.10.5, draft-js@~0.10.0:
version "0.10.5"
resolved "https://registry.yarnpkg.com/draft-js/-/draft-js-0.10.5.tgz#bfa9beb018fe0533dbb08d6675c371a6b08fa742"
Expand Down Expand Up @@ -6376,13 +6397,6 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"

markdown-draft-js@^0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/markdown-draft-js/-/markdown-draft-js-0.6.3.tgz#5847cd3d07d7b7e3d4d87c5d7e5928c3a71bddd4"
integrity sha512-8kn53iDi9M+0jOeF5dXc2vy8tCkrcD/QlltOz9GErenWrJD+VJ5ZFRjjmPVk7TnE8f5R0DiGCDL/w8M2Lj7xQw==
dependencies:
remarkable "1.7.1"

math-random@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac"
Expand Down Expand Up @@ -8137,7 +8151,7 @@ regjsparser@^0.6.0:
dependencies:
jsesc "~0.5.0"

remarkable@1.7.1, remarkable@^1.x:
remarkable@^1.x:
version "1.7.1"
resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.1.tgz#aaca4972100b66a642a63a1021ca4bac1be3bff6"
integrity sha1-qspJchALZqZCpjoQIcpLrBvjv/Y=
Expand Down Expand Up @@ -9024,6 +9038,11 @@ symbol-tree@^3.2.1:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=

synthetic-dom@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/synthetic-dom/-/synthetic-dom-1.2.0.tgz#f3589aafe2b5e299f337bb32973a9be42dd5625e"
integrity sha1-81iar+K14pnzN7sylzqb5C3VYl4=

table@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc"
Expand Down
10 changes: 5 additions & 5 deletions cypress/integration/messages_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ describe('/messages/new', () => {

it('should allow to continue composing message incase of crash or reload', () => {
const newMessage = 'Persist New Message';
cy.get('[contenteditable="true"]').type(newMessage);
cy.get('[contenteditable="true"]').contains(newMessage);
cy.get('[data-cy="chat-input"]').type(newMessage);
cy.get('[data-cy="chat-input"]').contains(newMessage);

cy.wait(2000);
// Reload page(incase page closed or crashed ,reload should have same effect)
cy.reload();
cy.get('[contenteditable="true"]').contains(newMessage);
cy.get('[data-cy="chat-input"]').contains(newMessage);
});
});

Expand Down Expand Up @@ -86,9 +86,9 @@ describe('/messages', () => {
.click();

const newMessage = 'A new message!';
cy.get('[contenteditable="true"]').type(newMessage);
cy.get('[data-cy="chat-input"]').type(newMessage);
cy.get('[data-cy="chat-input-send-button"]').click();
cy.get('[contenteditable="true"]').type('');
cy.get('[data-cy="chat-input"]').clear();
cy.contains(newMessage);

cy.get('[data-cy="unread-dm-list-item"]').should($p => {
Expand Down
10 changes: 5 additions & 5 deletions cypress/integration/thread/chat_input_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,25 @@ describe('chat input', () => {
it('should allow authed members to send messages', () => {
const newMessage = 'A new message!';
cy.get('[data-cy="thread-view"]').should('be.visible');
cy.get('[contenteditable="true"]').type(newMessage);
cy.get('[data-cy="chat-input"]').type(newMessage);
// Wait for the messages to be loaded before sending new message
cy.get('[data-cy="message-group"]').should('be.visible');
cy.get('[data-cy="chat-input-send-button"]').click();
// Clear the chat input and make sure the message was sent by matching the text
cy.get('[contenteditable="true"]').type('');
cy.get('[data-cy="chat-input"]').clear();
cy.contains(newMessage);
});

it('should allow chat input to be maintained', () => {
const newMessage = 'Persist New Message';
cy.get('[data-cy="thread-view"]').should('be.visible');
cy.get('[contenteditable="true"]').type(newMessage);
cy.get('[contenteditable="true"]').contains(newMessage);
cy.get('[data-cy="chat-input"]').type(newMessage);
cy.get('[data-cy="chat-input"]').contains(newMessage);
cy.get('[data-cy="message-group"]').should('be.visible');
cy.wait(1000);
// Reload page(incase page closed or crashed ,reload should have same effect)
cy.reload();
cy.get('[contenteditable="true"]').contains(newMessage);
cy.get('[data-cy="chat-input"]').contains(newMessage);
});
});

Expand Down
12 changes: 6 additions & 6 deletions cypress/integration/thread_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ describe('Thread View', () => {
it('should allow logged-in users to send public messages', () => {
const newMessage = 'A new message!';
cy.get('[data-cy="thread-view"]').should('be.visible');
cy.get('[contenteditable="true"]').type(newMessage);
cy.get('[data-cy="chat-input"]').type(newMessage);
// Wait for the messages to be loaded before sending new message
cy.get('[data-cy="message-group"]').should('be.visible');
cy.get('[data-cy="chat-input-send-button"]').click();
// Clear the chat input and make sure the message was sent by matching the text
cy.get('[contenteditable="true"]').type('');
cy.get('[data-cy="chat-input"]').clear();
cy.contains(newMessage);
});
});
Expand All @@ -101,10 +101,10 @@ describe('Thread View', () => {
it('should allow logged-in users to send private messages if they have permission', () => {
const newMessage = 'A new private message!';
cy.get('[data-cy="thread-view"]').should('be.visible');
cy.get('[contenteditable="true"]').type(newMessage);
cy.get('[data-cy="chat-input"]').type(newMessage);
cy.get('[data-cy="chat-input-send-button"]').click();
// Clear the chat input and make sure the message was sent by matching the text
cy.get('[contenteditable="true"]').type('');
cy.get('[data-cy="chat-input"]').clear();
cy.contains(newMessage);
});
});
Expand Down Expand Up @@ -430,7 +430,7 @@ describe('edit message signed in', () => {
.click({ force: true });

cy.get('[data-cy="edit-message-input"]');
cy.get('[contenteditable="true"]').type(' with edits');
cy.get('[data-cy="editing-chat-input"]').type(' with edits');

cy.get('[data-cy="edit-message-save"]').click();

Expand All @@ -443,7 +443,7 @@ describe('edit message signed in', () => {
});
});

describe.only('/new/thread', () => {
describe('/new/thread', () => {
beforeEach(() => {
cy.auth(author.id).then(() => cy.visit('/new/thread'));
});
Expand Down
Loading