[NEW]Added file type filter to RoomFiles (#15289)

pull/15317/head^2
Juan Petterson 6 years ago committed by Guilherme Gazzo
parent 7d29c68fe4
commit 28e290cc46
  1. 34
      app/models/server/models/Uploads.js
  2. 9
      app/theme/client/imports/forms/select.css
  3. 37
      app/ui-flextab/client/tabs/uploadedFilesList.html
  4. 15
      app/ui-flextab/client/tabs/uploadedFilesList.js
  5. 5
      packages/rocketchat-i18n/i18n/en.i18n.json
  6. 5
      packages/rocketchat-i18n/i18n/pt-BR.i18n.json
  7. 4
      server/lib/roomFiles.js
  8. 1
      server/startup/migrations/index.js
  9. 28
      server/startup/migrations/v163.js

@ -4,6 +4,14 @@ import { InstanceStatus } from 'meteor/konecty:multiple-instances-status';
import { Base } from './_Base';
const fillTypeGroup = (fileData) => {
if (!fileData.type) {
return;
}
fileData.typeGroup = fileData.type.split('/').shift();
};
export class Uploads extends Base {
constructor() {
super('uploads');
@ -14,9 +22,10 @@ export class Uploads extends Base {
this.tryEnsureIndex({ rid: 1 });
this.tryEnsureIndex({ uploadedAt: 1 });
this.tryEnsureIndex({ typeGroup: 1 });
}
findNotHiddenFilesOfRoom(roomId, searchText, limit) {
findNotHiddenFilesOfRoom(roomId, searchText, fileType, limit) {
const fileQuery = {
rid: roomId,
complete: true,
@ -30,6 +39,10 @@ export class Uploads extends Base {
fileQuery.name = { $regex: new RegExp(RegExp.escape(searchText), 'i') };
}
if (fileType && fileType !== 'all') {
fileQuery.typeGroup = fileType;
}
const fileOptions = {
limit,
sort: {
@ -44,12 +57,28 @@ export class Uploads extends Base {
type: 1,
url: 1,
uploadedAt: 1,
typeGroup: 1,
},
};
return this.find(fileQuery, fileOptions);
}
insert(fileData, ...args) {
fillTypeGroup(fileData);
return super.insert(fileData, ...args);
}
update(filter, update, ...args) {
if (update.$set) {
fillTypeGroup(update.$set);
} else if (update.type) {
fillTypeGroup(update);
}
return super.update(filter, update, ...args);
}
insertFileInit(userId, store, file, extra) {
const fileData = {
userId,
@ -64,6 +93,7 @@ export class Uploads extends Base {
_.extend(fileData, file, extra);
if (this.model.direct && this.model.direct.insert != null) {
fillTypeGroup(fileData);
file = this.model.direct.insert(fileData);
} else {
file = this.insert(fileData);
@ -94,6 +124,8 @@ export class Uploads extends Base {
update.$set = _.extend(file, update.$set);
if (this.model.direct && this.model.direct.update != null) {
fillTypeGroup(update.$set);
result = this.model.direct.update(filter, update);
} else {
result = this.update(filter, update);

@ -65,6 +65,15 @@
}
}
.rc-select-wrapper {
display: flex;
flex: 0 0 auto;
padding: 0.5rem 0;
align-items: flex-end;
}
.rtl .rc-select__element {
padding: 0 1rem 0 2rem;
}

@ -1,17 +1,32 @@
<template name="uploadedFilesList">
<form class="search-form" role="form">
<div class="rc-input">
<label class="rc-input__label">
<div class="rc-input__title">{{_ "Search_by_file_name"}}</div>
<div class="rc-input__wrapper">
<div class="rc-input__icon">
{{> icon block="rc-input__icon-svg" icon="magnifier"}}
<div class="flex-tab__header">
<form class="search-form rc-member-list__search js-search-form" role="form">
<div class="rc-input">
<label class="rc-input__label">
<div class="rc-input__title">{{_ "Search_by_file_name"}}</div>
<div class="rc-input__wrapper">
<div class="rc-input__icon">
{{> icon block="rc-input__icon-svg" icon="magnifier"}}
</div>
<input type="text" class="rc-input__element uploaded-files-list__search-input" name="file-search" placeholder={{_ "File_name_Placeholder"}} autocomplete="off" />
</div>
<input type="text" class="rc-input__element uploaded-files-list__search-input" name="file-search" placeholder={{_ "File_name_Placeholder"}} autocomplete="off" />
</label>
</div>
<div class="rc-select-wrapper">
<div class="rc-select">
<select class="rc-select__element js-type" name="status-type">
<option value="all">{{_ 'All'}}</option>
<option value="image">{{_ 'Images'}}</option>
<option value="video">{{_ 'Videos'}}</option>
<option value="audio">{{_ 'Audios'}}</option>
<option value="text">{{_ 'Texts'}}</option>
<option value="application">{{_ 'Files'}}</option>
</select>
{{> icon block="rc-select__arrow" icon="arrow-down" }}
</div>
</label>
</div>
</form>
</div>
</form>
</div>
<div class="flex-tab__result">
<ul class="attachments">
{{#each files}}

@ -51,8 +51,12 @@ Template.uploadedFilesList.onCreated(function() {
const { rid } = Template.currentData();
const room = Rooms.findOne({ _id: rid });
this.searchText = new ReactiveVar(null);
this.showFileType = new ReactiveVar('all');
this.roomFiles = new ReactiveVar([]);
this.files = new Mongo.Collection(null);
this.state = new ReactiveDict({
limit: LIST_SIZE,
hasMore: true,
@ -103,6 +107,13 @@ Template.uploadedFilesList.onCreated(function() {
});
this.autorun(() => {
if (this.showFileType.get() === 'all') {
delete query.typeGroup;
} else {
this.files.remove({});
query.typeGroup = this.showFileType.get();
}
const limit = this.state.get('limit');
const searchText = this.searchText.get();
if (!searchText) {
@ -220,6 +231,10 @@ Template.uploadedFilesList.events({
}
}, 200),
'change .js-type'(e, t) {
t.showFileType.set(e.currentTarget.value);
},
'click .js-action'(e) {
e.currentTarget.parentElement.classList.add('active');

@ -398,6 +398,7 @@
"Attachment_File_Uploaded": "File Uploaded",
"Attribute_handling": "Attribute handling",
"Audio": "Audio",
"Audios": "Audios",
"Audio_message": "Audio message",
"Audio_Notification_Value_Description": "Can be any custom sound or the default ones: beep, chelle, ding, droplet, highbell, seasons",
"Audio_Notifications_Default_Alert": "Audio Notifications Default Alert",
@ -1392,6 +1393,7 @@
"Field": "Field",
"Field_removed": "Field removed",
"Field_required": "Field required",
"Files": "Files",
"File_exceeds_allowed_size_of_bytes": "File exceeds allowed size of __size__.",
"File_name_Placeholder": "Search files...",
"File_removed_by_automatic_prune": "File removed by automatic prune",
@ -1591,6 +1593,7 @@
"Iframe_Integration_send_target_origin_Description": "Origin with protocol prefix, which commands are sent to e.g. 'https://localhost', or * to allow sending to anywhere.",
"Ignore": "Ignore",
"Ignored": "Ignored",
"Images": "Images",
"IMAP_intercepter_already_running": "IMAP intercepter already running",
"IMAP_intercepter_Not_running": "IMAP intercepter Not running",
"Impersonate_next_agent_from_queue": "Impersonate next agent from queue",
@ -2967,6 +2970,7 @@
"Telecom": "Telecom",
"Test_Connection": "Test Connection",
"Test_Desktop_Notifications": "Test Desktop Notifications",
"Texts": "Texts",
"Thank_you_exclamation_mark": "Thank you!",
"Thank_you_for_your_feedback": "Thank you for your feedback",
"The_application_name_is_required": "The application name is required",
@ -3283,6 +3287,7 @@
"Verify": "Verify",
"Verify_your_email": "Verify your email",
"Version": "Version",
"Videos": "Videos",
"Video Conference": "Video Conference",
"Video_Chat_Window": "Video Chat",
"Video_Conference": "Video Conference",

@ -375,6 +375,7 @@
"Attachment_File_Uploaded": "Arquivo Carregado",
"Attribute_handling": "Manipulação de atributos",
"Audio": "Áudio",
"Audios": "Áudios",
"Audio_message": "Mensagem de áudio",
"Audio_Notification_Value_Description": "Pode ser qualquer som personalizado ou padrão: beep, chelle, ding, droplet, highbell, estações",
"Audio_Notifications_Default_Alert": "Alertas de notificação de áudio Alerta padrão",
@ -1375,6 +1376,7 @@
"FileUpload_Webdav_Proxy_Avatars_Description": "Transmissões de arquivos de avatar proxy por meio de seu servidor, em vez de acesso direto ao URL do recurso",
"FileUpload_Webdav_Proxy_Uploads": "Uploads de proxy",
"FileUpload_Webdav_Proxy_Uploads_Description": "Transmissões de arquivo de upload de proxy por meio de seu servidor, em vez de acesso direto ao URL do recurso",
"Files": "Arquivos",
"files": "arquivos",
"Files_only": "Apenas remova os arquivos anexados, mantenha mensagens",
"FileSize_KB": "__fileSize__ KB",
@ -1512,6 +1514,7 @@
"Iframe_Integration_send_target_origin_Description": "Origem com o prefixo do protocolo, quais comandos são enviados para e. 'https: // localhost', ou * para permitir o envio para qualquer lugar.",
"Ignore": "Ignorar",
"Ignored": "Ignorado",
"Images": "Imagens",
"IMAP_intercepter_already_running": "O interceptor IMAP já está sendo executado",
"IMAP_intercepter_Not_running": "Interceptor IMAP Não está funcionando",
"Impersonate_next_agent_from_queue": "Representar o próximo agente da fila",
@ -2788,6 +2791,7 @@
"Telecom": "Telecom",
"Test_Connection": "Testar Conexão",
"Test_Desktop_Notifications": "Testar Notificações de Desktop",
"Texts": "Textos",
"Thank_you_exclamation_mark": "Obrigado!",
"Thank_you_for_your_feedback": "Obrigado pelo seu feedback",
"The_application_name_is_required": "O nome da aplicação é obrigatório",
@ -3099,6 +3103,7 @@
"Verify": "Verificar",
"Verify_your_email": "Verifique seu e-mail",
"Version": "Versão",
"Videos": "Vídeos",
"Video Conference": "Vídeo Conferência",
"Video_Chat_Window": "Vídeo Chat",
"Video_Conference": "Vídeo Conferência",

@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { Users, Uploads } from '../../app/models';
export const roomFiles = (pub, { rid, searchText, limit = 50 }) => {
export const roomFiles = (pub, { rid, searchText, fileType, limit = 50 }) => {
if (!pub.userId) {
return pub.ready();
}
@ -11,7 +11,7 @@ export const roomFiles = (pub, { rid, searchText, limit = 50 }) => {
return this.ready();
}
const cursorFileListHandle = Uploads.findNotHiddenFilesOfRoom(rid, searchText, limit).observeChanges({
const cursorFileListHandle = Uploads.findNotHiddenFilesOfRoom(rid, searchText, fileType, limit).observeChanges({
added(_id, record) {
const { username, name } = record.userId ? Users.findOneById(record.userId) : {};
return pub.added('room_files', _id, { ...record, user: { username, name } });

@ -160,4 +160,5 @@ import './v159';
import './v160';
import './v161';
import './v162';
import './v163';
import './xrun';

@ -0,0 +1,28 @@
import { Migrations } from '../../../app/migrations';
import { Uploads } from '../../../app/models';
Migrations.add({
version: 163,
up() {
/*
* Migrate existing `rocketchat_uploads` documents to include the typeGroup
*/
Uploads.find({
type: {
$exists: true,
},
typeGroup: {
$exists: false,
},
}).forEach((upload) => {
Uploads.model.direct.update({
_id: upload._id,
}, {
$set: {
typeGroup: upload.type.split('/').shift(),
},
});
});
},
});
Loading…
Cancel
Save