Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/tags' into develop
Browse files Browse the repository at this point in the history
# Conflicts:
#	app/models/server/models/Messages.js
#	app/models/server/raw/index.js
#	app/theme/client/main.css
#	client/importPackages.js
#	server/importPackages.js
  • Loading branch information
shedoev committed May 18, 2020
2 parents 6cc521a + ee0d8e8 commit c804c4a
Show file tree
Hide file tree
Showing 48 changed files with 1,527 additions and 56 deletions.
1 change: 1 addition & 0 deletions app/api/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ import './v1/webdav';
import './v1/oauthapps';
import './v1/custom-sounds';
import './v1/custom-user-status';
import './v1/tags';

export { API, APIClass, defaultRateLimiterOptions } from './api';
20 changes: 20 additions & 0 deletions app/api/server/lib/tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Tags } from '../../../models/server/raw';

export async function findTags({ query = {}, pagination: { offset, count, sort } }) {
const cursor = await Tags.find(query, {
sort: sort || { name: 1 },
skip: offset,
limit: count,
});

const total = await cursor.count();

const tags = await cursor.toArray();

return {
tags,
count: tags.length,
offset,
total,
};
}
18 changes: 18 additions & 0 deletions app/api/server/v1/tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { API } from '../api';
import { findTags } from '../lib/tags';

API.v1.addRoute('tags.list', { authRequired: true }, {
get() {
const { offset, count } = this.getPaginationItems();
const { sort, query } = this.parseJsonQuery();

return API.v1.success(Promise.await(findTags({
query,
pagination: {
offset,
count,
sort,
},
})));
},
});
1 change: 1 addition & 0 deletions app/authorization/server/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Meteor.startup(function() {
{ _id: 'manage-own-incoming-integrations', roles: ['admin'] },
{ _id: 'manage-oauth-apps', roles: ['admin'] },
{ _id: 'manage-selected-settings', roles: ['admin'] },
{ _id: 'manage-tags', roles: ['admin'] },
{ _id: 'mention-all', roles: ['admin', 'owner', 'moderator', 'user'] },
{ _id: 'mention-here', roles: ['admin', 'owner', 'moderator', 'user'] },
{ _id: 'mute-user', roles: ['admin', 'owner', 'moderator'] },
Expand Down
8 changes: 8 additions & 0 deletions app/models/client/models/ChatMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@ ChatMessage.setReactions = function(messageId, reactions) {
ChatMessage.unsetReactions = function(messageId) {
return this.update({ _id: messageId }, { $unset: { reactions: 1 } });
};

ChatMessage.setTags = function(messageId, tags) {
return this.update({ _id: messageId }, { $set: { tags } });
};

ChatMessage.unsetTags = function(messageId) {
return this.update({ _id: messageId }, { $unset: { tags: 1 } });
};
8 changes: 8 additions & 0 deletions app/models/client/models/ChatRoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@ ChatRoom.setReactionsInLastMessage = function(roomId, lastMessage) {
ChatRoom.unsetReactionsInLastMessage = function(roomId) {
return this.update({ _id: roomId }, { $unset: { lastMessage: { reactions: 1 } } });
};

ChatRoom.setTagsInLastMessage = function(roomId, lastMessage) {
return this.update({ _id: roomId }, { $set: { lastMessage } });
};

ChatRoom.unsetTagsInLastMessage = function(roomId) {
return this.update({ _id: roomId }, { $unset: { lastMessage: { tags: 1 } } });
};
2 changes: 2 additions & 0 deletions app/models/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import LivechatInquiry from './models/LivechatInquiry';
import ReadReceipts from './models/ReadReceipts';
import LivechatExternalMessage from './models/LivechatExternalMessages';
import Analytics from './models/Analytics';
import Tags from './models/Tags';

export { AppsLogsModel } from './models/apps-logs-model';
export { AppsPersistenceModel } from './models/apps-persistence-model';
Expand Down Expand Up @@ -92,4 +93,5 @@ export {
LivechatExternalMessage,
LivechatInquiry,
Analytics,
Tags,
};
9 changes: 9 additions & 0 deletions app/models/server/models/Messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export class Messages extends Base {
return this.update({ _id: messageId }, { $set: { reactions } });
}

setTags(messageId, tags) {
return this.update({ _id: messageId }, { $set: { tags } });
}

setErrand(messageId, errand) {
return this.update({ _id: messageId }, { $set: { errand } });
}
Expand Down Expand Up @@ -86,6 +90,10 @@ export class Messages extends Base {
return this.update({ _id: messageId }, { $unset: { reactions: 1 } });
}

unsetTags(messageId) {
return this.update({ _id: messageId }, { $unset: { tags: 1 } });
}

deleteOldOTRMessages(roomId, ts) {
const query = { rid: roomId, t: 'otr', ts: { $lte: ts } };
return this.remove(query);
Expand Down Expand Up @@ -563,6 +571,7 @@ export class Messages extends Base {
mentions: [],
attachments: [],
reactions: [],
tags: [],
editedAt: new Date(),
editedBy: {
_id: user._id,
Expand Down
8 changes: 8 additions & 0 deletions app/models/server/models/Rooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ export class Rooms extends Base {
return this.update({ _id: roomId }, { $unset: { lastMessage: { reactions: 1 } } });
}

setTagsInLastMessage(roomId, lastMessage) {
return this.update({ _id: roomId }, { $set: { 'lastMessage.tags': lastMessage.tags } });
}

unsetTagsInLastMessage(roomId) {
return this.update({ _id: roomId }, { $unset: { lastMessage: { tags: 1 } } });
}

updateLastMessageStar(roomId, userId, starred) {
let update;
const query = { _id: roomId };
Expand Down
53 changes: 53 additions & 0 deletions app/models/server/models/Tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Base } from './_Base';

export class Tags extends Base {
constructor() {
super('tags');

this.tryEnsureIndex({ name: 1 });
}

findOneById(_id, options) {
return this.findOne(_id, options);
}

findByName(name, options) {
const query = {
name,
};

return this.find(query, options);
}

findByNameExceptId(name, except, options) {
const query = {
_id: { $nin: [except] },
name,
};

return this.find(query, options);
}

// INSERT
create(data) {
return this.insert(data);
}

// update
setName(_id, name) {
const update = {
$set: {
name,
},
};

return this.update({ _id }, update);
}

// REMOVE
removeById(_id) {
return this.remove(_id);
}
}

export default new Tags();
5 changes: 5 additions & 0 deletions app/models/server/raw/Tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { BaseRaw } from './BaseRaw';

export class TagsRaw extends BaseRaw {

}
3 changes: 3 additions & 0 deletions app/models/server/raw/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import StatisticsModel from '../models/Statistics';
import { StatisticsRaw } from './Statistics';
import NotificationQueueModel from '../models/NotificationQueue';
import { NotificationQueueRaw } from './NotificationQueue';
import TagsModel from '../models/Tags';
import { TagsRaw } from './Tags';
import { ErrandsRaw } from './ErrandsRaw';
import Errands from '../models/Errands';

Expand Down Expand Up @@ -77,3 +79,4 @@ export const CustomUserStatus = new CustomUserStatusRaw(CustomUserStatusModel.mo
export const LivechatAgentActivity = new LivechatAgentActivityRaw(LivechatAgentActivityModel.model.rawCollection());
export const Statistics = new StatisticsRaw(StatisticsModel.model.rawCollection());
export const NotificationQueue = new NotificationQueueRaw(NotificationQueueModel.model.rawCollection());
export const Tags = new TagsRaw(TagsModel.model.rawCollection());
1 change: 1 addition & 0 deletions app/reactions/client/stylesheets/reaction.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
& .reactions {
margin-top: 4px;
padding: 0;
display: inline-block;

& > li {
position: relative;
Expand Down
6 changes: 6 additions & 0 deletions app/tag-picker/client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import './tagPicker';
import { TagPicker } from './lib/TagPicker';

export {
TagPicker,
};
94 changes: 94 additions & 0 deletions app/tag-picker/client/lib/TagPicker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import _ from 'underscore';
import { Blaze } from 'meteor/blaze';
import { Template } from 'meteor/templating';

export const TagPicker = {
width: 365,
height: 300,
initiated: false,
input: null,
source: null,
opened: false,
pickCallback: null,
scrolling: false,
async init() {
if (this.initiated) {
return;
}

this.initiated = true;

Blaze.render(Template.tagPicker, document.body);

$(document).click((event) => {
if (!this.opened) {
return;
}
if (!$(event.target).closest('.tag-picker').length && !$(event.target).is('.tag-picker')) {
if (this.opened) {
this.close();
}
}
});

$(window).resize(_.debounce(() => {
if (!this.opened) {
return;
}
this.setPosition();
}, 300));
},
isOpened() {
return this.opened;
},
setPosition() {
const windowHeight = window.innerHeight;
const windowWidth = window.innerWidth;
const windowBorder = 10;
const sourcePos = $(this.source).offset();
const {left, top} = sourcePos;
const cssProperties = {top, left};
const isLargerThanWindow = this.width + windowBorder > windowWidth;

if (top + this.height >= windowHeight) {
cssProperties.top = windowHeight - this.height - windowBorder - 75;
}

if (left < windowBorder) {
cssProperties.left = isLargerThanWindow ? 0 : windowBorder;
}

if (left + this.width >= windowWidth) {
cssProperties.left = isLargerThanWindow ? 0 : windowWidth - this.width - windowBorder;
}

return $('.tag-picker').css(cssProperties);
},
async open(source, callback) {
if (!this.initiated) {
await this.init();
}
this.pickCallback = callback;
this.source = source;

const containerEl = this.setPosition();
containerEl.addClass('show');

const tagInput = containerEl.find('.js-tagpicker-search');
if (tagInput) {
tagInput.focus();
}

this.opened = true;
},
close() {
$('.tag-picker').removeClass('show');
this.opened = false;
this.source.focus();
},
pickTag(tag) {
this.pickCallback(tag);

this.close();
},
};
29 changes: 29 additions & 0 deletions app/tag-picker/client/tagPicker.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template name="tagPicker">
<div class="tag-picker rc-popover__content">
<div class="tag-top">
<div class="rc-input">
<label class="rc-input__label">
<div class="rc-input__wrapper">
<div class="rc-input__icon">
{{> icon block="rc-input__icon-svg" icon="magnifier" }}
</div>
<input name="name" type="text" class="rc-input__element js-tagpicker-search" placeholder="{{_ "Search"}}" autofocus autocomplete="off">
</div>
</label>
</div>
</div>
<div class="tags">
<ul class="tag-list">
{{#each tags}}
<li class="tag-{{_id}} tag-picker-item" data-tag="{{_id}}" title="{{name}}">
<span>{{name}}</span>
</li>
{{else}}
<li class="tag-new tag-picker-item" data-tag="new">
<span>{{_ "Tag_Add"}} {{filter}}</span>
</li>
{{/each}}
</ul>
</div>
</div>
</template>
Loading

0 comments on commit c804c4a

Please sign in to comment.