Skip to content

Commit f1026b7

Browse files
author
hackape
committed
Accept Merge Request #10 协作相关改动:(yangzhen/ot -> ot)
Merge Request: 协作相关改动 Created By: @杨臻
2 parents cbef9d0 + 74b01c4 commit f1026b7

39 files changed

+392
-69
lines changed

app/backendAPI/collaborationAPI.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,15 @@ export function postCollaborators (inviteKey) {
1414
export function deleteCollaborators (id) {
1515
return request.delete(`/workspaces/${config.spaceKey}/collaborators/${id}`)
1616
}
17+
18+
export function requestCollaborator () {
19+
return request.post(`/workspaces/${config.spaceKey}/collaborator/request`)
20+
}
21+
22+
export function fetchRqeuestState () {
23+
return request.get(`/workspaces/${config.spaceKey}/collaborator/request`)
24+
}
25+
26+
export function rejectCollaborator (id) {
27+
return request.post(`/workspaces/${config.spaceKey}/collaborators/${id}/reject`)
28+
}

app/backendAPI/workspaceAPI.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function getUserProfile () {
4747
// return request.get('/user/current').then(res => res.data)
4848
return request.get('/user/current', null,
4949
{ headers: { Accept: '*/*' } }
50-
).then(res => res.data)
50+
)
5151
}
5252

5353
export function findSpaceKey ({ ownerName, projectName }) {

app/commons/Tree/TreeNode.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ class TreeNode extends Component {
3636
<span className="filetree-node-icon">
3737
<i className={cx({
3838
'fa fa-briefcase': node.isRoot,
39-
'fa fa-folder-o': node.isDir && !node.isRoot,
39+
'fa fa-folder-o': node.isDir && !node.isRoot && node.isFolded,
40+
'fa fa-folder-open-o': node.isDir && !node.isRoot && !node.isFolded,
4041
'fa fa-file-o': !node.isDir
4142
})}></i>
4243
</span>

app/components/Collaboration/Chat.jsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ const os = (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerC
1414
const isMac = (os === 'mac')
1515
import indexOf from 'lodash/indexOf'
1616
import calculateNodeHeight from './calculateNodeHeight'
17-
17+
import { i18n } from 'utils'
18+
import settings from 'settings'
19+
const language = settings.general.language
1820
const getTime = (time) => moment(new Date(time)).calendar()//.fromNow()
1921

20-
const ChatItem = observer(({ chat }) => {
22+
const ChatItem = observer(({ chat, language }) => {
2123
const { collaborator, timestamp, message } = chat
2224
const hue = hueFromString(collaborator.collaborator.name)
2325
const [r, g, b] = chroma.hsv2rgb(hue, 1, 0.8)
2426
const color = `rgb(${r},${g},${b})`
27+
const languageValue = language.value
2528
return (
2629
<div className='chat-item' style={{
2730
borderColor: color,
@@ -60,6 +63,13 @@ class Chat extends Component {
6063
componentDidMount () {
6164
CollaborationActions.loadChat()
6265
this.chatManager = new ChatManager()
66+
this.chatManager.subscribeToFsSocket((frame) => {
67+
const data = JSON.parse(frame.body)
68+
const { globalKey, action, spaceKey } = data
69+
if (action === 'Request') {
70+
this.fetchCollaborators()
71+
}
72+
})
6373
this.chatManager.subscribe((data) => {
6474
const { globalKey, message, timestamp } = data
6575
const collaborator = state.collaborators.find(item => item.collaborator.globalKey === globalKey)
@@ -208,7 +218,7 @@ ${message}`
208218
}
209219

210220
render () {
211-
const placeholder = 'Your message here (Shift + Enter to return)'
221+
const placeholder = i18n.get('ot.chatPlaceHolder')
212222
const pickStyle = {
213223
visibility: 'hidden'
214224
}
@@ -219,11 +229,12 @@ ${message}`
219229
<div className='collaboration-chat'>
220230
<ScrollToBottom className='chat-content' chatCount={this.state.chatCount}>
221231
{
222-
state.chatList.map(chat => <ChatItem chat={chat} key={chat.timestamp} />)
232+
state.chatList.map(chat => <ChatItem chat={chat} key={chat.timestamp} language={language} />)
223233
}
224234
</ScrollToBottom>
225-
<div className='chat-editor'>
235+
{state.collaborators.length > 0 && <div className='chat-editor'>
226236
<textarea
237+
className='form-control'
227238
ref={dom => this.textarea = dom}
228239
onClick={this.handleHidePicker}
229240
placeholder={placeholder}
@@ -244,6 +255,7 @@ ${message}`
244255
</div>
245256
</div>
246257
</div>
258+
}
247259
{
248260
<Picker style={pickStyle} autoFocus set='emojione' emojiSize={16} native onClick={this.handleEmojiClick} title='Coding IDE' />
249261
}

app/components/Collaboration/Collaborators.jsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@ import config from 'config'
77
import * as Modal from 'components/Modal/actions'
88
import { hueFromString, chroma } from 'utils/colors'
99

10-
const Collaborator = observer(({ item, handleDelete, handleQuit, isOwner, handleOpenFile }) => {
10+
const Collaborator = observer(({ item, handleDelete, handleQuit, isOwner, handleOpenFile, handleReject, handleAdd }) => {
1111
const { collaborator, id } = item
1212
let info = ''
1313
if (item.inviteBy === 'Owner') {
1414
info = (
1515
<div className='info-owner'>Owner</div>
1616
)
1717
} else if (isOwner) {
18-
info = (
19-
<div className='info-delete' onClick={e => handleDelete(id, collaborator.globalKey)}>Remove</div>
20-
)
18+
if (item.status === 'Request') {
19+
info = (
20+
<div className='info-action'>
21+
<button className='btn btn-default btn-xs' onClick={e => handleAdd(collaborator.globalKey)} >
22+
Accept
23+
</button>
24+
<div className='info-request' onClick={e => handleReject(id, collaborator.globalKey)}>Reject</div>
25+
</div>
26+
)
27+
} else {
28+
info = (
29+
<div className='info-delete' onClick={e => handleDelete(id, collaborator.globalKey)}>Remove</div>
30+
)
31+
}
2132
} else if (config.globalKey === collaborator.globalKey) {
2233
info = (
2334
<div className='info-delete' onClick={e => handleQuit(id, collaborator.globalKey)}>Quit</div>
@@ -73,6 +84,14 @@ class Collaborators extends Component {
7384
CollaborationActions.fetchCollaborators()
7485
}
7586

87+
handleAdd = (globalKey) => {
88+
CollaborationActions.postCollaborators(globalKey)
89+
}
90+
91+
handleReject = (id) => {
92+
CollaborationActions.rejectCollaborator(id)
93+
}
94+
7695
handleDelete = async (id, globalKey) => {
7796
const confirmed = await Modal.showModal('Confirm', {
7897
header: 'Are you sure you want to remove this collaborator?',
@@ -118,6 +137,8 @@ class Collaborators extends Component {
118137
handleQuit={this.handleQuit}
119138
isOwner={isOwner}
120139
handleOpenFile={this.handleOpenFile}
140+
handleAdd={this.handleAdd}
141+
handleReject={this.handleReject}
121142
/>
122143
)
123144
})}

app/components/Collaboration/actions.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,28 @@ import * as TabActions from 'components/Tab/actions'
55
import state from './state'
66
import ChatManager from './ot/chat'
77
import config from 'config'
8+
import remove from 'lodash/remove'
89

910
export const fetchCollaborators = () => {
1011
if (state.loading) return
1112
state.loading = true
12-
return api.fetchCollaborators().then((res) => {
13+
const collaboratorsList = api.fetchCollaborators()
14+
const requestList = api.fetchCollaborators('Request')
15+
return Promise.all([collaboratorsList, requestList]).then(([collaboratorsRes, requestRes]) => {
16+
const res = collaboratorsRes.concat(requestRes)
17+
// return api.fetchCollaborators().then((res) => {
1318
state.collaborators = res.map((item) => {
1419
if (!/^(http|https):\/\/[^ "]+$/.test(item.collaborator.avatar)) {
1520
item.collaborator.avatar = `https://coding.net${item.collaborator.avatar}`
1621
}
1722
const oldItem = state.collaborators.find((c) => c.collaborator.globalKey === item.collaborator.globalKey)
1823
if (oldItem) {
1924
item.online = oldItem.online
25+
item.clientIds = oldItem.clientIds
2026
} else {
2127
item.online = false
28+
item.clientIds = []
2229
}
23-
item.clientIds = []
2430
item.path = ''
2531
const pathItem = state.paths[item.collaborator.globalKey]
2632
if (pathItem) {
@@ -39,6 +45,14 @@ export const fetchInvitedCollaborators = () => {
3945
})
4046
}
4147

48+
export const rejectCollaborator = (id) => {
49+
return api.rejectCollaborator(id).then((res) => {
50+
remove(state.collaborators, (n) => {
51+
return n.id === id
52+
})
53+
})
54+
}
55+
4256
export const postCollaborators = (inviteKey) => {
4357
return api.postCollaborators(inviteKey).then(res => {
4458
const chatManager = new ChatManager()
@@ -80,6 +94,9 @@ export const saveChat = () => {
8094
chatStorage[config.spaceKey] = {}
8195
} else {
8296
chatStorage = JSON.parse(chatStorage)
97+
if (!chatStorage[config.spaceKey]) {
98+
chatStorage[config.spaceKey] = {}
99+
}
83100
}
84101
chatStorage[config.spaceKey][config.globalKey] = currentChatList
85102
localStorage.setItem('chat', JSON.stringify(chatStorage))

app/components/Collaboration/index.jsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Component } from 'react'
22
import { observer } from 'mobx-react'
33
import { observable } from 'mobx'
4+
import { i18n } from 'utils'
45
import { AccordionGroup, Accordion } from '../Accordion/Accordion'
56
import Collaborators from './Collaborators'
67
import Chat from './Chat'
@@ -38,8 +39,9 @@ class Collaboration extends Component {
3839
<Menu className='top-down to-left'
3940
items={[
4041
{
41-
name: 'Clear',
42-
command: this.clearChat
42+
name: i18n`ot.clear`,
43+
command: this.clearChat,
44+
icon: 'fa fa-trash-o'
4345
}
4446
]}
4547
style={{ right: '2px' }}
@@ -52,7 +54,7 @@ class Collaboration extends Component {
5254
let action = null
5355
if (state.isOwner) {
5456
action = (
55-
<div className='accordion-actions' onClick={this.handleInvite}><i className='fa fa-user-plus' /> Invite</div>
57+
<div className='accordion-actions' onClick={this.handleInvite}><i className='fa fa-user-plus' /> {i18n`ot.invite`}</div>
5658
)
5759
}
5860
const chatSetting = (
@@ -64,7 +66,7 @@ class Collaboration extends Component {
6466
return (
6567
<AccordionGroup flexDirection='column'>
6668
<Accordion
67-
header='Collaborators'
69+
header={i18n`ot.collaborators`}
6870
icon='fa fa-users'
6971
size='40'
7072
id='d1'
@@ -73,7 +75,7 @@ class Collaboration extends Component {
7375
<Collaborators />
7476
</Accordion>
7577
<Accordion
76-
header='Group Chat'
78+
header={i18n`ot.groupChat`}
7779
icon='fa fa-comments'
7880
size='40'
7981
id='d2'

app/components/Collaboration/modals/invite.jsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as Modal from '../../Modal/actions'
99
import trim from 'lodash/trim'
1010
import * as CollaborationActions from '../actions'
1111
import state from '../state'
12+
import { i18n } from 'utils'
1213

1314
const UserItem = observer(({ item, handleInvite, handleRemove }) => {
1415
const { inviteKey, id } = item
@@ -23,12 +24,12 @@ const UserItem = observer(({ item, handleInvite, handleRemove }) => {
2324
<div className='remove-btn' onClick={() => {
2425
handleRemove(id)
2526
}}>
26-
remove
27+
{i18n`ot.removeInvite`}
2728
</div>
2829
<div className='invite-btn' onClick={() => {
2930
handleInvite(inviteKey)
3031
}}>
31-
resend
32+
{i18n`ot.resendInvite`}
3233
</div>
3334
</div>
3435
)
@@ -80,20 +81,20 @@ class Invite extends Component {
8081
return (
8182
<div className='invite-container'>
8283
<h2>
83-
Share this workspace
84+
{i18n`ot.shareWS`}
8485
</h2>
8586
<div className='form-group'>
86-
<label>Invite People</label>
87+
<label>{i18n`ot.inviteTitle`}</label>
8788
<div className='form-line'>
8889
<input className='form-control'
8990
type='text'
90-
placeholder='username or email'
91+
placeholder={i18n.get('ot.sharePlaceHolder')}
9192
onChange={this.handleChange}
9293
value={this.state.value}
9394
ref={dom => this.input = dom}
9495
onKeyDown={e => {if (e.keyCode === 13) this.handleInvite(this.state.value)}}
9596
/>
96-
<button disabled={this.state.loading || (!this.state.value)} className="btn btn-default" onClick={e => this.handleInvite(this.state.value)} >Invite</button>
97+
<button disabled={this.state.loading || (!this.state.value)} className="btn btn-default" onClick={e => this.handleInvite(this.state.value)} >{i18n`ot.inviteBtn`}</button>
9798
</div>
9899
{this.state.error && (
99100
<div className='form-line'>
@@ -104,7 +105,7 @@ class Invite extends Component {
104105
)}
105106
</div>
106107
{invited.length > 0 && <div className='form-group'>
107-
<label>Wait for Verify</label>
108+
<label>{i18n`ot.waitVerify`}</label>
108109
<div className='user-list'>
109110
{
110111
invited.map((item, i) => {

app/components/Collaboration/ot/chat.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import WebSocketClient from './WebSocketClient'
22
import config from 'config'
3-
3+
import { autorun } from 'mobx'
4+
import { FsSocketClient } from 'backendAPI/websocketClients'
45

56
export default class ChatManager {
67
constructor () {
@@ -57,4 +58,13 @@ export default class ChatManager {
5758
messageString
5859
)
5960
}
61+
62+
subscribeToFsSocket (fn) {
63+
autorun(() => {
64+
if (!config.fsSocketConnected) return
65+
const client = FsSocketClient.$$singleton.stompClient
66+
67+
client.subscribe(`/topic/collaboration/${config.spaceKey}/collaborators`, fn)
68+
})
69+
}
6070
}

app/components/Collaboration/state.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ const state = observable({
1818
return -1
1919
} else if (b.inviteBy === 'Owner') {
2020
return 1
21+
} else if (a.status === 'Request') {
22+
return -1
23+
} else if (b.status === 'Request') {
24+
return 1
2125
} else {
2226
if (a.online && !b.online) {
2327
return -1

0 commit comments

Comments
 (0)