diff --git a/packages/rocketchat-api/server/routes.coffee b/packages/rocketchat-api/server/routes.coffee
index 10b34d05b93..116ea410be0 100644
--- a/packages/rocketchat-api/server/routes.coffee
+++ b/packages/rocketchat-api/server/routes.coffee
@@ -105,6 +105,73 @@ RocketChat.API.v1.addRoute 'channels.create', authRequired: true,
return RocketChat.API.v1.success
channel: RocketChat.models.Rooms.findOneById(id.rid)
+RocketChat.API.v1.addRoute 'channels.history', authRequired: true,
+ get: ->
+ if not @queryParams.roomId?
+ return RocketChat.API.v1.failure 'Query parameter "roomId" is required.'
+
+ rid = @queryParams.roomId
+
+ latestDate = new Date
+ if @queryParams.latest?
+ latestDate = new Date(@queryParams.latest)
+
+ oldestDate = undefined
+ if @queryParams.oldest?
+ oldestDate = new Date(@queryParams.oldest)
+
+ inclusive = false
+ if @queryParams.inclusive?
+ inclusive = @queryParams.inclusive
+
+ count = 20
+ if @queryParams.count?
+ count = parseInt @queryParams.count
+
+ unreads = false
+ if @queryParams.unreads?
+ unreads = @queryParams.unreads
+
+ result = {}
+
+ try
+ Meteor.runAsUser this.userId, =>
+ result = Meteor.call 'getChannelHistory', { rid, latest: latestDate, oldest: oldestDate, inclusive, count, unreads }
+ catch e
+ return RocketChat.API.v1.failure e.name + ': ' + e.message
+
+ return RocketChat.API.v1.success
+ result: result
+
+RocketChat.API.v1.addRoute 'channels.cleanHistory', authRequired: true,
+ post: ->
+ if not @bodyParams.roomId?
+ return RocketChat.API.v1.failure 'Body parameter "roomId" is required.'
+
+ roomId = @bodyParams.roomId
+
+ if not @bodyParams.latest?
+ return RocketChat.API.v1.failure 'Body parameter "latest" is required.'
+
+ if not @bodyParams.oldest?
+ return RocketChat.API.v1.failure 'Body parameter "oldest" is required.'
+
+ latest = new Date(@bodyParams.latest)
+ oldest = new Date(@bodyParams.oldest)
+
+ inclusive = false
+ if @bodyParams.inclusive?
+ inclusive = @bodyParams.inclusive
+
+ try
+ Meteor.runAsUser this.userId, =>
+ Meteor.call 'cleanChannelHistory', { roomId, latest, oldest, inclusive }
+ catch e
+ return RocketChat.API.v1.failure e.name + ': ' + e.message
+
+ return RocketChat.API.v1.success
+ success: true
+
# List Private Groups a user has access to
RocketChat.API.v1.addRoute 'groups.list', authRequired: true,
get: ->
diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee
index a6beed9bbd3..323a7b1c271 100644
--- a/packages/rocketchat-authorization/server/startup.coffee
+++ b/packages/rocketchat-authorization/server/startup.coffee
@@ -17,6 +17,7 @@ Meteor.startup ->
{ _id: 'create-d', roles : ['admin', 'user'] }
{ _id: 'create-p', roles : ['admin', 'user'] }
{ _id: 'create-user', roles : ['admin'] }
+ { _id: 'clean-channel-history', roles : ['admin'] } # special permission to bulk delete a channel's mesages
{ _id: 'delete-c', roles : ['admin'] }
{ _id: 'delete-d', roles : ['admin'] }
{ _id: 'delete-message', roles : ['admin', 'owner', 'moderator'] }
diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json
index b5c67698f63..0a90f0fed11 100644
--- a/packages/rocketchat-i18n/i18n/en.i18n.json
+++ b/packages/rocketchat-i18n/i18n/en.i18n.json
@@ -424,6 +424,7 @@
"error-invalid-channel-start-with-chars": "Invalid channel. Start with @ or #",
"error-invalid-custom-field": "Invalid custom field",
"error-invalid-custom-field-name": "Invalid custom field name. Use only letters, numbers, hyphens and underscores.",
+ "error-invalid-date": "Invalid date provided.",
"error-invalid-description": "Invalid description",
"error-invalid-domain": "Invalid domain",
"error-invalid-email": "Invalid email __email__",
@@ -764,6 +765,7 @@
"Livechat_managers": "Livechat managers",
"Livechat_offline": "Livechat offline",
"Livechat_online": "Livechat online",
+ "Livechat_open_inquiery_show_connecting": "Show connecting message instead of input when guest is not yet connected to an agent",
"Livechat_Queue": "Livechat Queue",
"Livechat_room_count": "Livechat room count",
"Livechat_Routing_Method": "Livechat Routing Method",
@@ -1167,6 +1169,7 @@
"Show_all": "Show all",
"Show_more": "Show more",
"show_offline_users": "show offline users",
+ "Show_on_registration_page": "Show on registration page",
"Show_only_online": "Show only online",
"Show_preregistration_form": "Show pre-registration form",
"Show_queue_list_to_all_agents": "Show queue list to all agents",
@@ -1278,6 +1281,7 @@
"theme-color-transparent-dark": "Transparent Dark",
"theme-color-transparent-light": "Transparent Light",
"theme-color-transparent-lighter": "Transparent Lighter",
+ "theme-color-transparent-lightest": "Transparent Lightest",
"theme-color-content-background-color": "Content Background Color",
"theme-color-primary-background-color": "Primary Background Color",
"theme-color-primary-font-color": "Primary Font Color",
@@ -1488,4 +1492,4 @@
"your_message_optional": "your message (optional)",
"Your_password_is_wrong": "Your password is wrong!",
"Your_push_was_sent_to_s_devices": "Your push was sent to %s devices"
-}
\ No newline at end of file
+}
diff --git a/packages/rocketchat-i18n/i18n/pt.i18n.json b/packages/rocketchat-i18n/i18n/pt.i18n.json
index cbea202314d..9c38197eda9 100644
--- a/packages/rocketchat-i18n/i18n/pt.i18n.json
+++ b/packages/rocketchat-i18n/i18n/pt.i18n.json
@@ -1035,6 +1035,7 @@
"Show_all": "Mostrar tudo",
"Show_more": "Mostrar mais",
"show_offline_users": "mostrar usuários offline",
+ "Show_on_registration_page": "Mostrar no formulário de registro",
"Show_only_online": "Mostrar apenas online",
"Show_preregistration_form": "Mostrar formulário de pré-registro",
"Show_queue_list_to_all_agents": "Mostrar link da roleta à todos agentes",
@@ -1306,4 +1307,4 @@
"your_message_optional": "sua mensagem (opcional)",
"Your_password_is_wrong": "Sua senha está errada!",
"Your_push_was_sent_to_s_devices": "Sua natificação foi enviada para %s dispositivos"
-}
\ No newline at end of file
+}
diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js
index 398052a8c27..301f538d447 100644
--- a/packages/rocketchat-lib/package.js
+++ b/packages/rocketchat-lib/package.js
@@ -137,6 +137,8 @@ Package.onUse(function(api) {
api.addFiles('server/methods/updateMessage.coffee', 'server');
api.addFiles('server/methods/filterBadWords.js', ['server']);
api.addFiles('server/methods/filterATAllTag.js', 'server');
+ api.addFiles('server/methods/getChannelHistory.js', 'server');
+ api.addFiles('server/methods/cleanChannelHistory.js', 'server');
// SERVER STARTUP
api.addFiles('server/startup/settingsOnLoadCdnPrefix.coffee', 'server');
diff --git a/packages/rocketchat-lib/server/functions/settings.coffee b/packages/rocketchat-lib/server/functions/settings.coffee
index e5197b6f20f..104896b7d46 100644
--- a/packages/rocketchat-lib/server/functions/settings.coffee
+++ b/packages/rocketchat-lib/server/functions/settings.coffee
@@ -92,9 +92,16 @@ RocketChat.settings.add = (_id, value, options = {}) ->
updateOperations.$unset = { section: 1 }
query.section = { $exists: false }
- if not RocketChat.models.Settings.findOne(query)?
+ existantSetting = RocketChat.models.Settings.findOne(query)
+
+ if existantSetting?
+ if not existantSetting.editor? and updateOperations.$setOnInsert.editor?
+ updateOperations.$set.editor = updateOperations.$setOnInsert.editor
+ delete updateOperations.$setOnInsert.editor
+ else
updateOperations.$set.ts = new Date
- return RocketChat.models.Settings.upsert { _id: _id }, updateOperations
+
+ return RocketChat.models.Settings.upsert { _id: _id }, updateOperations
diff --git a/packages/rocketchat-lib/server/methods/cleanChannelHistory.js b/packages/rocketchat-lib/server/methods/cleanChannelHistory.js
new file mode 100644
index 00000000000..8c96388c7fb
--- /dev/null
+++ b/packages/rocketchat-lib/server/methods/cleanChannelHistory.js
@@ -0,0 +1,34 @@
+Meteor.methods({
+ cleanChannelHistory({roomId, latest, oldest, inclusive}) {
+ check(roomId, String);
+ check(latest, Date);
+ check(oldest, Date);
+ check(inclusive, Boolean);
+
+ if (!Meteor.userId()) {
+ throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'cleanChannelHistory' });
+ }
+
+ if (!RocketChat.authz.hasPermission(Meteor.userId(), 'clean-channel-history')) {
+ throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'cleanChannelHistory' });
+ }
+
+ if (inclusive) {
+ RocketChat.models.Messages.remove({
+ rid: roomId,
+ ts: {
+ $gte: oldest,
+ $lte: latest
+ }
+ });
+ } else {
+ RocketChat.models.Messages.remove({
+ rid: roomId,
+ ts: {
+ $gt: oldest,
+ $lt: latest
+ }
+ });
+ }
+ }
+});
diff --git a/packages/rocketchat-lib/server/methods/getChannelHistory.js b/packages/rocketchat-lib/server/methods/getChannelHistory.js
new file mode 100644
index 00000000000..03958a40fae
--- /dev/null
+++ b/packages/rocketchat-lib/server/methods/getChannelHistory.js
@@ -0,0 +1,81 @@
+Meteor.methods({
+ getChannelHistory({rid, latest, oldest, inclusive, count = 20, unreads}) {
+ check(rid, String);
+
+ if (!Meteor.userId()) {
+ throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getChannelHistory' });
+ }
+
+ const fromUserId = Meteor.userId();
+ const room = Meteor.call('canAccessRoom', rid, fromUserId);
+ if (!room) {
+ return false;
+ }
+
+ //Make sure they can access the room
+ if (room.t === 'c' && !RocketChat.authz.hasPermission(fromUserId, 'preview-c-room') && room.usernames.indexOf(room.username) === -1) {
+ return false;
+ }
+
+ //Ensure latest is always defined.
+ if (_.isUndefined(latest)) {
+ latest = new Date();
+ }
+
+ //Verify oldest is a date if it exists
+ if (!_.isUndefined(oldest) && !_.isDate(oldest)) {
+ throw new Meteor.Error('error-invalid-date', 'Invalid date', { method: 'getChannelHistory' });
+ }
+
+ const options = {
+ sort: {
+ ts: -1
+ },
+ limit: count
+ };
+
+ if (!RocketChat.settings.get('Message_ShowEditedStatus')) {
+ options.fields = { 'editedAt': 0 };
+ }
+
+ let records = [];
+ if (_.isUndefined(oldest) && inclusive) {
+ records = RocketChat.models.Messages.findVisibleByRoomIdBeforeTimestampInclusive(rid, latest, options).fetch();
+ } else if (_.isUndefined(oldest) && !inclusive) {
+ records = RocketChat.models.Messages.findVisibleByRoomIdBeforeTimestamp(rid, latest, options).fetch();
+ } else if (!_.isUndefined(oldest) && inclusive) {
+ records = RocketChat.models.Messages.findVisibleByRoomIdBetweenTimestampsInclusive(rid, oldest, latest, options).fetch();
+ } else {
+ records = RocketChat.models.Messages.findVisibleByRoomIdBetweenTimestamps(rid, oldest, latest, options).fetch();
+ }
+
+ const messages = _.map(records, (message) => {
+ message.starred = _.findWhere(message.starred, { _id: fromUserId });
+ return message;
+ });
+
+ if (unreads) {
+ let unreadNotLoaded = 0;
+ let firstUnread = undefined;
+
+ if (!_.isUndefined(oldest)) {
+ const firstMsg = messages[messages.length - 1];
+ if (!_.isUndefined(firstMsg) && firstMsg.ts > oldest) {
+ const unreadMessages = RocketChat.models.Messages.findVisibleByRoomIdBetweenTimestamps(rid, oldest, firstMsg.ts, { limit: 1, sort: { ts: 1 } });
+ firstUnread = unreadMessages.fetch()[0];
+ unreadNotLoaded = unreadMessages.count();
+ }
+ }
+
+ return {
+ messages,
+ firstUnread,
+ unreadNotLoaded
+ };
+ }
+
+ return {
+ messages
+ };
+ }
+});
diff --git a/packages/rocketchat-lib/server/models/Messages.coffee b/packages/rocketchat-lib/server/models/Messages.coffee
index 02cc0f77e56..a117c8ada37 100644
--- a/packages/rocketchat-lib/server/models/Messages.coffee
+++ b/packages/rocketchat-lib/server/models/Messages.coffee
@@ -89,6 +89,16 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base
return @find query, options
+ findVisibleByRoomIdBeforeTimestampInclusive: (roomId, timestamp, options) ->
+ query =
+ _hidden:
+ $ne: true
+ rid: roomId
+ ts:
+ $lte: timestamp
+
+ return @find query, options
+
findVisibleByRoomIdBetweenTimestamps: (roomId, afterTimestamp, beforeTimestamp, options) ->
query =
_hidden:
@@ -100,6 +110,17 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base
return @find query, options
+ findVisibleByRoomIdBetweenTimestampsInclusive: (roomId, afterTimestamp, beforeTimestamp, options) ->
+ query =
+ _hidden:
+ $ne: true
+ rid: roomId
+ ts:
+ $gte: afterTimestamp
+ $lte: beforeTimestamp
+
+ return @find query, options
+
findVisibleByRoomIdBeforeTimestampNotContainingTypes: (roomId, timestamp, types, options) ->
query =
_hidden:
diff --git a/packages/rocketchat-livechat/app/client/lib/_livechat.js b/packages/rocketchat-livechat/app/client/lib/_livechat.js
index 46895402b43..f1c361bcbdc 100644
--- a/packages/rocketchat-livechat/app/client/lib/_livechat.js
+++ b/packages/rocketchat-livechat/app/client/lib/_livechat.js
@@ -18,15 +18,17 @@ this.Livechat = new (class Livechat {
this._offlineSuccessMessage = new ReactiveVar(TAPi18n.__('Thanks_We_ll_get_back_to_you_soon'));
this._videoCall = new ReactiveVar(false);
this._transcriptMessage = new ReactiveVar('');
+ this._connecting = new ReactiveVar(false);
this._room = new ReactiveVar(null);
- Tracker.autorun((c) => {
+ this._department = new ReactiveVar(null);
+
+ Tracker.autorun(() => {
if (this._room.get() && Meteor.userId()) {
RoomHistoryManager.getMoreIfIsEmpty(this._room.get());
visitor.subscribeToRoom(this._room.get());
visitor.setRoom(this._room.get());
- c.stop();
}
});
}
@@ -70,6 +72,13 @@ this.Livechat = new (class Livechat {
get transcriptMessage() {
return this._transcriptMessage.get();
}
+ get department() {
+ return this._department.get();
+ }
+
+ get connecting() {
+ return this._connecting.get();
+ }
set online(value) {
this._online.set(value);
@@ -118,8 +127,17 @@ this.Livechat = new (class Livechat {
set transcriptMessage(value) {
this._transcriptMessage.set(value);
}
-
+ set connecting(value) {
+ this._connecting.set(value);
+ }
set room(roomId) {
this._room.set(roomId);
}
+ set department(departmentId) {
+ const dept = Department.findOne({ _id: departmentId }) || Department.findOne({ name: departmentId });
+
+ if (dept) {
+ this._department.set(dept._id);
+ }
+ }
})();
diff --git a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee
index f63f91e5ce2..4b6eecccf0e 100644
--- a/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee
+++ b/packages/rocketchat-livechat/app/client/lib/chatMessages.coffee
@@ -76,7 +76,12 @@ class @ChatMessages
rid ?= visitor.getRoom(true)
sendMessage = (callback) ->
- msgObject = { _id: Random.id(), rid: rid, msg: msg, token: visitor.getToken() }
+ msgObject = {
+ _id: Random.id(),
+ rid: rid,
+ msg: msg,
+ token: visitor.getToken()
+ }
MsgTyping.stop(rid)
Meteor.call 'sendMessageLivechat', msgObject, (error, result) ->
@@ -84,12 +89,20 @@ class @ChatMessages
ChatMessage.update msgObject._id, { $set: { error: true } }
showError error.reason
- if result.rid? and not visitor.isSubscribed(result.rid)
+ if result?.rid? and not visitor.isSubscribed(result.rid)
+ Livechat.connecting = result.showConnecting
ChatMessage.update result._id, _.omit(result, '_id')
Livechat.room = result.rid
if not Meteor.userId()
- Meteor.call 'livechat:registerGuest', { token: visitor.getToken() }, (error, result) ->
+ guest = {
+ token: visitor.getToken()
+ }
+
+ if Livechat.department
+ guest.department = Livechat.department
+
+ Meteor.call 'livechat:registerGuest', guest, (error, result) ->
if error?
return showError error.reason
diff --git a/packages/rocketchat-livechat/app/client/lib/commands.js b/packages/rocketchat-livechat/app/client/lib/commands.js
index 8c8f60bbbdd..decd3173f69 100644
--- a/packages/rocketchat-livechat/app/client/lib/commands.js
+++ b/packages/rocketchat-livechat/app/client/lib/commands.js
@@ -60,5 +60,9 @@ this.Commands = {
showConfirmButton: false
});
}
+ },
+
+ connected: function() {
+ Livechat.connecting = false;
}
};
diff --git a/packages/rocketchat-livechat/app/client/lib/hooks.js b/packages/rocketchat-livechat/app/client/lib/hooks.js
index 4a8fa387a3f..6733cb2f6ef 100644
--- a/packages/rocketchat-livechat/app/client/lib/hooks.js
+++ b/packages/rocketchat-livechat/app/client/lib/hooks.js
@@ -19,6 +19,14 @@ var api = {
if (theme.fontColor) {
Livechat.customFontColor = theme.fontColor;
}
+ },
+
+ setDepartment: function(department) {
+ Livechat.department = department;
+ },
+
+ clearDepartment: function() {
+ Livechat.department = null;
}
};
diff --git a/packages/rocketchat-livechat/app/client/stylesheets/loading.less b/packages/rocketchat-livechat/app/client/stylesheets/loading.less
new file mode 100644
index 00000000000..5d7fd0b884b
--- /dev/null
+++ b/packages/rocketchat-livechat/app/client/stylesheets/loading.less
@@ -0,0 +1,45 @@
+@import "_variables.less";
+
+.loading {
+ color: @secondary-font-color;
+ font-size: 1.3rem;
+ margin-left: 32px;
+ margin-top: 12px;
+ margin-bottom: 5px;
+}
+
+.loading > div {
+ width: 3px;
+ height: 3px;
+ background-color: @secondary-font-color;
+
+ border-radius: 100%;
+ display: inline-block;
+ -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+ animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+}
+
+.loading .bounce1 {
+ -webkit-animation-delay: -0.32s;
+ animation-delay: -0.32s;
+}
+
+.loading .bounce2 {
+ -webkit-animation-delay: -0.16s;
+ animation-delay: -0.16s;
+}
+
+@-webkit-keyframes sk-bouncedelay {
+ 0%, 80%, 100% { -webkit-transform: scale(0) }
+ 40% { -webkit-transform: scale(1.0) }
+}
+
+@keyframes sk-bouncedelay {
+ 0%, 80%, 100% {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ } 40% {
+ -webkit-transform: scale(1.0);
+ transform: scale(1.0);
+ }
+}
\ No newline at end of file
diff --git a/packages/rocketchat-livechat/app/client/views/loading.html b/packages/rocketchat-livechat/app/client/views/loading.html
new file mode 100644
index 00000000000..69e145bcdff
--- /dev/null
+++ b/packages/rocketchat-livechat/app/client/views/loading.html
@@ -0,0 +1,8 @@
+
+
| {{_ "Name"}} | -{{_ "Description"}} | -{{_ "Num_Agents"}} | -{{_ "Enabled"}} | +{{_ "Name"}} | +{{_ "Description"}} | +{{_ "Num_Agents"}} | +{{_ "Enabled"}} | +{{_ "Show_on_registration"}} | {{_ "Delete"}} | {{description}} | {{numAgents}} | {{#if enabled}}{{_ "Yes"}}{{else}}{{_ "No"}}{{/if}} | +{{#if showOnRegistration}}{{_ "Yes"}}{{else}}{{_ "No"}}{{/if}} | {{/each}} diff --git a/packages/rocketchat-livechat/config.js b/packages/rocketchat-livechat/config.js index 1270237727a..80102c9613e 100644 --- a/packages/rocketchat-livechat/config.js +++ b/packages/rocketchat-livechat/config.js @@ -211,4 +211,12 @@ Meteor.startup(function() { enableQuery: { _id: 'Livechat_enable_transcript', value: true } }); + RocketChat.settings.add('Livechat_open_inquiery_show_connecting', false, { + type: 'boolean', + group: 'Livechat', + public: true, + i18nLabel: 'Livechat_open_inquiery_show_connecting', + enableQuery: { _id: 'Livechat_Routing_Method', value: 'Guest_Pool' } + }); + }); diff --git a/packages/rocketchat-livechat/server/lib/Livechat.js b/packages/rocketchat-livechat/server/lib/Livechat.js index 34af055d948..37a52e7b8f6 100644 --- a/packages/rocketchat-livechat/server/lib/Livechat.js +++ b/packages/rocketchat-livechat/server/lib/Livechat.js @@ -68,7 +68,9 @@ RocketChat.Livechat = { if (guest.name) { message.alias = guest.name; } - return _.extend(RocketChat.sendMessage(guest, message, room), { newRoom: newRoom }); + + // return messages; + return _.extend(RocketChat.sendMessage(guest, message, room), { newRoom: newRoom, showConnecting: this.showConnecting() }); }, registerGuest({ token, name, email, department, phone, loginToken, username } = {}) { check(token, String); @@ -200,7 +202,6 @@ RocketChat.Livechat = { RocketChat.sendMessage(user, message, room); RocketChat.models.Subscriptions.hideByRoomIdAndUserId(room._id, user._id); - RocketChat.models.Messages.createCommandWithRoomIdAndUser('promptTranscript', room._id, user); Meteor.defer(() => { @@ -465,7 +466,8 @@ RocketChat.Livechat = { check(departmentData, { enabled: Boolean, name: String, - description: Match.Optional(String) + description: Match.Optional(String), + showOnRegistration: Boolean }); check(departmentAgents, [ @@ -482,7 +484,7 @@ RocketChat.Livechat = { } } - return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description, departmentAgents); + return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData, departmentAgents); }, removeDepartment(_id) { @@ -495,6 +497,14 @@ RocketChat.Livechat = { } return RocketChat.models.LivechatDepartment.removeById(_id); + }, + + showConnecting() { + if (RocketChat.settings.get('Livechat_Routing_Method') === 'Guest_Pool') { + return RocketChat.settings.get('Livechat_open_inquiery_show_connecting'); + } else { + return false; + } } }; diff --git a/packages/rocketchat-livechat/server/lib/QueueMethods.js b/packages/rocketchat-livechat/server/lib/QueueMethods.js index 85013f3a4fe..c40fe6166ca 100644 --- a/packages/rocketchat-livechat/server/lib/QueueMethods.js +++ b/packages/rocketchat-livechat/server/lib/QueueMethods.js @@ -120,4 +120,4 @@ RocketChat.QueueMethods = { return room; } -}; +}; \ No newline at end of file diff --git a/packages/rocketchat-livechat/server/methods/takeInquiry.js b/packages/rocketchat-livechat/server/methods/takeInquiry.js index b431c5721ea..8a110f76ecc 100644 --- a/packages/rocketchat-livechat/server/methods/takeInquiry.js +++ b/packages/rocketchat-livechat/server/methods/takeInquiry.js @@ -51,6 +51,11 @@ Meteor.methods({ // mark inquiry as taken RocketChat.models.LivechatInquiry.takeInquiry(inquiry._id); + // remove sending message from guest widget + // dont check if setting is true, because if settingwas switched off inbetween guest entered pool, + // and inquiry being taken, message would not be switched off. + RocketChat.models.Messages.createCommandWithRoomIdAndUser('connected', room._id, user); + // return room corresponding to inquiry (for redirecting agent to the room route) return room; } diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js index 08627f550ef..a1f9285f0ff 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js @@ -4,6 +4,11 @@ class LivechatDepartment extends RocketChat.models._Base { constructor() { super('livechat_department'); + + this.tryEnsureIndex({ + numAgents: 1, + enabled: 1 + }); } // FIND @@ -19,18 +24,17 @@ class LivechatDepartment extends RocketChat.models._Base { return this.find(query, options); } - createOrUpdateDepartment(_id, enabled, name, description, agents, extraData) { + createOrUpdateDepartment(_id, { enabled, name, description, showOnRegistration }, agents) { agents = [].concat(agents); var record = { enabled: enabled, name: name, description: description, - numAgents: agents.length + numAgents: agents.length, + showOnRegistration: showOnRegistration }; - _.extend(record, extraData); - if (_id) { this.update({ _id: _id }, { $set: record }); } else { diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js index 681a6c73eec..ef725815b9c 100644 --- a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js +++ b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js @@ -74,7 +74,7 @@ class LivechatDepartmentAgents extends RocketChat.models._Base { var agents = this.findByDepartmentId(departmentId).fetch(); if (agents.length === 0) { - return; + return []; } var onlineUsers = RocketChat.models.Users.findOnlineUserFromList(_.pluck(agents, 'username')); @@ -93,7 +93,7 @@ class LivechatDepartmentAgents extends RocketChat.models._Base { if (depAgents) { return depAgents; } else { - return null; + return []; } } diff --git a/packages/rocketchat-sandstorm/client/setPath.js b/packages/rocketchat-sandstorm/client/setPath.js new file mode 100644 index 00000000000..004ab4cee8e --- /dev/null +++ b/packages/rocketchat-sandstorm/client/setPath.js @@ -0,0 +1,12 @@ +function updateSandstormMetaData(msg) { + return window.parent.postMessage(msg, '*'); +} + +if (Meteor.settings.public.sandstorm) { + // Set the path of the parent frame when the grain's path changes. + // See https://docs.sandstorm.io/en/latest/developing/path/ + + FlowRouter.triggers.enter([({ path }) => { + updateSandstormMetaData({ setPath: path }); + }]); +} diff --git a/packages/rocketchat-sandstorm/package.js b/packages/rocketchat-sandstorm/package.js index a052ac15b38..bd68220fa2e 100644 --- a/packages/rocketchat-sandstorm/package.js +++ b/packages/rocketchat-sandstorm/package.js @@ -6,8 +6,8 @@ Package.describe({ }); Package.onUse(function(api) { - api.use([ 'ecmascript', 'rocketchat:lib', 'jalik:ufs' ]); + api.use([ 'ecmascript', 'rocketchat:lib', 'jalik:ufs', 'kadira:flow-router']); api.addFiles([ 'server/lib.js', 'server/events.js', 'server/powerbox.js' ], 'server'); - api.addFiles([ 'client/powerboxListener.js' ], 'client'); + api.addFiles([ 'client/powerboxListener.js', 'client/setPath.js' ], 'client'); }); diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less index 58c23c015f7..c7f9d670ad3 100644 --- a/packages/rocketchat-theme/assets/stylesheets/base.less +++ b/packages/rocketchat-theme/assets/stylesheets/base.less @@ -174,6 +174,12 @@ blockquote { } .first-unread { + &.message { + padding-top: 20px; + } + &.sequential.message { + padding-top: 20px; + } .body { &::before { content: ""; @@ -181,21 +187,24 @@ blockquote { height: 1px; position: absolute; right: 0px; - left: 20px; + left: 0px; top: 0px; .transition(background-color, .5s, linear); + height: 16px; } &::after { content: "unread messages"; display: block; position: absolute; right: 0px; - top: -4px; + top: 0px; text-transform: uppercase; - font-size: 8px; - line-height: 10px; + font-size: 12px; + line-height: 16px; padding: 0 5px; .transition(color, .5s, linear); + left: 0; + text-align: center; } } } diff --git a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less index c06d30225d6..99dd5f2d9ca 100755 --- a/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less +++ b/packages/rocketchat-theme/assets/stylesheets/utils/_colors.import.less @@ -22,18 +22,11 @@ */ html { - .custom-scroll(transparent, @custom-scrollbar-color, 0); + .custom-scroll(@transparent-dark, @custom-scrollbar-color, 0); } -.flex-nav, -.flex-tab .content, -.messages-container .wrapper, -.list-view, -.page-container .content, -.rooms-list, -.scrollable, -.user-view { - .custom-scroll(transparent, @custom-scrollbar-color); +* { + .custom-scroll(@transparent-dark, @custom-scrollbar-color); } body { @@ -77,7 +70,7 @@ blockquote:before { tr { background-color: @transparent-light; &:nth-of-type(even) { - background-color: @transparent-lighter; + background-color: @transparent-lightest; } } tr:hover td { @@ -138,7 +131,7 @@ blockquote:before { pre { color: @error-color; border-color: @error-border; - background-color: @transparent-lighter; + background-color: @transparent-lightest; } } @@ -313,7 +306,6 @@ blockquote:before { } } - .messages-box { .start { color: @info-font-color; @@ -329,6 +321,25 @@ blockquote:before { * Message content */ +.first-unread { + .body { + &::before { + background: @transparent-darker; + } + &::after { + color: @primary-font-color; + } + } +} + +.first-unread-opaque { + .body { + &::before { + background: @transparent-dark; + } + } +} + .message { .body { color: @primary-font-color; @@ -468,22 +479,25 @@ a:hover { .rooms-list { background-color: lighten(@primary-background-color, 2.5%); } - .more:hover, h3:hover, + li:hover, + .more:hover, .selected-users li { background-color: @transparent-darker; } - li.active .opt { - color: @tertiary-font-color; + li.active { + background-color: @transparent-light !important; } - .active a { - color: @primary-background-contrast; - background-color: @transparent-lighter; + i { + color: @transparent-lighter; } - .open-room:hover { - background-color: @transparent-lighter; + .status-offline { + color: @transparent-lighter !important; } - .has-alert a { + .opt i:hover { + color: @transparent-lightest; + } + .has-alert .name { color: @primary-background-contrast; } .unread { @@ -493,6 +507,12 @@ a:hover { background-color: @primary-action-color; color: @primary-action-contrast; } + .button { + .buttonColors(@tertiary-font-color, mix(@primary-action-color, @primary-background-color)); + } + .options button { + .buttonColors(@tertiary-font-color, @primary-background-color); + } } @@ -502,11 +522,12 @@ a:hover { .flex-tab { background-color: @secondary-background-color; - .content, .user-view, .list-view { + .content, + .user-view, + .list-view { background-color: @secondary-background-color; } .message { - background-color: @transparent-lighter; &.new-day::before { background-color: @secondary-background-color; } @@ -577,7 +598,7 @@ i.status-away { .account-box .status-away .thumb:after, .account-box .status.away:after, -.options .status .online:after, +.options .status .away:after, .popup-user-status-away, .status-pending:after, .user-image.status-away .avatar:after { @@ -591,7 +612,7 @@ i.status-busy { .account-box .status-busy .thumb:after, .account-box .status.busy:after, -.options .status .online:after, +.options .status .busy:after, .popup-user-status-busy, .status-busy:after, .user-image.status-busy .avatar:after { @@ -605,7 +626,7 @@ i.status-offline { .account-box .status-offline .thumb:after, .account-box .status.offline:after, -.options .status .online:after, +.options .status .offline:after, .popup-user-status-offline, .status-offline:after, .user-image.status-offline .avatar:after { @@ -685,15 +706,6 @@ i.status-offline { } } -.side-nav { - .button { - .buttonColors(@tertiary-font-color, mix(@primary-action-color, @primary-background-color)); - } - .options button { - .buttonColors(@tertiary-font-color, @primary-background-color); - } -} - /** ---------------------------------------------------------------------------- * Feedback and overlay content diff --git a/packages/rocketchat-theme/server/variables.coffee b/packages/rocketchat-theme/server/variables.coffee index 75631d4044b..b5ebd79e2c0 100755 --- a/packages/rocketchat-theme/server/variables.coffee +++ b/packages/rocketchat-theme/server/variables.coffee @@ -10,9 +10,10 @@ # Defined range of transparencies reduces random colour variances alphaColors= 'transparent-darker': 'rgba(0,0,0,0.15)' - 'transparent-dark': 'rgba(0,0,0,0.03)' - 'transparent-light': 'rgba(255,255,255,0.60)' - 'transparent-lighter': 'rgba(255,255,255,0.25)' + 'transparent-dark': 'rgba(0,0,0,0.05)' + 'transparent-light': 'rgba(255,255,255,0.10)' + 'transparent-lighter': 'rgba(255,255,255,0.30)' + 'transparent-lightest': 'rgba(255,255,255,0.60)' # Major colors form the core of the scheme # Names changed to reflect usage, comments show pre-refactor names @@ -33,10 +34,10 @@ majorColors= # Minor colours implement major colours by default, but can be overruled minorColors= 'tertiary-background-color': '@component-color' - 'tertiary-font-color': '@transparent-light' + 'tertiary-font-color': '@transparent-lightest' 'link-font-color': '@primary-action-color' 'info-font-color': '@secondary-font-color' - 'custom-scrollbar-color': '@transparent-dark' + 'custom-scrollbar-color': '@transparent-darker' 'status-online': '@success-color' 'status-away': '@pending-color' 'status-busy': '@error-color' diff --git a/packages/rocketchat-ui-admin/admin/admin.coffee b/packages/rocketchat-ui-admin/admin/admin.coffee index 12a1d056607..08aba89d9ad 100644 --- a/packages/rocketchat-ui-admin/admin/admin.coffee +++ b/packages/rocketchat-ui-admin/admin/admin.coffee @@ -5,7 +5,7 @@ RocketChat.TempSettings = TempSettings updateColorComponent = -> $('input.minicolors').minicolors theme: 'rocketchat' - format: 'hex' + format: 'rgb' opacity: true Template.admin.onCreated -> diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee index e0196df020a..d470222c5a3 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.coffee @@ -29,6 +29,20 @@ Template.uploadedFilesList.helpers url: -> return '/file-upload/' + @_id + '/' + @name + fixCordova: (url) -> + if Meteor.isCordova and url?[0] is '/' + url = Meteor.absoluteUrl().replace(/\/$/, '') + url + query = "rc_uid=#{Meteor.userId()}&rc_token=#{Meteor._localStorage.getItem('Meteor.loginToken')}" + if url.indexOf('?') is -1 + url = url + '?' + query + else + url = url + '&' + query + + if Meteor.settings.public.sandstorm or url.match /^(https?:)?\/\//i + return url + else + return Meteor.absoluteUrl().replace(/\/$/, '') + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX + url + Template.uploadedFilesList.events 'click .room-file-item': (e, t) -> if $(e.currentTarget).siblings('.icon-picture').length diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html index 4d8a25c79b0..2f5ad0bc782 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/uploadedFilesList.html @@ -10,10 +10,10 @@ {{#if canDelete}} {{/if}} - + - + |
|---|