Merge branch 'note-unread-indicator' of github.com:pedrobmarin/bigbluebutton into locales-8
This commit is contained in:
commit
c79eddf46d
@ -3,7 +3,7 @@ import Logger from '/imports/startup/server/logger';
|
||||
import editCaptions from '/imports/api/captions/server/methods/editCaptions';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
export default function padUpdate(padId, data, revs) {
|
||||
export default function updatePad(padId, data, revs) {
|
||||
check(padId, String);
|
||||
check(data, String);
|
||||
check(revs, Number);
|
||||
|
@ -3,7 +3,7 @@ import { Meteor } from 'meteor/meteor';
|
||||
const Note = new Mongo.Collection('note');
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Note._ensureIndex({ meetingId: 1 });
|
||||
Note._ensureIndex({ meetingId: 1, noteId: 1 });
|
||||
}
|
||||
|
||||
export default Note;
|
||||
|
@ -0,0 +1,5 @@
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import { processForNotePadOnly } from '/imports/api/note/server/helpers';
|
||||
import handlePadUpdate from './handlers/padUpdate';
|
||||
|
||||
RedisPubSub.on('PadUpdateSysMsg', processForNotePadOnly(handlePadUpdate));
|
@ -0,0 +1,12 @@
|
||||
import { check } from 'meteor/check';
|
||||
import updateNote from '/imports/api/note/server/modifiers/updateNote';
|
||||
|
||||
export default function handlePadUpdate({ body }) {
|
||||
const { pad, revs } = body;
|
||||
const { id } = pad;
|
||||
|
||||
check(id, String);
|
||||
check(revs, Number);
|
||||
|
||||
updateNote(id, revs);
|
||||
}
|
@ -4,6 +4,7 @@ import { hashFNV32a } from '/imports/api/common/server/helpers';
|
||||
const ETHERPAD = Meteor.settings.private.etherpad;
|
||||
const NOTE_CONFIG = Meteor.settings.public.note;
|
||||
const BASE_URL = `http://${ETHERPAD.host}:${ETHERPAD.port}/api/${ETHERPAD.version}`;
|
||||
const TOKEN = '_';
|
||||
|
||||
const createPadURL = padId => `${BASE_URL}/createPad?apikey=${ETHERPAD.apikey}&padID=${padId}`;
|
||||
|
||||
@ -26,10 +27,26 @@ const getDataFromResponse = (data, key) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const isNotePad = (padId) => {
|
||||
return padId.search(TOKEN);
|
||||
};
|
||||
|
||||
const processForNotePadOnly = fn => (message, ...args) => {
|
||||
const { body } = message;
|
||||
const { pad } = body;
|
||||
const { id } = pad;
|
||||
|
||||
check(id, String);
|
||||
|
||||
if (isNotePad(id)) return fn(message, ...args);
|
||||
return () => {};
|
||||
};
|
||||
|
||||
export {
|
||||
generateNoteId,
|
||||
createPadURL,
|
||||
getReadOnlyIdURL,
|
||||
isEnabled,
|
||||
getDataFromResponse,
|
||||
processForNotePadOnly,
|
||||
};
|
||||
|
@ -1 +1,2 @@
|
||||
import './publishers';
|
||||
import './eventHandlers';
|
||||
|
@ -9,12 +9,14 @@ export default function addNote(meetingId, noteId, readOnlyNoteId) {
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
noteId,
|
||||
};
|
||||
|
||||
const modifier = {
|
||||
meetingId,
|
||||
noteId,
|
||||
readOnlyNoteId,
|
||||
revs: 0,
|
||||
};
|
||||
|
||||
const cb = (err, numChanged) => {
|
||||
|
@ -0,0 +1,28 @@
|
||||
import Note from '/imports/api/note';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
export default function updateNote(noteId, revs) {
|
||||
check(noteId, String);
|
||||
check(revs, Number);
|
||||
|
||||
const selector = {
|
||||
noteId,
|
||||
};
|
||||
|
||||
const modifier = {
|
||||
$set: {
|
||||
revs,
|
||||
},
|
||||
};
|
||||
|
||||
const cb = (err) => {
|
||||
if (err) {
|
||||
return Logger.error(`Updating note pad: ${err}`);
|
||||
}
|
||||
|
||||
return Logger.verbose(`Update note pad=${noteId} revs=${revs}`);
|
||||
};
|
||||
|
||||
return Note.update(selector, modifier, { multi: true }, cb);
|
||||
}
|
@ -4,6 +4,7 @@ import Note from '/imports/api/note';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import Settings from '/imports/ui/services/settings';
|
||||
import mapUser from '/imports/ui/services/user/mapUser';
|
||||
import { Session } from 'meteor/session';
|
||||
|
||||
const NOTE_CONFIG = Meteor.settings.public.note;
|
||||
|
||||
@ -66,14 +67,25 @@ const getNoteURL = () => {
|
||||
return url;
|
||||
};
|
||||
|
||||
const getRevs = () => {
|
||||
const note = Note.findOne({ meetingId: Auth.meetingID });
|
||||
return note ? note.revs : 0;
|
||||
};
|
||||
|
||||
const isEnabled = () => {
|
||||
const note = Note.findOne({ meetingId: Auth.meetingID });
|
||||
return NOTE_CONFIG.enabled && note;
|
||||
};
|
||||
|
||||
const isPanelOpened = () => {
|
||||
return Session.get('openPanel') === 'note';
|
||||
};
|
||||
|
||||
export default {
|
||||
getNoteURL,
|
||||
getReadOnlyURL,
|
||||
isLocked,
|
||||
isEnabled,
|
||||
isPanelOpened,
|
||||
getRevs,
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { styles } from './styles';
|
||||
import UserParticipantsContainer from './user-participants/container';
|
||||
import UserMessages from './user-messages/component';
|
||||
import UserNotes from './user-notes/component';
|
||||
import UserNotesContainer from './user-notes/container';
|
||||
import UserCaptionsContainer from './user-captions/container';
|
||||
import WaitingUsers from './waiting-users/component';
|
||||
import UserPolls from './user-polls/component';
|
||||
@ -101,7 +101,7 @@ class UserContent extends PureComponent {
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
<UserNotes
|
||||
<UserNotesContainer
|
||||
{...{
|
||||
intl,
|
||||
}}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cx from 'classnames';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import Icon from '/imports/ui/components/icon/component';
|
||||
import { Session } from 'meteor/session';
|
||||
import NoteService from '/imports/ui/components/note/service';
|
||||
import { styles } from './styles';
|
||||
|
||||
@ -10,6 +10,8 @@ const propTypes = {
|
||||
intl: PropTypes.shape({
|
||||
formatMessage: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
revs: PropTypes.number.isRequired,
|
||||
isPanelOpened: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
@ -23,23 +25,52 @@ const intlMessages = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
class UserNotes extends PureComponent {
|
||||
class UserNotes extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
unread: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { revs } = this.props;
|
||||
|
||||
if (revs !== 0) this.setState({ unread: true });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { isPanelOpened, revs } = this.props;
|
||||
const { unread } = this.state;
|
||||
|
||||
if (!isPanelOpened && !unread) {
|
||||
if (prevProps.revs !== revs) this.setState({ unread: true });
|
||||
}
|
||||
|
||||
if (isPanelOpened && unread) {
|
||||
this.setState({ unread: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
intl,
|
||||
} = this.props;
|
||||
const { intl, isPanelOpened } = this.props;
|
||||
const { unread } = this.state;
|
||||
|
||||
if (!NoteService.isEnabled()) return null;
|
||||
|
||||
const toggleNotePanel = () => {
|
||||
Session.set(
|
||||
'openPanel',
|
||||
Session.get('openPanel') === 'note'
|
||||
isPanelOpened
|
||||
? 'userlist'
|
||||
: 'note',
|
||||
);
|
||||
};
|
||||
|
||||
const iconClasses = {};
|
||||
iconClasses[styles.notification] = unread;
|
||||
|
||||
return (
|
||||
<div className={styles.messages}>
|
||||
{
|
||||
@ -54,7 +85,7 @@ class UserNotes extends PureComponent {
|
||||
className={styles.noteLink}
|
||||
onClick={toggleNotePanel}
|
||||
>
|
||||
<Icon iconName="copy" />
|
||||
<Icon iconName="copy" className={cx(iconClasses)}/>
|
||||
<span>{intl.formatMessage(intlMessages.title)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import NoteService from '/imports/ui/components/note/service';
|
||||
import UserNotes from './component';
|
||||
|
||||
const UserNotesContainer = props => <UserNotes {...props} />;
|
||||
|
||||
export default withTracker(() => ({
|
||||
isPanelOpened: NoteService.isPanelOpened(),
|
||||
revs: NoteService.getRevs(),
|
||||
}))(UserNotesContainer);
|
@ -73,3 +73,18 @@
|
||||
box-shadow: inset 0 0 0 var(--border-size) var(--item-focus-border), inset 1px 0 0 1px var(--item-focus-border);
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
bottom: 3px;
|
||||
right: 3px;
|
||||
background-color: var(--color-danger);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user