[IMPROVE] Admin ui step 1 (#13393)

Just few changes to update admin pages
pull/13410/head
Guilherme Gazzo 6 years ago committed by GitHub
parent 5842d7e49d
commit 687d51e0aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      packages/rocketchat-authorization/client/route.js
  2. 11
      packages/rocketchat-authorization/client/stylesheets/permissions.css
  3. 50
      packages/rocketchat-authorization/client/views/permissions.html
  4. 62
      packages/rocketchat-custom-sounds/client/admin/adminSounds.html
  5. 39
      packages/rocketchat-custom-sounds/client/admin/adminSounds.js
  6. 69
      packages/rocketchat-emoji-custom/client/admin/adminEmoji.html
  7. 23
      packages/rocketchat-emoji-custom/client/admin/adminEmoji.js
  8. 8
      packages/rocketchat-importer/client/admin/adminImport.html
  9. 4
      packages/rocketchat-importer/client/admin/adminImportHistory.html
  10. 2
      packages/rocketchat-importer/client/admin/adminImportPrepare.html
  11. 4
      packages/rocketchat-integrations/client/stylesheets/integrations.css
  12. 3
      packages/rocketchat-oauth2-server-config/client/admin/route.js
  13. 13
      packages/rocketchat-oauth2-server-config/client/admin/views/oauthApps.html
  14. 64
      packages/rocketchat-ui-admin/client/rooms/adminRooms.html
  15. 37
      packages/rocketchat-ui-admin/client/rooms/adminRooms.js
  16. 99
      packages/rocketchat-ui-admin/client/users/adminUsers.html
  17. 24
      packages/rocketchat-ui-admin/client/users/adminUsers.js
  18. 1
      packages/rocketchat-ui-admin/server/publications/adminRooms.js
  19. 73
      packages/rocketchat-ui/client/components/header/header.html
  20. 147
      packages/rocketchat-ui/client/components/header/header.js
  21. 81
      packages/rocketchat-ui/client/components/header/headerRoom.html
  22. 170
      packages/rocketchat-ui/client/components/header/headerRoom.js
  23. 2
      packages/rocketchat-ui/client/index.js
  24. 4
      packages/rocketchat-ui/client/views/app/room.html
  25. 4
      packages/rocketchat-ui/client/views/app/room.js
  26. 2
      packages/rocketchat_theme/client/imports/components/contextual-bar.css
  27. 54
      packages/rocketchat_theme/client/imports/components/header.css
  28. 3
      packages/rocketchat_theme/client/imports/components/modal/directory.css
  29. 2
      packages/rocketchat_theme/client/imports/components/setup-wizard.css
  30. 2
      packages/rocketchat_theme/client/imports/components/tabs.css
  31. 2
      packages/rocketchat_theme/client/imports/general/base.css
  32. 81
      packages/rocketchat_theme/client/imports/general/base_old.css
  33. 3
      packages/rocketchat_theme/client/imports/general/variables.css
  34. 6
      packages/rocketchat_theme/server/colors.less
  35. 2
      tests/pageobjects/administration.page.js

@ -6,9 +6,8 @@ FlowRouter.route('/admin/permissions', {
name: 'admin-permissions',
action(/* params*/) {
return BlazeLayout.render('main', {
center: 'pageContainer',
center: 'permissions',
pageTitle: t('Permissions'),
pageTemplate: 'permissions',
});
},
});

@ -10,13 +10,20 @@
}
& .permission-grid {
& table {
display: block;
overflow-x: auto;
white-space: nowrap;
}
& th {
position: relative;
padding-top: 20px;
padding: 20px;
text-align: center;
white-space: normal;
white-space: nowrap;
}
& td {

@ -1,36 +1,46 @@
<template name="permissions">
<div class="permissions-manager">
<section class="permissions-manager page-container page-home page-static page-list">
{{#if hasPermission}}
<a href="{{pathFor "admin-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a>
<table border="1" class="permission-grid secondary-background-color">
<thead class="content-background-color">
<tr>
<th class="border-component-color">&nbsp;</th>
{{#each role}}
{{# header sectionName=pageTitle}}
<div class="rc-header__section-button">
<a href="{{pathFor"admin-permissions-new"}}" class="rc-button rc-button--primary new-role">{{_ "New_role"}}</a>
</div>
{{/header}}
<div class="content">
<table border="1" class="permission-grid secondary-background-color">
<thead class="content-background-color">
<tr>
<th class="border-component-color">&nbsp;</th>
{{#each role}}
<th class="border-component-color" title="{{description}}">
<a href="{{pathFor "admin-permissions-edit" name=_id}}">
{{_id}}
<i class="icon-edit"></i>
</a>
</th>
{{/each}}
</tr>
</thead>
<tbody>
{{#each permission}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each permission}}
<tr class="admin-table-row">
<td class="permission-name border-component-color" title="{{_ permissionDescription}}">{{_ permissionName}}<br>[{{_id}}]</td>
{{#each role}}
<td class="border-component-color">
<input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles}}" data-role="{{_id}}" data-permission="{{../_id}}">
</td>
<td class="border-component-color">
<input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles}}" data-role="{{_id}}" data-permission="{{../_id}}">
</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
{{/each}}
</tbody>
</table>
</div>
{{else}}
{{_ "Not_authorized"}}
<div class="content">
{{#if i18nPageTitle}} {{> header sectionName=i18nPageTitle}} {{else}} {{> header sectionName=pageTitle}} {{/if}}
{{_ "Not_authorized"}}
</div>
{{/if}}
</div>
</section>
</template>

@ -20,25 +20,49 @@
<div class="results">
{{{_ "Showing_results" customsounds.length}}}
</div>
<div class="list">
<table>
<thead>
<tr>
<th width="100%">{{_ "Name"}}</th>
</tr>
</thead>
<tbody>
{{#each customsounds}}
<tr class="sound-info row-link">
<td>{{name}}&nbsp;<i class="icon-play-circled"></i></td>
</tr>
{{/each}}
</tbody>
</table>
{{#if hasMore}}
<button class="button secondary load-more {{isLoading}}">{{_ "Load_more"}}</button>
{{/if}}
</div>
{{#table fixed='true' onItemClick=onTableItemClick onScroll=onTableScroll onResize=onTableResize}}
<thead>
<tr>
<th width="95%">
<div class="table-fake-th">{{_ "Name"}}</div>
</th>
<th width="5%">
<div class="table-fake-th">{{_ "Action"}}</div>
</th>
</tr>
</thead>
<tbody>
{{#each customsounds}}
<tr>
<td width="95%">
<div class="rc-table-wrapper">
<div class="rc-table-info">
<span class="rc-table-title">
{{name}}
</span>
</div>
</div>
</td>
<td width="5%">
<div class="rc-table-wrapper">
{{>icon _id=_id icon="play" block="icon-play-circled"}}
</div>
</td>
</tr>
{{else}}
{{# with searchText}}
<tr class="table-no-click">
<td>{{_ "No_results_found_for"}} {{.}}</td>
</tr>
{{/with}}
{{/each}}
{{#unless isReady}}
<tr class="table-no-click">
<td class="table-loading-td">{{> loading}}</td>
</tr>
{{/unless}}
</tbody>
{{/table}}
{{/requiresPermission}}
</div>
</section>

@ -7,6 +7,10 @@ import { CustomSounds } from 'meteor/rocketchat:models';
import s from 'underscore.string';
Template.adminSounds.helpers({
searchText() {
const instance = Template.instance();
return instance.filter && instance.filter.get();
},
isReady() {
if (Template.instance().ready != null) {
return Template.instance().ready.get();
@ -37,6 +41,26 @@ Template.adminSounds.helpers({
data: Template.instance().tabBarData.get(),
};
},
onTableScroll() {
const instance = Template.instance();
return function(currentTarget) {
if (
currentTarget.offsetHeight + currentTarget.scrollTop >=
currentTarget.scrollHeight - 100
) {
return instance.limit.set(instance.limit.get() + 50);
}
};
},
onTableItemClick() {
const instance = Template.instance();
return function(item) {
instance.tabBarData.set(CustomSounds.findOne({ _id: item._id }));
instance.tabBar.showGroup('custom-sounds-selected');
instance.tabBar.open('admin-sound-info');
};
},
});
Template.adminSounds.onCreated(function() {
@ -108,26 +132,11 @@ Template.adminSounds.events({
e.preventDefault();
}
},
'keyup #sound-filter'(e, t) {
e.stopPropagation();
e.preventDefault();
t.filter.set(e.currentTarget.value);
},
'click .sound-info'(e, instance) {
e.preventDefault();
instance.tabBarData.set(CustomSounds.findOne({ _id: this._id }));
instance.tabBar.showGroup('custom-sounds-selected');
instance.tabBar.open('admin-sound-info');
},
'click .load-more'(e, t) {
e.preventDefault();
e.stopPropagation();
t.limit.set(t.limit.get() + 50);
},
'click .icon-play-circled'(e) {
e.preventDefault();
e.stopPropagation();

@ -22,33 +22,50 @@
<div class="results">
{{{_ "Showing_results" customemoji.length}}}
</div>
<div class="list">
<table class="secondary-background-color">
<thead>
<tr class="admin-table-row">
<th class="content-background-color border-component-color">&nbsp;</th>
<th class="content-background-color border-component-color" width="51%">{{_ "Name"}}</th>
<th class="content-background-color border-component-color" width="49%">{{_ "Aliases"}}</th>
</tr>
</thead>
<tbody>
{{#each customemoji}}
<tr class="emoji-info row-link admin-table-row">
<td class="border-component-color">
<div class="emojiAdminPreview-image">
{{> emojiPreview name=name extension=extension}}
{{#table fixed='true' onItemClick=onTableItemClick onScroll=onTableScroll onResize=onTableResize}}
<thead>
<tr>
<th width="50%">
<div class="table-fake-th">{{_ "Name"}}</div>
</th>
<th width="50%">
<div class="table-fake-th">{{_ "Aliases"}}</div>
</th>
</tr>
</thead>
<tbody>
{{#each customemoji}}
<tr>
<td width="50%">
<div class="rc-table-wrapper">
<div class="rc-table-info">
<span class="rc-table-title">
{{name}}
</span>
</div>
</td>
<td class="border-component-color">{{name}}</td>
<td class="border-component-color">{{aliases}}</td>
</tr>
{{/each}}
</tbody>
</table>
{{#if hasMore}}
<button class="button secondary load-more {{isLoading}}">{{_ "Load_more"}}</button>
{{/if}}
</div>
</div>
</td>
<td width="50%">
<div class="rc-table-wrapper">
<div class="rc-table-info">
<span class="rc-table-title">
{{aliases}}
</span>
</div>
</div>
</td>
</tr>
{{else}} {{# with searchText}}
<tr class="table-no-click">
<td>{{_ "No_results_found_for"}} {{.}}</td>
</tr>
{{/with}} {{/each}} {{#unless isReady}}
<tr class="table-no-click">
<td class="table-loading-td">{{> loading}}</td>
</tr>
{{/unless}}
</tbody>
{{/table}}
{{/unless}}
</div>
</section>

@ -7,6 +7,10 @@ import { SideNav } from 'meteor/rocketchat:ui';
import s from 'underscore.string';
Template.adminEmoji.helpers({
searchText() {
const instance = Template.instance();
return instance.filter && instance.filter.get();
},
isReady() {
if (Template.instance().ready != null) {
return Template.instance().ready.get();
@ -37,6 +41,13 @@ Template.adminEmoji.helpers({
data: Template.instance().tabBarData.get(),
};
},
onTableItemClick() {
const instance = Template.instance();
return function({ _id }) {
instance.tabBarData.set(RocketChat.models.EmojiCustom.findOne({ _id }));
instance.tabBar.open('admin-emoji-info');
};
},
});
Template.adminEmoji.onCreated(function() {
@ -110,16 +121,4 @@ Template.adminEmoji.events({
e.preventDefault();
t.filter.set(e.currentTarget.value);
},
'click .emoji-info'(e, instance) {
e.preventDefault();
instance.tabBarData.set(RocketChat.models.EmojiCustom.findOne({ _id: this._id }));
instance.tabBar.open('admin-emoji-info');
},
'click .load-more'(e, t) {
e.preventDefault();
e.stopPropagation();
t.limit.set(t.limit.get() + 50);
},
});

@ -1,6 +1,6 @@
<template name="adminImport">
<section class="page-container page-home page-static page-settings">
{{> header sectionName="Import"}}
{{> header sectionName="Import" fullpage="true"}}
<div class="content">
{{#unless isAdmin}}
<p>{{_ "You_are_not_authorized_to_view_this_page"}}</p>
@ -12,8 +12,8 @@
<div class="section-content">
<div>{{_ "View the status of all import operations." }}</div>
<br/>
<button class="button primary import-history">{{_ "View History"}}</button>
<button class="rc-button rc-button--primary import-history">{{_ "View History"}}</button>
</div>
</div>
@ -26,7 +26,7 @@
<div class="section-content">
<div>{{getDescription .}}</div>
<br/>
<button class="button primary start-import">{{_ "Start"}}</button>
<button class="rc-button rc-button--primary start-import">{{_ "Start"}}</button>
</div>
</div>
{{/each}}

@ -1,6 +1,6 @@
<template name="adminImportHistory">
<section class="page-container page-home page-static page-settings">
{{> header sectionName="Recent_Import_History"}}
{{> header sectionName="Recent_Import_History" ullpage="true"}}
<div class="content">
{{#unless isAdmin}}
<p>{{_ "You_are_not_authorized_to_view_this_page"}}</p>
@ -8,7 +8,7 @@
{{#if isPreparing}}
{{> loading}}
{{else}}
<button class="button primary import-list">{{_ "Back"}}</button>
<button class="rc-button rc-button--primary import-list">{{_ "Back"}}</button>
{{#each history}}
<div class="section">

@ -1,7 +1,7 @@
<template name="adminImportPrepare">
<section class="page-container page-home page-static page-settings">
{{#with importer}}
{{> header sectionName=name}}
{{> header sectionName=name fullpage="true"}}
<div class="content">
{{#unless isAdmin}}
<p>{{_ "You_are_not_authorized_to_view_this_page"}}</p>

@ -53,10 +53,6 @@
}
}
.zapier-btn {
margin-right: 5px;
}
.integrate-other-ways {
& p {
font-size: 1rem;

@ -6,9 +6,8 @@ FlowRouter.route('/admin/oauth-apps', {
name: 'admin-oauth-apps',
action() {
return BlazeLayout.render('main', {
center: 'pageSettingsContainer',
center: 'oauthApps',
pageTitle: t('OAuth_Applications'),
pageTemplate: 'oauthApps',
});
},
});

@ -1,8 +1,12 @@
<template name="oauthApps">
<div class="permissions-manager">
<section class="permissions-manager page-container page-home page-static page-list">
{{# header sectionName=pageTitle}}
<div class="rc-header__section-button">
<a href="{{pathFor "admin-oauth-app"}}" class="rc-button rc-button--primary new-role">{{_ "New_Application"}}</a>
</div>
{{/header}}
<div class="content">
{{#if hasPermission}}
<a href="{{pathFor "admin-oauth-app"}}" class="button primary new-role">{{_ "New_Application"}}</a>
<div class="rocket-form">
<div class="section">
<div class="admin-integrations-new-panel">
@ -29,5 +33,6 @@
{{else}}
{{_ "Not_authorized"}}
{{/if}}
</div>
</div>
</section>
</template>

@ -1,7 +1,7 @@
<template name="adminRooms">
<div class="main-content-flex">
<section class="page-container page-list flex-tab-main-content">
{{> header sectionName="Rooms"}}
{{> header sectionName="Rooms" fixedHeight="true" fullpage="true"}}
<div class="content">
{{#unless hasPermission 'view-room-administration'}}
<p>{{_ "You_are_not_authorized_to_view_this_page"}}</p>
@ -25,33 +25,45 @@
<div class="results">
{{{_ "Showing_results" roomCount}}}
</div>
<div class="list">
<table class="secondary-background-color">
<thead>
<tr class="admin-table-row">
<th class="content-background-color border-component-color" width="30%">{{_ "Name"}}</th>
<th class="content-background-color border-component-color" width="20%">{{_ "Type"}}</th>
<th class="content-background-color border-component-color" width="20%">{{_ "Users"}}</th>
<th class="content-background-color border-component-color" width="10%">{{_ "Msgs"}}</th>
<th class="content-background-color border-component-color" width="20%">{{_ "Default"}}</th>
{{#table fixed='true' onItemClick=onTableItemClick onScroll=onTableScroll onResize=onTableResize}}
<thead>
<tr>
<th width="30%"><div class="table-fake-th">{{_ "Name"}}</div></th>
<th width="20%"><div class="table-fake-th">{{_ "Type"}}</div></th>
<th width="20%"><div class="table-fake-th">{{_ "Users"}}</div></th>
<th width="10%"><div class="table-fake-th">{{_ "Msgs"}}</div></th>
<th width="20%"><div class="table-fake-th">{{_ "Default"}}</div></th>
</tr>
</thead>
<tbody>
{{#each rooms}}
<tr>
<td width="30%"><div class="rc-table-wrapper">
<div class="rc-table-avatar">{{> avatar username=name roomIcon="true"}}</div>
<div class="rc-table-info">
<span class="rc-table-title">
{{>icon icon="hashtag" block="rc-directory-icon"}} {{name}}
</span>
</div>
</div></td>
<td width="20%"><div class="rc-table-wrapper">{{type}}</div></td>
<td width="20%"><div class="rc-table-wrapper">{{usersCount}}</div></td>
<td width="10%"><div class="rc-table-wrapper">{{msgs}}</div></td>
<td width="20%"><div class="rc-table-wrapper">{{default}}</div></td>
</tr>
</thead>
<tbody>
{{#each rooms}}
<tr class="room-info row-link">
<td class="border-component-color">{{name}}</td>
<td class="border-component-color">{{type}}</td>
<td class="border-component-color">{{usernames.length}}</td>
<td class="border-component-color">{{msgs}}</td>
<td class="border-component-color">{{default}}</td>
{{else}} {{# with searchText}}
<tr class="table-no-click">
<td>{{_ "No_results_found_for"}} {{.}}</td>
</tr>
{{/with}}
{{/each}}
{{#unless isReady}}
<tr class="table-no-click">
<td class="table-loading-td" colspan="{{#if showLastMessage}}5{{else}}4{{/if}}">{{> loading}}</td>
</tr>
{{/each}}
</tbody>
</table>
{{#if hasMore}}
<button class="button secondary load-more {{isLoading}}">{{_ "Load_more"}}</button>
{{/if}}
</div>
{{/unless}}
</tbody>
{{/table}}
{{/unless}}
</div>
</section>

@ -14,6 +14,10 @@ import s from 'underscore.string';
export const AdminChatRoom = new Mongo.Collection('rocketchat_room');
Template.adminRooms.helpers({
searchText() {
const instance = Template.instance();
return instance.filter && instance.filter.get();
},
isReady() {
const instance = Template.instance();
return instance.ready && instance.ready.get();
@ -55,6 +59,27 @@ Template.adminRooms.helpers({
tabBar: Template.instance().tabBar,
};
},
onTableScroll() {
const instance = Template.instance();
return function(currentTarget) {
if (
currentTarget.offsetHeight + currentTarget.scrollTop >=
currentTarget.scrollHeight - 100
) {
return instance.limit.set(instance.limit.get() + 50);
}
};
},
onTableItemClick() {
const instance = Template.instance();
return function(item) {
Session.set('adminRoomsSelected', {
rid: item._id,
});
instance.tabBar.open('admin-room');
};
},
});
Template.adminRooms.onCreated(function() {
@ -141,18 +166,6 @@ Template.adminRooms.events({
e.preventDefault();
t.filter.set(e.currentTarget.value);
},
'click .room-info'(e, instance) {
e.preventDefault();
Session.set('adminRoomsSelected', {
rid: this._id,
});
instance.tabBar.open('admin-room');
},
'click .load-more'(e, t) {
e.preventDefault();
e.stopPropagation();
t.limit.set(t.limit.get() + 50);
},
'change [name=room-type]'(e, t) {
t.types.set(t.getSearchTypes());
},

@ -22,40 +22,75 @@
<div class="results">
{{{_ "Showing_results" users.length}}}
</div>
<div class="list">
<table class="secondary-background-color">
<thead>
<tr class="admin-table-row">
<th class="content-background-color border-component-color">&nbsp;</th>
<th class="content-background-color border-component-color" width="34%">{{_ "Name"}}</th>
<th class="content-background-color border-component-color" width="33%">{{_ "Username"}}</th>
<th class="content-background-color border-component-color" width="33%">{{_ "Email"}}</th>
<th class="content-background-color border-component-color" width="33%">{{_ "Roles"}}</th>
<th class="content-background-color border-component-color" width="33%">{{_ "Status"}}</th>
</tr>
</thead>
<tbody>
{{#each users}}
<tr class="user-info row-link {{#if not active}}deactivated{{/if}}">
<td class="border-component-color">
<div class="user-image status-{{status}}">
{{#table fixed='true' onItemClick=onTableItemClick onScroll=onTableScroll onResize=onTableResize}}
<thead>
<tr>
<th width="34%">
<div class="table-fake-th">{{_ "Name"}}</div>
</th>
<th width="33%">
<div class="table-fake-th">{{_ "Username"}}</div>
</th>
<th width="33%">
<div class="table-fake-th">{{_ "Email"}}</div>
</th>
<th width="33%">
<div class="table-fake-th">{{_ "Roles"}}</div>
</th>
<th width="33%">
<div class="table-fake-th">{{_ "Status"}}</div>
</th>
</tr>
</thead>
<tbody>
{{#each users}}
<tr class='user-info'>
<td width="30%">
<div class="rc-table-wrapper">
<div class="rc-table-avatar">
{{> avatar username=username}}
</div>
</td>
<td class="border-component-color">{{name}}</td>
<td class="border-component-color">{{username}}</td>
<td class="border-component-color">{{emailAddress}}</td>
<td class="border-component-color">{{roles}}</td>
<td class="border-component-color">{{status}}</td>
</tr>
{{/each}}
</tbody>
</table>
{{#if hasMore}}
<button class="button secondary load-more {{isLoading}}">{{_ "Load_more"}}</button>
{{/if}}
</div>
<div class="rc-table-info">
<span class="rc-table-title">{{name}}</span>
</div>
</div>
</td>
<td width="20%">
<div class="rc-table-wrapper">
<div class="rc-table-info">
<span class="rc-table-title">{{username}}</span>
</div>
</div>
</td>
<td width="20%">
<div class="rc-table-wrapper">
<div class="rc-table-info">
<span class="rc-table-title">{{emailAddress}}</span>
</div>
</div>
</td>
<td width="10%">
<div class="rc-table-wrapper">
<div class="rc-table-info">
<span class="rc-table-title">{{roles}}</span>
</div>
</div>
</td>
<td width="20%">
<div class="rc-table-wrapper">{{#if not active}}{{_"deactivated"}}{{else}}{{status}}{{/if}}</div>
</td>
</tr>
{{else}} {{# with searchText}}
<tr class="table-no-click">
<td>{{_ "No_results_found_for"}} {{.}}</td>
</tr>
{{/with}} {{/each}} {{#unless isReady}}
<tr class="table-no-click">
<td class="table-loading-td" colspan="{{#if showLastMessage}}5{{else}}4{{/if}}">{{> loading}}</td>
</tr>
{{/unless}}
</tbody>
{{/table}}
{{/unless}}
</div>
</section>

@ -11,6 +11,10 @@ import s from 'underscore.string';
import { RocketChatTabBar } from 'meteor/rocketchat:lib';
Template.adminUsers.helpers({
searchText() {
const instance = Template.instance();
return instance.filter && instance.filter.get();
},
isReady() {
const instance = Template.instance();
return instance.ready && instance.ready.get();
@ -40,6 +44,26 @@ Template.adminUsers.helpers({
data: Template.instance().tabBarData.get(),
};
},
onTableScroll() {
const instance = Template.instance();
return function(currentTarget) {
if (
currentTarget.offsetHeight + currentTarget.scrollTop >=
currentTarget.scrollHeight - 100
) {
return instance.limit.set(instance.limit.get() + 50);
}
};
},
// onTableItemClick() {
// const instance = Template.instance();
// return function(item) {
// Session.set('adminRoomsSelected', {
// rid: item._id,
// });
// instance.tabBar.open('admin-room');
// };
// },
});
Template.adminUsers.onCreated(function() {

@ -21,6 +21,7 @@ Meteor.publish('adminRooms', function(filter, types, limit) {
cl: 1,
u: 1,
usernames: 1,
usersCount: 1,
muted: 1,
ro: 1,
default: 1,

@ -1,81 +1,30 @@
<template name="header">
<header class="rc-header{{#if fixedHeight}} rc-header--height-fixed{{/if}} {{#if fullpage}} rc-header--fullpage{{/if}}" >
<header class="rc-header">
<div class="rc-header__wrap">
<div class="rc-header__block rc-header--burger">
{{> burger}}
</div>
{{#if showToggleFavorite}}
<div class="rc-header__block rc-header__favorite">
<a href="#favorite" class="rc-header__toggle-favorite {{state}}">{{> icon block="rc-header__icon" icon="star"}}</a>
</div>
{{/if}}
<!-- TODO: fix it style and helper -->
{{#if tokenAccessChannel}}
<i class="icon-tokenpass" aria-label="{{_ "Tokenpass_Channel_Label"}}"></i>
{{/if}}
{{#if encryptedChannel}}
<i class="icon-key" aria-label="{{_ "Encrypted_Channel_Label"}}"></i>
{{/if}}
{{#if isChannel}}
<div class="rc-header__content rc-header__block">
{{#if isDirect}}
<div class="rc-header__image rc-header__block">
{{> avatar username=avatarBackground}}
</div>
{{/if}}
<div class="rc-header__data">
{{#unless secondaryName}}
<div class="rc-header__name">{{> icon block="rc-header__icon" icon=channelIcon}}{{roomName}}</div>
{{else}}
<div class="rc-header__name">{{roomName}} <div class="rc-header__username">@{{secondaryName}}</div></div>
{{/unless}}
{{#if isDirect}}
<span class="rc-header__status">
<div class="rc-header__status-bullet rc-header__status-bullet--{{userStatus}}" title="{{_ userStatus}}"></div>
<div class="rc-header__visual-status">{{_ userStatus}}</div>
</span>
{{else}}
{{#if roomTopic}}<span class="rc-header__topic">{{{roomTopic}}}</span>{{/if}}
{{/if}}
</div>
{{#if sentimentSmile}}
<span class="sentiment">{{sentimentSmile}}</span>
{{/if}}
{{#if isTranslated}}
<i class="icon-language" aria-label="{{_ "Translated"}}"></i>
{{/if}}
</div>
{{/if}}
{{#if isSection}}
<span class="rc-header__block">{{_ sectionName}}</span>
{{/if}}
{{#if Template.contentBlock}}
{{> Template.contentBlock}}
{{> Template.contentBlock}}
{{/if}}
{{#unless isChannel}}
{{# unless hideHelp}}
<div class="rc-header__section-help"></div>
{{/unless}}
<div class="rc-header__section-help"></div>
{{/unless}}
{{#with toolbarButtons}}
<div class="iframe-toolbar">
{{#each buttons}}
<button class="{{id}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</button>
{{/each}}
</div>
<div class="iframe-toolbar">
{{#each buttons}}
<button class="{{id}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</button>
{{/each}}
</div>
{{/with}}
</div>
</header>

@ -1,134 +1,13 @@
import { Meteor } from 'meteor/meteor';
import { Session } from 'meteor/session';
import { Template } from 'meteor/templating';
import { t, roomTypes, handleError } from 'meteor/rocketchat:utils';
import { TabBar, fireGlobalEvent } from 'meteor/rocketchat:ui-utils';
import { ChatSubscription, Rooms } from 'meteor/rocketchat:models';
import { settings } from 'meteor/rocketchat:settings';
const isSubscribed = (_id) => ChatSubscription.find({ rid: _id }).count() > 0;
const favoritesEnabled = () => settings.get('Favorite_Rooms');
Template.header.helpers({
back() {
return Template.instance().data.back;
},
avatarBackground() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData) { return ''; }
return roomTypes.getSecondaryRoomName(roomData.t, roomData) || roomTypes.getRoomName(roomData.t, roomData);
},
buttons() {
return TabBar.getButtons();
},
isTranslated() {
const sub = ChatSubscription.findOne({ rid: this._id }, { fields: { autoTranslate: 1, autoTranslateLanguage: 1 } });
return settings.get('AutoTranslate_Enabled') && ((sub != null ? sub.autoTranslate : undefined) === true) && (sub.autoTranslateLanguage != null);
},
state() {
const sub = ChatSubscription.findOne({ rid: this._id }, { fields: { f: 1 } });
if (((sub != null ? sub.f : undefined) != null) && sub.f && favoritesEnabled()) { return ' favorite-room'; }
return 'empty';
},
favoriteLabel() {
const sub = ChatSubscription.findOne({ rid: this._id }, { fields: { f: 1 } });
if (((sub != null ? sub.f : undefined) != null) && sub.f && favoritesEnabled()) { return 'Unfavorite'; }
return 'Favorite';
},
isDirect() {
return Rooms.findOne(this._id).t === 'd';
},
roomName() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData) { return ''; }
return roomTypes.getRoomName(roomData.t, roomData);
},
secondaryName() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData) { return ''; }
return roomTypes.getSecondaryRoomName(roomData.t, roomData);
},
roomTopic() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData || !roomData.topic) { return ''; }
let roomTopic = RocketChat.Markdown.parse(roomData.topic);
// &#39; to apostrophe (') for emojis such as :')
roomTopic = roomTopic.replace(/&#39;/g, '\'');
Object.keys(RocketChat.emoji.packages).forEach((emojiPackage) => {
roomTopic = RocketChat.emoji.packages[emojiPackage].render(roomTopic);
});
// apostrophe (') back to &#39;
roomTopic = roomTopic.replace(/\'/g, '&#39;');
return roomTopic;
},
channelIcon() {
const roomType = Rooms.findOne(this._id).t;
switch (roomType) {
case 'd':
return 'at';
case 'p':
return 'lock';
case 'c':
return 'hashtag';
case 'l':
return 'livechat';
default:
return roomTypes.getIcon(roomType);
}
},
roomIcon() {
const roomData = Session.get(`roomData${ this._id }`);
if (!(roomData != null ? roomData.t : undefined)) { return ''; }
return roomTypes.getIcon(roomData != null ? roomData.t : undefined);
},
encryptedChannel() {
const roomData = Session.get(`roomData${ this._id }`);
return roomData && roomData.encrypted;
},
userStatus() {
const roomData = Session.get(`roomData${ this._id }`);
return roomTypes.getUserStatus(roomData.t, this._id) || t('offline');
},
showToggleFavorite() {
if (isSubscribed(this._id) && favoritesEnabled()) { return true; }
},
fixedHeight() {
return Template.instance().data.fixedHeight;
},
fullpage() {
return Template.instance().data.fullpage;
},
isChannel() {
return Template.instance().currentChannel != null;
},
isSection() {
return Template.instance().data.sectionName != null;
},
});
Template.header.events({
@ -137,30 +16,4 @@ Template.header.events({
e.currentTarget.querySelector('button').blur();
return false;
},
'click .rc-header__toggle-favorite'(event) {
event.stopPropagation();
event.preventDefault();
return Meteor.call(
'toggleFavorite',
this._id,
!$(event.currentTarget).hasClass('favorite-room'),
(err) => err && handleError(err)
);
},
'click .edit-room-title'(event) {
event.preventDefault();
Session.set('editRoomTitle', true);
$('.rc-header').addClass('visible');
return Meteor.setTimeout(() =>
$('#room-title-field')
.focus()
.select(),
10);
},
});
Template.header.onCreated(function() {
this.currentChannel = (this.data && this.data._id && Rooms.findOne(this.data._id)) || undefined;
});

@ -0,0 +1,81 @@
<template name="headerRoom">
<header class="rc-header rc-header--room" >
<div class="rc-header__wrap">
<div class="rc-header__block rc-header--burger">
{{> burger}}
</div>
<div class="rc-header__block rc-header__favorite">
<a href="#favorite" class="rc-header__toggle-favorite {{state}}">{{> icon block="rc-header__icon" icon="star"}}</a>
</div>
<!-- TODO: fix it style and helper -->
{{#if tokenAccessChannel}}
<i class="icon-tokenpass" aria-label="{{_ "Tokenpass_Channel_Label"}}"></i>
{{/if}}
{{#if encryptedChannel}}
<i class="icon-key" aria-label="{{_ "Encrypted_Channel_Label"}}"></i>
{{/if}}
<div class="rc-header__content rc-header__block">
{{#if isDirect}}
<div class="rc-header__block">
<div class="rc-header__image">
{{> avatar username=avatarBackground}}
</div>
</div>
{{/if}}
<div class="rc-header__data">
{{#unless secondaryName}}
<div class="rc-header__name">{{> icon block="rc-header__icon" icon=channelIcon}}{{roomName}}</div>
{{else}}
<div class="rc-header__name">{{roomName}} <div class="rc-header__username">@{{secondaryName}}</div></div>
{{/unless}}
{{#if isDirect}}
<span class="rc-header__status">
<div class="rc-header__status-bullet rc-header__status-bullet--{{userStatus}}" title="{{_ userStatus}}"></div>
<div class="rc-header__visual-status">{{_ userStatus}}</div>
</span>
{{else}}
{{#if roomTopic}}<span class="rc-header__topic">{{{roomTopic}}}</span>{{/if}}
{{/if}}
</div>
{{#if sentimentSmile}}
<span class="sentiment">{{sentimentSmile}}</span>
{{/if}}
{{#if isTranslated}}
<i class="icon-language" aria-label="{{_ "Translated"}}"></i>
{{/if}}
</div>
{{#if isSection}}
<span class="rc-header__block">{{_ sectionName}}</span>
{{/if}}
{{#if Template.contentBlock}}
{{> Template.contentBlock}}
{{/if}}
{{#unless isChannel}}
{{# unless hideHelp}}
<div class="rc-header__section-help"></div>
{{/unless}}
{{/unless}}
{{#with toolbarButtons}}
<div class="iframe-toolbar">
{{#each buttons}}
<button class="{{id}}">
{{#if icon}}<i class="{{icon}}"></i>{{/if}}
{{label}}
</button>
{{/each}}
</div>
{{/with}}
</div>
</header>
</template>

@ -0,0 +1,170 @@
import { Meteor } from 'meteor/meteor';
import { Session } from 'meteor/session';
import { Template } from 'meteor/templating';
import { t, roomTypes, handleError } from 'meteor/rocketchat:utils';
import { TabBar, fireGlobalEvent } from 'meteor/rocketchat:ui-utils';
import { ChatSubscription, Rooms } from 'meteor/rocketchat:models';
import { settings } from 'meteor/rocketchat:settings';
const isSubscribed = (_id) => ChatSubscription.find({ rid: _id }).count() > 0;
const favoritesEnabled = () => settings.get('Favorite_Rooms');
Template.headerRoom.helpers({
back() {
return Template.instance().data.back;
},
avatarBackground() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData) { return ''; }
return roomTypes.getSecondaryRoomName(roomData.t, roomData) || roomTypes.getRoomName(roomData.t, roomData);
},
buttons() {
return TabBar.getButtons();
},
isTranslated() {
const sub = ChatSubscription.findOne({ rid: this._id }, { fields: { autoTranslate: 1, autoTranslateLanguage: 1 } });
return settings.get('AutoTranslate_Enabled') && ((sub != null ? sub.autoTranslate : undefined) === true) && (sub.autoTranslateLanguage != null);
},
state() {
const sub = ChatSubscription.findOne({ rid: this._id }, { fields: { f: 1 } });
if (((sub != null ? sub.f : undefined) != null) && sub.f && favoritesEnabled()) { return ' favorite-room'; }
return 'empty';
},
favoriteLabel() {
const sub = ChatSubscription.findOne({ rid: this._id }, { fields: { f: 1 } });
if (((sub != null ? sub.f : undefined) != null) && sub.f && favoritesEnabled()) { return 'Unfavorite'; }
return 'Favorite';
},
isDirect() {
return Rooms.findOne(this._id).t === 'd';
},
roomName() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData) { return ''; }
return roomTypes.getRoomName(roomData.t, roomData);
},
secondaryName() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData) { return ''; }
return roomTypes.getSecondaryRoomName(roomData.t, roomData);
},
roomTopic() {
const roomData = Session.get(`roomData${ this._id }`);
if (!roomData || !roomData.topic) { return ''; }
let roomTopic = RocketChat.Markdown.parse(roomData.topic);
// &#39; to apostrophe (') for emojis such as :')
roomTopic = roomTopic.replace(/&#39;/g, '\'');
Object.keys(RocketChat.emoji.packages).forEach((emojiPackage) => {
roomTopic = RocketChat.emoji.packages[emojiPackage].render(roomTopic);
});
// apostrophe (') back to &#39;
roomTopic = roomTopic.replace(/\'/g, '&#39;');
return roomTopic;
},
channelIcon() {
const roomType = Rooms.findOne(this._id).t;
switch (roomType) {
case 'd':
return 'at';
case 'p':
return 'lock';
case 'c':
return 'hashtag';
case 'l':
return 'livechat';
default:
return roomTypes.getIcon(roomType);
}
},
roomIcon() {
const roomData = Session.get(`roomData${ this._id }`);
if (!(roomData != null ? roomData.t : undefined)) { return ''; }
return roomTypes.getIcon(roomData != null ? roomData.t : undefined);
},
tokenAccessChannel() {
return Template.instance().hasTokenpass.get();
},
encryptedChannel() {
const roomData = Session.get(`roomData${ this._id }`);
return roomData && roomData.encrypted;
},
userStatus() {
const roomData = Session.get(`roomData${ this._id }`);
return roomTypes.getUserStatus(roomData.t, this._id) || t('offline');
},
showToggleFavorite() {
if (isSubscribed(this._id) && favoritesEnabled()) { return true; }
},
fixedHeight() {
return Template.instance().data.fixedHeight;
},
fullpage() {
return Template.instance().data.fullpage;
},
isChannel() {
return Template.instance().currentChannel != null;
},
isSection() {
return Template.instance().data.sectionName != null;
},
});
Template.headerRoom.events({
'click .iframe-toolbar .js-iframe-action'(e) {
fireGlobalEvent('click-toolbar-button', { id: this.id });
e.currentTarget.querySelector('button').blur();
return false;
},
'click .rc-header__toggle-favorite'(event) {
event.stopPropagation();
event.preventDefault();
return Meteor.call(
'toggleFavorite',
this._id,
!$(event.currentTarget).hasClass('favorite-room'),
(err) => err && handleError(err)
);
},
'click .edit-room-title'(event) {
event.preventDefault();
Session.set('editRoomTitle', true);
$('.rc-header').addClass('visible');
return Meteor.setTimeout(() =>
$('#room-title-field')
.focus()
.select(),
10);
},
});
Template.header.onCreated(function() {
this.currentChannel = (this.data && this.data._id && Rooms.findOne(this.data._id)) || undefined;
});

@ -86,6 +86,8 @@ import './components/selectDropdown.html';
import './components/selectDropdown';
import './components/header/header.html';
import './components/header/header';
import './components/header/headerRoom.html';
import './components/header/headerRoom';
import './components/contextualBar.html';
import './components/contextualBar';
export { getAvatarUrFromUsername } from 'meteor/rocketchat:utils';

@ -8,13 +8,13 @@
<div class="main-content-flex">
<section class="messages-container flex-tab-main-content {{adminClass}}" id="{{windowId}}" aria-label="{{_ "Channel"}}">
{{# unless embeddedVersion}}
{{# header}}
{{# headerRoom}}
{{#with flexData}}
<div class="rc-header__block rc-header__block-action">
{{> RoomsActionTab}}
</div>
{{/with}}
{{/header}}
{{/headerRoom}}
{{/unless}}
<div class="messages-container-wrapper">

@ -349,10 +349,6 @@ Template.room.helpers({
return roomIcon;
},
tokenAccessChannel() {
return Template.instance().hasTokenpass.get();
},
userStatus() {
const roomData = Session.get(`roomData${ this._id }`);
return roomTypes.getUserStatus(roomData.t, this._id) || 'offline';

@ -51,7 +51,7 @@
padding: var(--default-padding);
align-items: end;
align-items: flex-end;
justify-content: flex-end;
&-data {

@ -1,24 +1,15 @@
.rc-header.rc-header--fullpage {
padding: 1.25rem 1rem 0.75rem;
& .rc-header__wrap {
.rc-header {
padding: 0.5rem;
padding: 0.75rem 0;
font-size: var(--text-heading-size);
box-shadow: none;
}
&--room {
padding: 1.25rem;
& .rc-header__block {
font-size: 1.375rem;
}
box-shadow: 0 1px 2px 0 rgba(31, 35, 41, 0.08);
& .rc-button {
margin: -10px 0;
font-size: var(--header-title-font-size);
}
}
.rc-header {
padding: 0 0.5rem;
&__wrap {
z-index: 2;
@ -27,30 +18,26 @@
flex: 0 0 auto;
margin: 0 -0.5rem;
height: 36px;
padding: var(--header-padding);
margin: 0 -0.5rem;
white-space: nowrap;
background-color: var(--header-background-color);
box-shadow: 0 1px 2px 0 rgba(31, 35, 41, 0.08);
font-size: var(--header-title-font-size);
align-items: center;
justify-content: space-between;
}
&--height-fixed {
height: 78px;
}
&__block {
display: flex;
margin: 0 0.5rem;
margin: 0 -0.5rem;
padding: 0 0.5rem;
align-items: center;
}
@ -185,9 +172,10 @@
}
&__toggle-favorite {
color: var(--header-toggle-favorite-star-color);
font-size: 1.5rem;
padding: 0 0.25rem;
color: var(--header-toggle-favorite-star-color);
&.empty {
color: var(--header-toggle-favorite-color);
@ -198,7 +186,7 @@
}
& > .rc-header__icon {
font-size: 1.5rem;
font-size: 2rem;
}
&:hover {
@ -213,9 +201,15 @@
&__image {
width: 32px;
height: 32px;
margin: 0 0.5rem;
flex-shrink: 0;
}
.rc-button {
height: 36px;
min-height: 36px;
margin: 0 0.25rem;
}
}
.rc-room-actions {

@ -4,7 +4,7 @@
height: 100vh;
padding: 0 1.5rem;
padding: 1.25rem 2rem;
&-search {
width: 100%;
@ -30,7 +30,6 @@
flex: 1 1 100%;
height: 100vh;
padding: 0 1rem;
& .js-sort {
cursor: pointer;

@ -452,7 +452,7 @@
display: flex;
flex-direction: row;
margin: 0 -0.5rem 2rem -0.5rem;
margin: 0 -0.5rem 2rem;
& .rc-button {
margin: 0 0.5rem;

@ -9,7 +9,7 @@
width: 100%;
margin: 0 -1rem -2px -1rem;
margin: 0 -1rem -2px;
}
.tab {

@ -110,7 +110,7 @@ button {
& .tab-button-icon {
color: var(--rc-color-primary-dark);
fill: var(--rc-color-primary-dark);
font-size: 20px;
&--star {
width: 17px;

@ -192,17 +192,24 @@
top: 0;
left: 0;
display: flex;
overflow-y: hidden;
flex-direction: column;
width: 100%;
height: 100%;
padding: 1.25rem 2rem;
& .content {
overflow-y: scroll;
display: flex;
overflow-y: auto;
flex-direction: column;
flex: 1 1 auto;
width: 100%;
height: calc(100% - 60px);
padding: 25px 40px;
margin: 0 -2rem;
padding: 2rem 2rem 0;
line-height: 1.3em;
-webkit-overflow-scrolling: touch;
@ -266,28 +273,6 @@
}
}
}
& table {
overflow: hidden;
width: 100%;
margin-bottom: 30px;
& th,
& td {
padding: 0.6rem 0.7rem;
user-select: text;
text-align: left;
vertical-align: middle;
border-width: 0 0 1px;
}
& th {
white-space: nowrap;
}
}
}
.rc-old .input-line {
@ -1790,10 +1775,16 @@ rc-old select,
& .section {
padding: 20px 0;
border-bottom: 2px solid #dddddd;
&:not(:only-child) {
border-bottom: 2px solid #dddddd;
&.section-collapsed .section-content {
display: none;
&.section-collapsed .section-content {
display: none;
}
.section-title-right {
visibility: visible;
}
}
}
@ -1813,8 +1804,12 @@ rc-old select,
flex-grow: 1;
}
& .section-title-right > .rc-button {
font-size: 1.25rem;
& .section-title-right {
visibility: hidden;
& > .rc-button {
font-size: 1.25rem;
}
}
}
@ -2055,8 +2050,6 @@ rc-old select,
margin-bottom: 10px;
padding: 10px 0;
border-width: 0 0 1px;
font-weight: 300;
& p {
@ -3505,9 +3498,19 @@ body:not(.is-cordova) {
z-index: 2;
display: flex;
flex: 0 0 41px;
flex: 0 0 40px;
transform: box-shadow 0.3s;
box-shadow: -1px 0 0 1px #cccccc26;
&.opened {
box-shadow: -1px 0 5px 2px #cccccc26;
border-width: 0 0 0 1px;
& > .flex-tab-bar {
box-shadow: -1px 0 5px 2px #cccccc26;
}
}
& .flex-tab {
position: relative;
@ -3736,7 +3739,9 @@ body:not(.is-cordova) {
min-width: 40px;
border: 1px solid rgba(31, 35, 41, 0.08);
transition: box-shadow 0.3s;
box-shadow: -1px 0 0 1px #cccccc26;
& .tab-button {
position: relative;
@ -4004,7 +4009,7 @@ body:not(.is-cordova) {
}
& .contact-code {
margin: -5px 0 10px 0;
margin: -5px 0 10px;
font-size: 12px;
}
@ -5605,8 +5610,6 @@ body:not(.is-cordova) {
right: 40px;
height: 100%;
border-width: 0 0 0 1px;
}
}

@ -56,7 +56,7 @@
--status-invisible-sidebar: var(--rc-color-primary-darkest);
--default-padding: 1.5rem;
--default-small-padding: 1rem;
--status-bullet-size: 12px;
--status-bullet-size: 10px;
--status-bullet-radius: 50%;
--account-username-weight: 700;
--status-name-weight: 400;
@ -326,4 +326,5 @@
--alerts-background: #1d73f5;
--alerts-color: var(--color-white);
--alerts-font-size: var(--text-default-size);
--content-page-padding: 2.5rem;
}

@ -247,12 +247,6 @@
* Document components
*/
.page-container {
tr:hover td {
background-color: @content-background-color;
}
}
.burger i {
background-color: @primary-font-color;
}

@ -33,7 +33,7 @@ class Administration extends Page {
get usersRocketCat() { return browser.element('td=Rocket.Cat'); }
get usersInternalAdmin() { return browser.element('td=rocketchat.internal.admin.test'); }
get usersFilter() { return browser.element('#users-filter'); }
get rolesNewRolesButton() { return browser.element('.button.new-role'); }
get rolesNewRolesButton() { return browser.element('.rc-button.new-role'); }
get rolesPermissionGrid() { return browser.element('.permission-grid'); }
get rolesAdmin() { return browser.element('[title="Admin"]'); }
get rolesModerator() { return browser.element('[title="Moderator"]'); }

Loading…
Cancel
Save