From 823c61242fcdbb53151b186faad774616ecf18d7 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 11 May 2020 21:26:29 -0300 Subject: [PATCH 01/25] Regression: Do not show custom status inside sequential messages (#17613) --- app/theme/client/imports/general/base_old.css | 8 ++++++++ app/ui-message/client/message.html | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/theme/client/imports/general/base_old.css b/app/theme/client/imports/general/base_old.css index 62e89ad03fa2..abd91f9efa6f 100644 --- a/app/theme/client/imports/general/base_old.css +++ b/app/theme/client/imports/general/base_old.css @@ -2657,6 +2657,9 @@ rc-old select, } & .time { + padding-right: 2px; + padding-left: 2px; + white-space: nowrap; } @@ -2802,6 +2805,10 @@ rc-old select, display: none; } + .message-custom-status { + display: none; + } + & .title { position: absolute; left: 5px; @@ -2928,6 +2935,7 @@ rc-old select, } & .message-alias { + padding-right: 2px; padding-left: 2px; font-weight: 400; diff --git a/app/ui-message/client/message.html b/app/ui-message/client/message.html index b3951f4fa709..f6dccc66a445 100644 --- a/app/ui-message/client/message.html +++ b/app/ui-message/client/message.html @@ -34,7 +34,7 @@ {{getName}}{{#if showUsername}} @{{msg.u.username}}{{/if}} {{#if getStatus}} - + {{/if}} {{#each role in roleTags}} From 7b054e794ac7e9667e5e4f1f0d5fe2bd7ca11134 Mon Sep 17 00:00:00 2001 From: Michael Pintos Date: Tue, 12 May 2020 09:29:30 -0300 Subject: [PATCH 02/25] [FIX] Relative image path in oembededUrlWidget (#15902) --- app/oembed/client/oembedUrlWidget.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/oembed/client/oembedUrlWidget.js b/app/oembed/client/oembedUrlWidget.js index 66db81e25af7..4304c3db216b 100644 --- a/app/oembed/client/oembedUrlWidget.js +++ b/app/oembed/client/oembedUrlWidget.js @@ -50,11 +50,7 @@ Template.oembedUrlWidget.helpers({ if (url == null) { return; } - if (url.indexOf('//') === 0) { - url = `${ this.parsedUrl.protocol }${ url }`; - } else if (url.indexOf('/') === 0 && (this.parsedUrl && this.parsedUrl.host)) { - url = `${ this.parsedUrl.protocol }//${ this.parsedUrl.host }${ url }`; - } + url = new URL(url, `${ this.parsedUrl.protocol }//${ this.parsedUrl.host }`).href; return url; }, show() { From 960bed44412384de0edeb4ef63127e41c5b6651f Mon Sep 17 00:00:00 2001 From: Hoang Son Nguyen Date: Tue, 12 May 2020 21:15:29 +0700 Subject: [PATCH 03/25] [NEW] Unread bars on sidebar (#16862) Co-authored-by: Guilherme Gazzo --- app/theme/client/imports/components/sidebar/sidebar.css | 4 +++- app/ui-utils/client/lib/RoomManager.js | 2 ++ app/ui-utils/client/lib/menu.js | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/theme/client/imports/components/sidebar/sidebar.css b/app/theme/client/imports/components/sidebar/sidebar.css index 6a273c8fa646..033835d8f094 100644 --- a/app/theme/client/imports/components/sidebar/sidebar.css +++ b/app/theme/client/imports/components/sidebar/sidebar.css @@ -64,7 +64,9 @@ } & .unread-rooms { - display: none; + padding: calc(var(--sidebar-small-default-padding) - 8px); + + text-align: center; } } diff --git a/app/ui-utils/client/lib/RoomManager.js b/app/ui-utils/client/lib/RoomManager.js index e6dfae8be3c4..84eff4b04a38 100644 --- a/app/ui-utils/client/lib/RoomManager.js +++ b/app/ui-utils/client/lib/RoomManager.js @@ -9,6 +9,7 @@ import _ from 'underscore'; import { fireGlobalEvent } from './fireGlobalEvent'; import { upsertMessage, RoomHistoryManager } from './RoomHistoryManager'; import { mainReady } from './mainReady'; +import { menu } from './menu'; import { roomTypes } from '../../../utils'; import { callbacks } from '../../../callbacks'; import { Notifications } from '../../../notifications'; @@ -86,6 +87,7 @@ export const RoomManager = new function() { name, }; if (isNew) { + menu.updateUnreadBars(); callbacks.run('streamNewMessage', msg); } } diff --git a/app/ui-utils/client/lib/menu.js b/app/ui-utils/client/lib/menu.js index a5f09573039a..fb2ee2e37642 100644 --- a/app/ui-utils/client/lib/menu.js +++ b/app/ui-utils/client/lib/menu.js @@ -20,7 +20,7 @@ export const menu = new class extends EventEmitter { const listHeight = this.list.height(); let showTop = false; let showBottom = false; - $('li.has-alert').each(function() { + $('li.sidebar-item--unread').each(function() { if ($(this).offset().top < listOffset.top - $(this).height()) { showTop = true; } From 8b380ab69c4fdf5dad66b5c2191bdab6c5b63b1e Mon Sep 17 00:00:00 2001 From: Thassio Victor Date: Tue, 12 May 2020 14:48:18 -0300 Subject: [PATCH 04/25] [FIX] Resolve 'app already exists' error on app update (#17544) * fix: resolve 'app already exists' error on app update The 'Apps' and 'Marketplace' admin pages were using the function `installApp` from the `AppClientOrchestrator` class instead of `updateApp` to update apps. As a result, the 'app already exists' error was being thrown and apps were not being updated. * fix: remove `install app` handle from apps admin page As the `install app` handle is only needed in the marketplace page, there's no need to have it in the apps admin page. --- app/apps/client/admin/apps.js | 4 ++-- app/apps/client/admin/marketplace.js | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/apps/client/admin/apps.js b/app/apps/client/admin/apps.js index 86f32c90c23e..045ac52571bd 100644 --- a/app/apps/client/admin/apps.js +++ b/app/apps/client/admin/apps.js @@ -226,7 +226,7 @@ Template.apps.events({ } = instance.state.get('apps').find(({ id }) => id === currentTarget.dataset.id); FlowRouter.go('app-manage', { appId }, { version }); }, - async 'click .js-install, click .js-update'(event, instance) { + async 'click .js-update'(event, instance) { event.preventDefault(); event.stopPropagation(); @@ -240,7 +240,7 @@ Template.apps.events({ instance.startAppWorking(app.id); try { - const { status } = await Apps.installApp(app.id, app.marketplaceVersion); + const { status } = await Apps.updateApp(app.id, app.marketplaceVersion); warnStatusChange(app.name, status); } catch (error) { handleAPIError(error); diff --git a/app/apps/client/admin/marketplace.js b/app/apps/client/admin/marketplace.js index 495bda2a90ac..ed39d11b8bcd 100644 --- a/app/apps/client/admin/marketplace.js +++ b/app/apps/client/admin/marketplace.js @@ -273,7 +273,7 @@ Template.marketplace.events({ } = instance.state.get('apps').find(({ id }) => id === currentTarget.dataset.id); FlowRouter.go('marketplace-app', { appId }, { version: version || marketplaceVersion }); }, - async 'click .js-install, click .js-update'(event, instance) { + async 'click .js-install'(event, instance) { event.preventDefault(); event.stopPropagation(); @@ -284,6 +284,7 @@ Template.marketplace.events({ } const { currentTarget: button } = event; + const app = instance.state.get('apps').find(({ id }) => id === button.dataset.id); instance.startAppWorking(app.id); @@ -297,6 +298,31 @@ Template.marketplace.events({ instance.stopAppWorking(app.id); } }, + async 'click .js-update'(event, instance) { + event.preventDefault(); + event.stopPropagation(); + + const isLoggedInCloud = await checkCloudLogin(); + instance.state.set('isLoggedInCloud', isLoggedInCloud); + if (!isLoggedInCloud) { + return; + } + + const { currentTarget: button } = event; + + const app = instance.state.get('apps').find(({ id }) => id === button.dataset.id); + + instance.startAppWorking(app.id); + + try { + const { status } = await Apps.updateApp(app.id, app.marketplaceVersion); + warnStatusChange(app.name, status); + } catch (error) { + handleAPIError(error); + } finally { + instance.stopAppWorking(app.id); + } + }, async 'click .js-purchase'(event, instance) { event.preventDefault(); event.stopPropagation(); From a09b606f25d37c1371e517ddf4624c6c2635616c Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 12 May 2020 16:37:31 -0300 Subject: [PATCH 05/25] [FIX] Notification sounds (#17616) Co-authored-by: Guilherme Gazzo --- app/custom-sounds/client/lib/CustomSounds.js | 33 ++++++++++++++----- .../server/startup/custom-sounds.js | 13 ++++---- app/ui-master/client/main.html | 1 - app/ui/client/index.js | 1 - app/ui/client/lib/notification.js | 9 +---- .../client/views/app/audioNotification.html | 10 ------ client/admin/customSounds/EditCustomSound.js | 11 +++---- client/admin/customSounds/lib.js | 5 +-- packages/rocketchat-i18n/i18n/en.i18n.json | 1 + 9 files changed, 40 insertions(+), 44 deletions(-) delete mode 100644 app/ui/client/views/app/audioNotification.html diff --git a/app/custom-sounds/client/lib/CustomSounds.js b/app/custom-sounds/client/lib/CustomSounds.js index a0422581f6aa..27b09ca5a50d 100644 --- a/app/custom-sounds/client/lib/CustomSounds.js +++ b/app/custom-sounds/client/lib/CustomSounds.js @@ -3,18 +3,21 @@ import { ReactiveVar } from 'meteor/reactive-var'; import _ from 'underscore'; import { CachedCollectionManager } from '../../../ui-cached-collection'; +import { getURL } from '../../../utils/client'; const getCustomSoundId = (sound) => `custom-sound-${ sound }`; class CustomSoundsClass { constructor() { this.list = new ReactiveVar({}); - this.add({ _id: 'beep', name: 'Beep', extension: 'mp3', src: 'sounds/beep.mp3' }); - this.add({ _id: 'chelle', name: 'Chelle', extension: 'mp3', src: 'sounds/chelle.mp3' }); - this.add({ _id: 'ding', name: 'Ding', extension: 'mp3', src: 'sounds/ding.mp3' }); - this.add({ _id: 'droplet', name: 'Droplet', extension: 'mp3', src: 'sounds/droplet.mp3' }); - this.add({ _id: 'highbell', name: 'Highbell', extension: 'mp3', src: 'sounds/highbell.mp3' }); - this.add({ _id: 'seasons', name: 'Seasons', extension: 'mp3', src: 'sounds/seasons.mp3' }); + this.add({ _id: 'chime', name: 'Chime', extension: 'mp3', src: getURL('sounds/chime.mp3') }); + this.add({ _id: 'door', name: 'Door', extension: 'mp3', src: getURL('sounds/door.mp3') }); + this.add({ _id: 'beep', name: 'Beep', extension: 'mp3', src: getURL('sounds/beep.mp3') }); + this.add({ _id: 'chelle', name: 'Chelle', extension: 'mp3', src: getURL('sounds/chelle.mp3') }); + this.add({ _id: 'ding', name: 'Ding', extension: 'mp3', src: getURL('sounds/ding.mp3') }); + this.add({ _id: 'droplet', name: 'Droplet', extension: 'mp3', src: getURL('sounds/droplet.mp3') }); + this.add({ _id: 'highbell', name: 'Highbell', extension: 'mp3', src: getURL('sounds/highbell.mp3') }); + this.add({ _id: 'seasons', name: 'Seasons', extension: 'mp3', src: getURL('sounds/seasons.mp3') }); } add(sound) { @@ -41,9 +44,12 @@ class CustomSoundsClass { const audio = $(`#${ sound._id }`); if (audio && audio[0]) { const list = this.list.get(); + if (!sound.src) { + sound.src = this.getURL(sound); + } list[sound._id] = sound; this.list.set(list); - $('source', audio).attr('src', this.getURL(sound)); + $('source', audio).attr('src', sound.src); audio[0].load(); } else { this.add(sound); @@ -51,8 +57,7 @@ class CustomSoundsClass { } getURL(sound) { - const path = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || ''; - return `${ path }/custom-sounds/${ sound._id }.${ sound.extension }?_dc=${ sound.random || 0 }`; + return getURL(`/custom-sounds/${ sound._id }.${ sound.extension }?_dc=${ sound.random || 0 }`); } getList() { @@ -72,6 +77,16 @@ class CustomSoundsClass { return audio; } + + pause = (sound) => { + const audio = document.querySelector(`#${ getCustomSoundId(sound) }`); + if (!audio || !audio.pause) { + return; + } + + audio.pause(); + audio.currentTime = 0; + } } export const CustomSounds = new CustomSoundsClass(); diff --git a/app/custom-sounds/server/startup/custom-sounds.js b/app/custom-sounds/server/startup/custom-sounds.js index 7417d90e568f..77a0d2c52b38 100644 --- a/app/custom-sounds/server/startup/custom-sounds.js +++ b/app/custom-sounds/server/startup/custom-sounds.js @@ -1,9 +1,8 @@ import { Meteor } from 'meteor/meteor'; import { WebApp } from 'meteor/webapp'; -import _ from 'underscore'; -import { RocketChatFile } from '../../../file'; -import { settings } from '../../../settings'; +import { RocketChatFile } from '../../../file/server'; +import { settings } from '../../../settings/server'; export let RocketChatFileCustomSoundsInstance; @@ -35,16 +34,16 @@ Meteor.startup(function() { }); return WebApp.connectHandlers.use('/custom-sounds/', Meteor.bindEnvironment(function(req, res/* , next*/) { - const params = { sound: decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')) }; + const fileId = decodeURIComponent(req.url.replace(/^\//, '').replace(/\?.*$/, '')); - if (_.isEmpty(params.sound)) { + if (!fileId) { res.writeHead(403); res.write('Forbidden'); res.end(); return; } - const file = RocketChatFileCustomSoundsInstance.getFileWithReadStream(params.sound); + const file = RocketChatFileCustomSoundsInstance.getFileWithReadStream(fileId); if (!file) { return; } @@ -73,7 +72,7 @@ Meteor.startup(function() { } else { res.setHeader('Last-Modified', new Date().toUTCString()); } - res.setHeader('Content-Type', 'audio/mpeg'); + res.setHeader('Content-Type', file.contentType); res.setHeader('Content-Length', file.length); file.readStream.pipe(res); diff --git a/app/ui-master/client/main.html b/app/ui-master/client/main.html index fa1554c3c4b9..040c1eae7678 100644 --- a/app/ui-master/client/main.html +++ b/app/ui-master/client/main.html @@ -45,7 +45,6 @@
{{> status}}
- {{> audioNotification }} {{/if}} {{/if}} {{/unless}} diff --git a/app/ui/client/index.js b/app/ui/client/index.js index b7fa4c6840de..40e796da5d0a 100644 --- a/app/ui/client/index.js +++ b/app/ui/client/index.js @@ -12,7 +12,6 @@ import './views/cmsPage.html'; import './views/404/roomNotFound.html'; import './views/404/invalidSecretURL.html'; import './views/404/invalidInvite.html'; -import './views/app/audioNotification.html'; import './views/app/burger.html'; import './views/app/createChannel.html'; import './views/app/editStatus.html'; diff --git a/app/ui/client/lib/notification.js b/app/ui/client/lib/notification.js index 14e1bebc7381..2ad74e0a7dd1 100644 --- a/app/ui/client/lib/notification.js +++ b/app/ui/client/lib/notification.js @@ -165,14 +165,7 @@ Meteor.startup(() => { } }); } else { - const [room] = $(`audio#${ newRoomNotification }`); - if (!room) { - return; - } - if (room.pause) { - room.pause(); - room.currentTime = 0; - } + CustomSounds.pause(newRoomNotification); } }); }); diff --git a/app/ui/client/views/app/audioNotification.html b/app/ui/client/views/app/audioNotification.html deleted file mode 100644 index 88a0accde674..000000000000 --- a/app/ui/client/views/app/audioNotification.html +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/client/admin/customSounds/EditCustomSound.js b/client/admin/customSounds/EditCustomSound.js index 43170fb5ddef..d7938a96a589 100644 --- a/client/admin/customSounds/EditCustomSound.js +++ b/client/admin/customSounds/EditCustomSound.js @@ -19,7 +19,7 @@ const DeleteWarningModal = ({ onDelete, onCancel, ...props }) => { - {t('Custom_Sound_Status_Delete_Warning')} + {t('Custom_Sound_Delete_Warning')} @@ -49,8 +49,7 @@ const SuccessModal = ({ onClose, ...props }) => { ; }; -export function EditSound({ _id, cache, ...props }) { - const t = useTranslation(); +export function EditCustomSound({ _id, cache, ...props }) { const query = useMemo(() => ({ query: JSON.stringify({ _id }), }), [_id]); @@ -75,13 +74,13 @@ export function EditSound({ _id, cache, ...props }) { } if (error || !data || data.sounds.length < 1) { - return {t('Custom_User_Status_Error_Invalid_User_Status')}; + return {error}; } - return ; + return ; } -export function EditCustomSound({ close, onChange, data, ...props }) { +function EditSound({ close, onChange, data, ...props }) { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); diff --git a/client/admin/customSounds/lib.js b/client/admin/customSounds/lib.js index bff7ad4c15ed..44420855af54 100644 --- a/client/admin/customSounds/lib.js +++ b/client/admin/customSounds/lib.js @@ -22,13 +22,14 @@ export function validate(soundData, soundFile) { } export function createSoundData(soundFile, name = '', previousData) { - const soundData = {}; + const soundData = { + extension: soundFile.name.split('.').pop(), + }; if (previousData) { soundData._id = previousData._id; soundData.previousName = previousData.previousName; soundData.previousSound = previousData.previousSound; - soundData.extension = soundFile.name.split('.').pop(); soundData.previousExtension = previousData.previousSound.extension; soundData.name = name; soundData.newFile = false; diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 8cf17e9333ad..54bdd5e1bb26 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1069,6 +1069,7 @@ "Custom_Script_On_Logout_Description": "Custom Script that will run on execute logout flow ONLY", "Custom_Sound_Add": "Add Custom Sound", "Custom_Sound_Delete_Warning": "Deleting a sound cannot be undone.", + "Custom_Sound_Edit": "Edit Custom Sound", "Custom_Sound_Error_Invalid_Sound": "Invalid sound", "Custom_Sound_Error_Name_Already_In_Use": "The custom sound name is already in use.", "Custom_Sound_Has_Been_Deleted": "The custom sound has been deleted.", From e51b3ab0974abb1277c721fe2e24467d62f8e464 Mon Sep 17 00:00:00 2001 From: Taimur Azhar Date: Wed, 13 May 2020 00:45:11 +0500 Subject: [PATCH 06/25] [FIX] remove multiple options from dontAskMeAgain (#17514) --- app/ui-account/client/accountPreferences.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/ui-account/client/accountPreferences.js b/app/ui-account/client/accountPreferences.js index d17cd1c80943..099fab32f97a 100644 --- a/app/ui-account/client/accountPreferences.js +++ b/app/ui-account/client/accountPreferences.js @@ -353,10 +353,10 @@ Template.accountPreferences.events({ 'click .js-dont-ask-remove'(e) { e.preventDefault(); const selectEl = document.getElementById('dont-ask'); - const { options } = selectEl; - const selectedOption = selectEl.value; - const optionIndex = Array.from(options).findIndex((option) => option.value === selectedOption); - - selectEl.remove(optionIndex); + for (let i = selectEl.options.length - 1; i >= 0; i--) { + if (selectEl.options[i].selected) { + selectEl.remove(i); + } + } }, }); From 3a17555b6f3dcf4dd4dbcd3c48986887da086fbb Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Tue, 12 May 2020 19:17:19 -0300 Subject: [PATCH 07/25] [FIX] Mail Messages > Cannot mail own user. (#17625) --- .../client/views/mailMessagesInstructions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js b/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js index fb8755501854..4bc7442b5ee3 100644 --- a/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js +++ b/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js @@ -240,9 +240,9 @@ Template.mailMessagesInstructions.onCreated(function() { this.selectedUsers = new ReactiveVar([]); this.userFilter = new ReactiveVar(''); - const filter = { exceptions: [Meteor.user().username].concat(this.selectedUsers.get().map((u) => u.username)) }; + const filter = { exceptions: this.selectedUsers.get().map((u) => u.username) }; Deps.autorun(() => { - filter.exceptions = [Meteor.user().username].concat(this.selectedUsers.get().map((u) => u.username)); + filter.exceptions = this.selectedUsers.get().map((u) => u.username); }); this.ac = new AutoComplete( From 8ab895187f1db7b15da9a52d7eb8d746734cda72 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Tue, 12 May 2020 19:20:50 -0300 Subject: [PATCH 08/25] [FIX] Do not allow passwords on private channels (#15642) --- app/channel-settings/client/views/channelSettings.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/channel-settings/client/views/channelSettings.html b/app/channel-settings/client/views/channelSettings.html index 67b3fb5ad62e..174bea859f9e 100644 --- a/app/channel-settings/client/views/channelSettings.html +++ b/app/channel-settings/client/views/channelSettings.html @@ -226,6 +226,7 @@ {{/if}} {{/with}} {{#with settings.joinCode}} + {{#if canView}} + {{/if}} {{/with}} {{#if hasRetentionPermission}} From e54e3ce119dfbd84ed3422a7c7ef704b887c21ea Mon Sep 17 00:00:00 2001 From: kolorafa Date: Wed, 13 May 2020 00:39:57 +0200 Subject: [PATCH 09/25] [FIX] Livechat iframe allow microphone and camera (#9956) Co-authored-by: Guilherme Gazzo --- packages/rocketchat-livechat/assets/rocket-livechat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/assets/rocket-livechat.js b/packages/rocketchat-livechat/assets/rocket-livechat.js index e4156d0b7c1a..326d528fff58 100644 --- a/packages/rocketchat-livechat/assets/rocket-livechat.js +++ b/packages/rocketchat-livechat/assets/rocket-livechat.js @@ -695,7 +695,7 @@ chatWidget.dataset.state = 'closed'; chatWidget.className = 'rocketchat-widget'; chatWidget.innerHTML = '
' + - ' ' + + ' ' + '
'; chatWidget.style.position = 'fixed'; From b8a71a08c3225d3909ccbb68bb12067af6a34394 Mon Sep 17 00:00:00 2001 From: Marcos Spessatto Defendi Date: Wed, 13 May 2020 01:04:17 -0300 Subject: [PATCH 10/25] [NEW] Add permissions to deal with Omnichannel custom fields (#17567) * Add permissions to deal with omnichannel custom fields * Apply suggestions from review Co-authored-by: Renato Becker --- app/authorization/server/startup.js | 198 +++++++++--------- .../client/views/app/tabbar/visitorEdit.html | 45 ++-- .../client/views/app/tabbar/visitorEdit.js | 10 +- .../client/views/app/tabbar/visitorInfo.js | 3 + app/livechat/server/lib/Livechat.js | 65 +++--- app/livechat/server/methods/saveInfo.js | 2 +- .../livechat-enterprise/server/permissions.js | 2 + 7 files changed, 174 insertions(+), 151 deletions(-) diff --git a/app/authorization/server/startup.js b/app/authorization/server/startup.js index 0a9dba5a9ff0..073e1675beaa 100644 --- a/app/authorization/server/startup.js +++ b/app/authorization/server/startup.js @@ -12,105 +12,107 @@ Meteor.startup(function() { // then we can define edit--message instead of edit-message // 2. admin, moderator, and user roles should not be deleted as they are referened in the code. const permissions = [ - { _id: 'access-permissions', roles: ['admin'] }, - { _id: 'access-setting-permissions', roles: ['admin'] }, - { _id: 'add-oauth-service', roles: ['admin'] }, - { _id: 'add-user-to-joined-room', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'add-user-to-any-c-room', roles: ['admin'] }, - { _id: 'add-user-to-any-p-room', roles: [] }, - { _id: 'api-bypass-rate-limit', roles: ['admin', 'bot', 'app'] }, - { _id: 'archive-room', roles: ['admin', 'owner'] }, - { _id: 'assign-admin-role', roles: ['admin'] }, - { _id: 'assign-roles', roles: ['admin'] }, - { _id: 'ban-user', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'bulk-register-user', roles: ['admin'] }, - { _id: 'create-c', roles: ['admin', 'user', 'bot', 'app'] }, - { _id: 'create-d', roles: ['admin', 'user', 'bot', 'app'] }, - { _id: 'create-p', roles: ['admin', 'user', 'bot', 'app'] }, - { _id: 'create-personal-access-tokens', roles: ['admin', 'user'] }, - { _id: 'create-user', roles: ['admin'] }, - { _id: 'clean-channel-history', roles: ['admin'] }, - { _id: 'delete-c', roles: ['admin', 'owner'] }, - { _id: 'delete-d', roles: ['admin'] }, - { _id: 'delete-message', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'delete-own-message', roles: ['admin', 'user'] }, - { _id: 'delete-p', roles: ['admin', 'owner'] }, - { _id: 'delete-user', roles: ['admin'] }, - { _id: 'edit-message', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'edit-other-user-active-status', roles: ['admin'] }, - { _id: 'edit-other-user-info', roles: ['admin'] }, - { _id: 'edit-other-user-password', roles: ['admin'] }, - { _id: 'edit-other-user-avatar', roles: ['admin'] }, - { _id: 'edit-privileged-setting', roles: ['admin'] }, - { _id: 'edit-room', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'edit-room-retention-policy', roles: ['admin'] }, - { _id: 'force-delete-message', roles: ['admin', 'owner'] }, - { _id: 'join-without-join-code', roles: ['admin', 'bot', 'app'] }, - { _id: 'leave-c', roles: ['admin', 'user', 'bot', 'anonymous', 'app'] }, - { _id: 'leave-p', roles: ['admin', 'user', 'bot', 'anonymous', 'app'] }, - { _id: 'manage-assets', roles: ['admin'] }, - { _id: 'manage-emoji', roles: ['admin'] }, - { _id: 'manage-user-status', roles: ['admin'] }, - { _id: 'manage-outgoing-integrations', roles: ['admin'] }, - { _id: 'manage-incoming-integrations', roles: ['admin'] }, - { _id: 'manage-own-outgoing-integrations', roles: ['admin'] }, - { _id: 'manage-own-incoming-integrations', roles: ['admin'] }, - { _id: 'manage-oauth-apps', roles: ['admin'] }, - { _id: 'manage-selected-settings', 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'] }, - { _id: 'remove-user', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'run-import', roles: ['admin'] }, - { _id: 'run-migration', roles: ['admin'] }, - { _id: 'set-moderator', roles: ['admin', 'owner'] }, - { _id: 'set-owner', roles: ['admin', 'owner'] }, - { _id: 'send-many-messages', roles: ['admin', 'bot', 'app'] }, - { _id: 'set-leader', roles: ['admin', 'owner'] }, - { _id: 'unarchive-room', roles: ['admin'] }, - { _id: 'view-c-room', roles: ['admin', 'user', 'bot', 'app', 'anonymous'] }, - { _id: 'user-generate-access-token', roles: ['admin'] }, - { _id: 'view-d-room', roles: ['admin', 'user', 'bot', 'app', 'guest'] }, - { _id: 'view-full-other-user-info', roles: ['admin'] }, - { _id: 'view-history', roles: ['admin', 'user', 'anonymous'] }, - { _id: 'view-joined-room', roles: ['guest', 'bot', 'app', 'anonymous'] }, - { _id: 'view-join-code', roles: ['admin'] }, - { _id: 'view-logs', roles: ['admin'] }, - { _id: 'view-other-user-channels', roles: ['admin'] }, - { _id: 'view-p-room', roles: ['admin', 'user', 'anonymous', 'guest'] }, - { _id: 'view-privileged-setting', roles: ['admin'] }, - { _id: 'view-room-administration', roles: ['admin'] }, - { _id: 'view-statistics', roles: ['admin'] }, - { _id: 'view-user-administration', roles: ['admin'] }, - { _id: 'preview-c-room', roles: ['admin', 'user', 'anonymous'] }, - { _id: 'view-outside-room', roles: ['admin', 'owner', 'moderator', 'user'] }, - { _id: 'view-broadcast-member-list', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'call-management', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'create-invite-links', roles: ['admin', 'owner', 'moderator'] }, - { _id: 'view-l-room', roles: ['livechat-agent', 'livechat-manager', 'admin'] }, - { _id: 'view-livechat-manager', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-rooms', roles: ['livechat-manager', 'admin'] }, - { _id: 'close-livechat-room', roles: ['livechat-agent', 'livechat-manager', 'admin'] }, - { _id: 'close-others-livechat-room', roles: ['livechat-manager', 'admin'] }, - { _id: 'save-others-livechat-room-info', roles: ['livechat-manager'] }, - { _id: 'remove-closed-livechat-rooms', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-analytics', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-queue', roles: ['livechat-manager', 'admin'] }, - { _id: 'transfer-livechat-guest', roles: ['livechat-manager', 'admin'] }, - { _id: 'manage-livechat-managers', roles: ['livechat-manager', 'admin'] }, - { _id: 'manage-livechat-agents', roles: ['livechat-manager', 'admin'] }, - { _id: 'manage-livechat-departments', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-departments', roles: ['livechat-manager', 'admin'] }, - { _id: 'add-livechat-department-agents', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-current-chats', roles: ['livechat-manager', 'admin'] }, + { _id: 'access-permissions', roles: ['admin'] }, + { _id: 'access-setting-permissions', roles: ['admin'] }, + { _id: 'add-oauth-service', roles: ['admin'] }, + { _id: 'add-user-to-joined-room', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'add-user-to-any-c-room', roles: ['admin'] }, + { _id: 'add-user-to-any-p-room', roles: [] }, + { _id: 'api-bypass-rate-limit', roles: ['admin', 'bot', 'app'] }, + { _id: 'archive-room', roles: ['admin', 'owner'] }, + { _id: 'assign-admin-role', roles: ['admin'] }, + { _id: 'assign-roles', roles: ['admin'] }, + { _id: 'ban-user', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'bulk-register-user', roles: ['admin'] }, + { _id: 'create-c', roles: ['admin', 'user', 'bot', 'app'] }, + { _id: 'create-d', roles: ['admin', 'user', 'bot', 'app'] }, + { _id: 'create-p', roles: ['admin', 'user', 'bot', 'app'] }, + { _id: 'create-personal-access-tokens', roles: ['admin', 'user'] }, + { _id: 'create-user', roles: ['admin'] }, + { _id: 'clean-channel-history', roles: ['admin'] }, + { _id: 'delete-c', roles: ['admin', 'owner'] }, + { _id: 'delete-d', roles: ['admin'] }, + { _id: 'delete-message', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'delete-own-message', roles: ['admin', 'user'] }, + { _id: 'delete-p', roles: ['admin', 'owner'] }, + { _id: 'delete-user', roles: ['admin'] }, + { _id: 'edit-message', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'edit-other-user-active-status', roles: ['admin'] }, + { _id: 'edit-other-user-info', roles: ['admin'] }, + { _id: 'edit-other-user-password', roles: ['admin'] }, + { _id: 'edit-other-user-avatar', roles: ['admin'] }, + { _id: 'edit-privileged-setting', roles: ['admin'] }, + { _id: 'edit-room', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'edit-room-retention-policy', roles: ['admin'] }, + { _id: 'force-delete-message', roles: ['admin', 'owner'] }, + { _id: 'join-without-join-code', roles: ['admin', 'bot', 'app'] }, + { _id: 'leave-c', roles: ['admin', 'user', 'bot', 'anonymous', 'app'] }, + { _id: 'leave-p', roles: ['admin', 'user', 'bot', 'anonymous', 'app'] }, + { _id: 'manage-assets', roles: ['admin'] }, + { _id: 'manage-emoji', roles: ['admin'] }, + { _id: 'manage-user-status', roles: ['admin'] }, + { _id: 'manage-outgoing-integrations', roles: ['admin'] }, + { _id: 'manage-incoming-integrations', roles: ['admin'] }, + { _id: 'manage-own-outgoing-integrations', roles: ['admin'] }, + { _id: 'manage-own-incoming-integrations', roles: ['admin'] }, + { _id: 'manage-oauth-apps', roles: ['admin'] }, + { _id: 'manage-selected-settings', 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'] }, + { _id: 'remove-user', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'run-import', roles: ['admin'] }, + { _id: 'run-migration', roles: ['admin'] }, + { _id: 'set-moderator', roles: ['admin', 'owner'] }, + { _id: 'set-owner', roles: ['admin', 'owner'] }, + { _id: 'send-many-messages', roles: ['admin', 'bot', 'app'] }, + { _id: 'set-leader', roles: ['admin', 'owner'] }, + { _id: 'unarchive-room', roles: ['admin'] }, + { _id: 'view-c-room', roles: ['admin', 'user', 'bot', 'app', 'anonymous'] }, + { _id: 'user-generate-access-token', roles: ['admin'] }, + { _id: 'view-d-room', roles: ['admin', 'user', 'bot', 'app', 'guest'] }, + { _id: 'view-full-other-user-info', roles: ['admin'] }, + { _id: 'view-history', roles: ['admin', 'user', 'anonymous'] }, + { _id: 'view-joined-room', roles: ['guest', 'bot', 'app', 'anonymous'] }, + { _id: 'view-join-code', roles: ['admin'] }, + { _id: 'view-logs', roles: ['admin'] }, + { _id: 'view-other-user-channels', roles: ['admin'] }, + { _id: 'view-p-room', roles: ['admin', 'user', 'anonymous', 'guest'] }, + { _id: 'view-privileged-setting', roles: ['admin'] }, + { _id: 'view-room-administration', roles: ['admin'] }, + { _id: 'view-statistics', roles: ['admin'] }, + { _id: 'view-user-administration', roles: ['admin'] }, + { _id: 'preview-c-room', roles: ['admin', 'user', 'anonymous'] }, + { _id: 'view-outside-room', roles: ['admin', 'owner', 'moderator', 'user'] }, + { _id: 'view-broadcast-member-list', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'call-management', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'create-invite-links', roles: ['admin', 'owner', 'moderator'] }, + { _id: 'view-l-room', roles: ['livechat-agent', 'livechat-manager', 'admin'] }, + { _id: 'view-livechat-manager', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-rooms', roles: ['livechat-manager', 'admin'] }, + { _id: 'close-livechat-room', roles: ['livechat-agent', 'livechat-manager', 'admin'] }, + { _id: 'close-others-livechat-room', roles: ['livechat-manager', 'admin'] }, + { _id: 'save-others-livechat-room-info', roles: ['livechat-manager'] }, + { _id: 'remove-closed-livechat-rooms', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-analytics', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-queue', roles: ['livechat-manager', 'admin'] }, + { _id: 'transfer-livechat-guest', roles: ['livechat-manager', 'admin'] }, + { _id: 'manage-livechat-managers', roles: ['livechat-manager', 'admin'] }, + { _id: 'manage-livechat-agents', roles: ['livechat-manager', 'admin'] }, + { _id: 'manage-livechat-departments', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-departments', roles: ['livechat-manager', 'admin'] }, + { _id: 'add-livechat-department-agents', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-current-chats', roles: ['livechat-manager', 'admin'] }, { _id: 'view-livechat-real-time-monitoring', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-triggers', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-customfields', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-installation', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-appearance', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-webhooks', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-facebook', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-officeHours', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-triggers', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-customfields', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-installation', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-appearance', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-webhooks', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-facebook', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-officeHours', roles: ['livechat-manager', 'admin'] }, + { _id: 'view-livechat-room-customfields', roles: ['livechat-manager', 'livechat-agent', 'admin'] }, + { _id: 'edit-livechat-room-customfields', roles: ['livechat-manager', 'livechat-agent', 'admin'] }, ]; for (const permission of permissions) { diff --git a/app/livechat/client/views/app/tabbar/visitorEdit.html b/app/livechat/client/views/app/tabbar/visitorEdit.html index 306d1c310246..a83fcfd5e766 100644 --- a/app/livechat/client/views/app/tabbar/visitorEdit.html +++ b/app/livechat/client/views/app/tabbar/visitorEdit.html @@ -31,16 +31,18 @@

{{username}}

- {{#each visitorCustomFields}} -
- -
- {{/each}} + {{#if canViewCustomFields }} + {{#each visitorCustomFields}} +
+ +
+ {{/each}} + {{/if}} {{/with}} {{#with room}} @@ -91,17 +93,18 @@

{{_ "Conversation" }}

{{/each}} - - {{#each roomCustomFields}} -
- -
- {{/each}} + {{#if canViewCustomFields }} + {{#each roomCustomFields}} +
+ +
+ {{/each}} + {{/if}} {{/with}} - + diff --git a/app/emoji/client/emojiPicker.js b/app/emoji/client/emojiPicker.js index 410bbfa5682c..86360cc47575 100644 --- a/app/emoji/client/emojiPicker.js +++ b/app/emoji/client/emojiPicker.js @@ -1,6 +1,7 @@ import _ from 'underscore'; import { ReactiveVar } from 'meteor/reactive-var'; import { ReactiveDict } from 'meteor/reactive-dict'; +import { FlowRouter } from 'meteor/kadira:flow-router'; import { Template } from 'meteor/templating'; import { t } from '../../utils/client'; @@ -142,6 +143,12 @@ Template.emojiPicker.events({ event.stopPropagation(); event.preventDefault(); }, + 'click .add-custom'(event) { + event.stopPropagation(); + event.preventDefault(); + FlowRouter.go('/admin/emoji-custom'); + EmojiPicker.close(); + }, 'click .category-link'(event) { event.stopPropagation(); event.preventDefault(); diff --git a/app/theme/client/imports/components/emojiPicker.css b/app/theme/client/imports/components/emojiPicker.css index bd2d72a0b9c1..f8601a798a4c 100644 --- a/app/theme/client/imports/components/emojiPicker.css +++ b/app/theme/client/imports/components/emojiPicker.css @@ -122,6 +122,12 @@ font-size: 12px; font-weight: 500; + + & .add-custom { + display: inline-block; + + width: 100%; + } } .emoji-top { diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 00c5277b5433..5253a9c83272 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -233,6 +233,7 @@ "MAU_value": "MAU __value__", "Activity": "Activity", "Add": "Add", + "Add_custom_emoji": "Add custom emoji", "add-oauth-service": "Add Oauth Service", "add-oauth-service_description": "Permission to add a new Oauth service", "add-user": "Add User", From 84ccdd0a46a6f8a6df1b1b847e856cd25bc8b4d5 Mon Sep 17 00:00:00 2001 From: Dumitru Zavrotschi <11751017+zdumitru@users.noreply.github.com> Date: Fri, 15 May 2020 05:37:50 +0200 Subject: [PATCH 21/25] [FIX] Directory search user placeholder (#17652) --- app/ui/client/views/app/components/Directory/UserTab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ui/client/views/app/components/Directory/UserTab.js b/app/ui/client/views/app/components/Directory/UserTab.js index 25145c0a7c70..58a997e1784d 100644 --- a/app/ui/client/views/app/components/Directory/UserTab.js +++ b/app/ui/client/views/app/components/Directory/UserTab.js @@ -23,7 +23,7 @@ const FilterByText = ({ setFilter, ...props }) => { }, [text]); return - } onChange={handleChange} value={text} /> + } onChange={handleChange} value={text} /> ; }; From 811688e11988bd55129ceccb9dbd600acfa945ae Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Fri, 15 May 2020 13:52:39 -0300 Subject: [PATCH 22/25] [IMPROVE] Unused styles (#17554) --- .postcssrc | 3 +- .storybook/mocks/decorators.js | 2 +- app/apps/client/admin/appManage.html | 10 +- .../client/views/autoTranslateFlexTab.html | 4 +- app/chatpal-search/client/template/admin.html | 2 +- .../client/views/integrationsIncoming.html | 4 +- .../client/views/integrationsOutgoing.html | 8 +- .../views/integrationsOutgoingHistory.html | 4 +- .../livechatIntegrationFacebook.html | 6 +- .../client/views/app/livechatAgents.html | 2 +- .../client/views/app/livechatManagers.html | 2 +- .../client/views/app/livechatQueue.html | 2 +- .../client/views/app/tabbar/visitorInfo.html | 4 +- app/models/server/models/Settings.js | 4 +- .../client/admin/views/oauthApp.html | 4 +- .../client/oauth/oauth2-client.html | 6 +- app/otr/client/rocketchat.otr.room.js | 4 - app/otr/client/stylesheets/otr.css | 18 - app/otr/client/views/otrFlexTab.html | 6 +- app/theme/client/imports/general/base.css | 1 + app/theme/client/imports/general/base_old.css | 909 +----------------- app/theme/client/imports/general/forms.css | 59 -- app/theme/client/imports/general/rtl.css | 84 -- .../client/imports/general/theme_old.css | 557 +++++++++++ .../client/imports/general/variables.css | 86 +- app/theme/client/main.css | 3 + app/theme/server/server.js | 20 +- app/theme/server/variables.js | 93 +- .../client/tokenpassChannelSettings.html | 8 +- app/ui-account/client/accountProfile.html | 4 - app/ui-account/client/avatar/prompt.html | 14 +- app/ui-flextab/client/tabs/userInfo.html | 2 +- app/ui-login/client/login/services.html | 2 +- app/ui-login/client/login/social.html | 10 +- .../client/reset-password/resetPassword.html | 2 +- app/ui-master/.eslintrc | 5 - app/ui-master/client/main.html | 2 +- app/ui-master/client/main.js | 2 - app/ui-master/server/inject.js | 1 - app/ui-message/client/message.html | 2 +- app/ui-sidenav/client/index.js | 1 - app/ui-sidenav/client/toolbar.js | 1 - app/ui-sidenav/client/userStatus.html | 29 - app/ui/client/views/app/room.js | 2 +- .../views/app/videoCall/videoButtons.html | 8 +- client/main.js | 1 + client/polyfills/cssVars.js | 85 ++ client/polyfills/index.js | 1 + client/startup/theme.js | 110 +++ .../client/views/livechatMonitors.html | 2 +- .../client/views/livechatUnitForm.html | 2 +- imports/client/mimic-fn | 1 - imports/client/mimic-fn/index.js | 1 + package-lock.json | 248 ++--- private/client/imports/general/variables.css | 381 +------- private/server/colors.less | 893 ----------------- private/server/dynamic-css.js | 187 ---- .../integration/04-main-elements-render.js | 4 - tests/cypress/integration/12-settings.js | 6 - .../cypress/pageobjects/main-content.page.js | 2 - 60 files changed, 1076 insertions(+), 2850 deletions(-) create mode 100644 app/theme/client/imports/general/theme_old.css delete mode 100644 app/ui-master/.eslintrc delete mode 100644 app/ui-sidenav/client/userStatus.html create mode 100644 client/polyfills/cssVars.js create mode 100644 client/startup/theme.js delete mode 120000 imports/client/mimic-fn create mode 120000 imports/client/mimic-fn/index.js mode change 100644 => 120000 private/client/imports/general/variables.css delete mode 100755 private/server/colors.less delete mode 100644 private/server/dynamic-css.js diff --git a/.postcssrc b/.postcssrc index 48f60768f666..e0279b84e3c1 100644 --- a/.postcssrc +++ b/.postcssrc @@ -10,7 +10,6 @@ "autoprefixer": {} }, "excludedPackages": [ - "deepwell:bootstrap-datepicker2", - "smoral:sweetalert" + "deepwell:bootstrap-datepicker2" ] } diff --git a/.storybook/mocks/decorators.js b/.storybook/mocks/decorators.js index 34a326f11077..0c545d5c1611 100644 --- a/.storybook/mocks/decorators.js +++ b/.storybook/mocks/decorators.js @@ -24,7 +24,7 @@ export const rocketChatDecorator = (fn) => { } `}
-
+
{fn()}
; diff --git a/app/apps/client/admin/appManage.html b/app/apps/client/admin/appManage.html index 783647e27ae0..8b6c0371ed26 100644 --- a/app/apps/client/admin/appManage.html +++ b/app/apps/client/admin/appManage.html @@ -359,8 +359,8 @@

{{_ "Settings"}}

{{> CodeMirror name=id options=getEditorOptions code=value }}
- - + +
{{/if}} @@ -463,7 +463,7 @@

{{_ "Settings"}}

{{#if hasChanges section}} {{_ "Save_to_enable_this_action"}} {{else}} - + {{/if}} {{/if}} @@ -472,14 +472,14 @@

{{_ "Settings"}}

- +
{{else}}
-
{{_ 'Select_file'}} +
{{_ 'Select_file'}}
diff --git a/app/autotranslate/client/views/autoTranslateFlexTab.html b/app/autotranslate/client/views/autoTranslateFlexTab.html index 5e5d74daeaba..161e3793b153 100644 --- a/app/autotranslate/client/views/autoTranslateFlexTab.html +++ b/app/autotranslate/client/views/autoTranslateFlexTab.html @@ -30,8 +30,8 @@

{{_ "Auto_Translate"}}

{{_ "AutoTranslate_Change_Language_Description"}}
- - + + {{else}} {{languageName autoTranslateLanguage}} {{/if}} diff --git a/app/chatpal-search/client/template/admin.html b/app/chatpal-search/client/template/admin.html index d59a982a6b23..f9b1e6c83a99 100644 --- a/app/chatpal-search/client/template/admin.html +++ b/app/chatpal-search/client/template/admin.html @@ -37,7 +37,7 @@
- +
diff --git a/app/integrations/client/views/integrationsIncoming.html b/app/integrations/client/views/integrationsIncoming.html index d9aae546f700..7a98d4ac9241 100644 --- a/app/integrations/client/views/integrationsIncoming.html +++ b/app/integrations/client/views/integrationsIncoming.html @@ -82,8 +82,8 @@ {{> CodeMirror name="script" options=editorOptions code=data.script }}
- - + +
{{#if data.hasScriptError }} diff --git a/app/integrations/client/views/integrationsOutgoing.html b/app/integrations/client/views/integrationsOutgoing.html index 18d6fc8d5791..d9dc03ae209e 100644 --- a/app/integrations/client/views/integrationsOutgoing.html +++ b/app/integrations/client/views/integrationsOutgoing.html @@ -18,7 +18,7 @@
{{_ "Webhook Details"}}
- +
@@ -148,8 +148,8 @@
{{> CodeMirror name="script" options=editorOptions code=data.script }}
- - + +
{{#if data.hasScriptError }} @@ -181,7 +181,7 @@
{{_ "Integration_Advanced_Settings"}}
- +
diff --git a/app/integrations/client/views/integrationsOutgoingHistory.html b/app/integrations/client/views/integrationsOutgoingHistory.html index cdd0d7f17933..b453924e1f9d 100644 --- a/app/integrations/client/views/integrationsOutgoingHistory.html +++ b/app/integrations/client/views/integrationsOutgoingHistory.html @@ -21,8 +21,8 @@ {{formatDate history._createdAt}}
- - +
diff --git a/app/livechat/client/views/app/integrations/livechatIntegrationFacebook.html b/app/livechat/client/views/app/integrations/livechatIntegrationFacebook.html index f7ff03d6b089..6686dbde984c 100644 --- a/app/livechat/client/views/app/integrations/livechatIntegrationFacebook.html +++ b/app/livechat/client/views/app/integrations/livechatIntegrationFacebook.html @@ -4,10 +4,10 @@
{{#if enabled}} - - + + {{else}} - + {{#unless hasToken}}

{{_ "You_have_to_set_an_API_token_first_in_order_to_use_the_integration"}}

diff --git a/app/livechat/client/views/app/livechatAgents.html b/app/livechat/client/views/app/livechatAgents.html index 063de6b19c25..bb57a86497e9 100644 --- a/app/livechat/client/views/app/livechatAgents.html +++ b/app/livechat/client/views/app/livechatAgents.html @@ -62,7 +62,7 @@
-
{{> avatar username=username}}
+
{{> avatar username=username}}
{{name}} diff --git a/app/livechat/client/views/app/livechatManagers.html b/app/livechat/client/views/app/livechatManagers.html index ec1468cd13b0..d35e2d33be44 100644 --- a/app/livechat/client/views/app/livechatManagers.html +++ b/app/livechat/client/views/app/livechatManagers.html @@ -57,7 +57,7 @@
-
{{> avatar username=username}}
+
{{> avatar username=username}}
{{name}} diff --git a/app/livechat/client/views/app/livechatQueue.html b/app/livechat/client/views/app/livechatQueue.html index e666828d5c33..2a3f926611e1 100644 --- a/app/livechat/client/views/app/livechatQueue.html +++ b/app/livechat/client/views/app/livechatQueue.html @@ -84,7 +84,7 @@
-
{{> avatar username=user.username}}
+
{{> avatar username=user.username}}
{{user.username}}
diff --git a/app/livechat/client/views/app/tabbar/visitorInfo.html b/app/livechat/client/views/app/tabbar/visitorInfo.html index 0ba4aa7d6c9e..b802b5962612 100644 --- a/app/livechat/client/views/app/tabbar/visitorInfo.html +++ b/app/livechat/client/views/app/tabbar/visitorInfo.html @@ -64,10 +64,10 @@

{{_ "Conversation"}}

{{/if}} {{#if canForwardGuest}} - + {{/if}} {{#if canReturnQueue}} - + {{/if}} {{/if}} diff --git a/app/models/server/models/Settings.js b/app/models/server/models/Settings.js index 6cca3203f251..a03c81a04100 100644 --- a/app/models/server/models/Settings.js +++ b/app/models/server/models/Settings.js @@ -58,7 +58,7 @@ export class Settings extends Base { filter._id = { $in: ids }; } - return this.find(filter, { fields: { _id: 1, value: 1 } }); + return this.find(filter, { fields: { _id: 1, value: 1, editor: 1 } }); } findNotHiddenPublicUpdatedAfter(updatedAt) { @@ -70,7 +70,7 @@ export class Settings extends Base { }, }; - return this.find(filter, { fields: { _id: 1, value: 1 } }); + return this.find(filter, { fields: { _id: 1, value: 1, editor: 1 } }); } findNotHiddenPrivate() { diff --git a/app/oauth2-server-config/client/admin/views/oauthApp.html b/app/oauth2-server-config/client/admin/views/oauthApp.html index 5bcab86d702b..360a4ff57c99 100644 --- a/app/oauth2-server-config/client/admin/views/oauthApp.html +++ b/app/oauth2-server-config/client/admin/views/oauthApp.html @@ -60,9 +60,9 @@
{{#if data.clientId}} - + {{/if}} - +
{{else}} diff --git a/app/oauth2-server-config/client/oauth/oauth2-client.html b/app/oauth2-server-config/client/oauth/oauth2-client.html index 49915dcf4738..917f44217918 100644 --- a/app/oauth2-server-config/client/oauth/oauth2-client.html +++ b/app/oauth2-server-config/client/oauth/oauth2-client.html @@ -30,9 +30,9 @@

{{currentUser.username}}

- - - + + +
{{#unless Template.subscriptionsReady}} diff --git a/app/otr/client/rocketchat.otr.room.js b/app/otr/client/rocketchat.otr.room.js index fcb34184e376..08da47733d76 100644 --- a/app/otr/client/rocketchat.otr.room.js +++ b/app/otr/client/rocketchat.otr.room.js @@ -71,13 +71,9 @@ OTR.Room = class { if (this.established.get()) { if ($room.length && $title.length && !$('.otr-icon', $title).length) { $title.prepend(''); - $('.input-message-container').addClass('otr'); - $('.inner-right-toolbar').prepend(''); } } else if ($title.length) { $('.otr-icon', $title).remove(); - $('.input-message-container').removeClass('otr'); - $('.inner-right-toolbar .otr-icon').remove(); } }); diff --git a/app/otr/client/stylesheets/otr.css b/app/otr/client/stylesheets/otr.css index 029972d1a1b5..2a44f16efe7c 100644 --- a/app/otr/client/stylesheets/otr.css +++ b/app/otr/client/stylesheets/otr.css @@ -27,21 +27,3 @@ } } } - -.input-message-container.otr { - & .input-message { - padding-right: 48px; - } - - & .inner-right-toolbar { - & .otr-icon { - display: inline-block; - - margin-top: 2px; - - vertical-align: top; - - color: green; - } - } -} diff --git a/app/otr/client/views/otrFlexTab.html b/app/otr/client/views/otrFlexTab.html index e394b43cba61..6357caf196a9 100644 --- a/app/otr/client/views/otrFlexTab.html +++ b/app/otr/client/views/otrFlexTab.html @@ -9,15 +9,15 @@

{{_ "Off_the_record_conversation"}}

{{#if userIsOnline}} {{#if established}}
- +
- +
{{else}} {{#if establishing}} {{_ "Please_wait_while_OTR_is_being_established"}} {{else}} - + {{/if}} {{/if}} {{else}}

{{_ "OTR_is_only_available_when_both_users_are_online"}}

diff --git a/app/theme/client/imports/general/base.css b/app/theme/client/imports/general/base.css index 701478ff6849..e35353061bce 100644 --- a/app/theme/client/imports/general/base.css +++ b/app/theme/client/imports/general/base.css @@ -29,6 +29,7 @@ body { background-color: var(--rc-color-primary); + font-family: var(--body-font-family); font-size: var(--text-small-size); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; diff --git a/app/theme/client/imports/general/base_old.css b/app/theme/client/imports/general/base_old.css index abd91f9efa6f..d2b2ace62a9b 100644 --- a/app/theme/client/imports/general/base_old.css +++ b/app/theme/client/imports/general/base_old.css @@ -1,7 +1,3 @@ -.rc-old .text-right { - text-align: right; -} - .rc-old .no-scroll { overflow: hidden !important; } @@ -180,18 +176,6 @@ display: none !important; } -.rc-old .scrollable { - position: absolute; - top: 0; - left: 0; - - overflow-y: scroll; - - width: 100%; - height: 100%; - -webkit-overflow-scrolling: touch; -} - .rc-old .page-container { position: absolute; top: 0; @@ -249,33 +233,11 @@ } } - & .logoutOthers { - text-align: right; - } - & .submit { margin-top: 20px; text-align: right; } - - &.request-password { - margin: 0 auto; - - & fieldset { - margin-top: 20px; - - & label { - display: block; - - margin-top: 20px; - } - } - - & .submit { - text-align: center; - } - } } } } @@ -383,38 +345,6 @@ } } -/* input & form styles */ - -.rc-old :not(.rcx-input-control):focus { - outline: none; - box-shadow: 0 0 0; -} - -/* .rc-old textarea, */ - -/* -rc-old select, -.rc-old input[type='text'], -.rc-old input[type='number'], -.rc-old input[type='email'], -.rc-old input[type='url'], -.rc-old input[type='password'] { - position: relative; - - width: 100%; - height: 35px; - padding: 2px 8px; - - border-width: 1px; - border-style: solid; - border-radius: 5px; - outline: none; - - line-height: normal; - appearance: none; -} -*/ - .rc-old input { & .input-forward { visibility: hidden; @@ -459,16 +389,6 @@ rc-old select, position: relative; } -.rc-old .form-group .input-group { - padding: 2px 0; -} - -.rc-old .form-horizontal .control-label { - padding-top: 12px; - - font-weight: bold; -} - .rc-old .-autocomplete-container { top: auto; @@ -616,26 +536,6 @@ rc-old select, flex-grow: 0; } -.rc-old .sec-header { - margin: 16px 0; - - text-align: center; - - & > * { - display: inline-table; - - width: auto; - - vertical-align: middle; - - line-height: 35px; - } - - & label { - margin-left: 20px; - } -} - .rc-old.burger { display: none; visibility: hidden; @@ -817,10 +717,6 @@ rc-old select, border-radius: var(--border-radius); } - - & .avatar-initials { - line-height: 44px; - } } & .data { @@ -1072,21 +968,8 @@ rc-old select, direction: rtl; -webkit-overflow-scrolling: touch; - &.no-shadow { - box-shadow: 0 0 0; - } - & > .wrapper { direction: ltr; - - & .flex-control { - margin-bottom: 30px; - - & .search { - width: 100%; - margin-bottom: 10px; - } - } } & h4 { @@ -1156,10 +1039,6 @@ rc-old select, } } - & .input-submit { - margin: 35px 0 0 -4px; - } - & .selected-users { padding: 20px 0 0; @@ -1186,65 +1065,6 @@ rc-old select, height: var(--toolbar-height); } -.rc-old .toolbar-wrapper { - display: flex; - - margin: 10px 8px; -} - -.rc-old .toolbar-search { - position: relative; - - width: 100%; -} - -.rc-old .toolbar-search__icon { - position: absolute; - top: 0; - left: 0; - - width: 35px; - - text-align: center; - - line-height: 35px; -} - -.rc-old .toolbar-search__icon--cancel { - right: 0; - left: auto; - - cursor: pointer; - transition: opacity 0.3s; - - opacity: 0; -} - -.rc-old .toolbar-search__input { - padding: 6px 35px !important; - - &:focus + .toolbar-search__icon--cancel { - opacity: 1; - } -} - -.rc-old .toolbar-search__buttons { - display: flex; - - margin-left: 5px; - align-items: center; - - & i { - width: 25px; - height: 25px; - - cursor: pointer; - text-align: center; - - line-height: 25px; - } -} - .rc-old .new-room-highlight a { animation: highlight 6s infinite; } @@ -1342,11 +1162,20 @@ rc-old select, text-align: center; color: var(--rc-color-content); + background-color: var(--primary-background-color); font-size: 1.2em; line-height: 40px; flex-flow: row nowrap; + &.warning { + background-color: var(--rc-color-alert); + } + + &.error { + background-color: var(--rc-color-alert-message-warning); + } + & ~ .container-bars { top: 45px; } @@ -1400,16 +1229,6 @@ rc-old select, /* MAIN CONTENT + MAIN PAGES */ -.rc-old.main-content { - & .container-fluid { - padding-top: 0; - } - - & .history-date { - margin-bottom: 20px; - } -} - .rc-old .page-settings { & .content { & h2 { @@ -1544,12 +1363,6 @@ rc-old select, line-height: 1.2rem; } - & .color-editor { - position: relative; - - width: 150px; - } - & .selected-rooms .remove-room { cursor: pointer; } @@ -1746,12 +1559,6 @@ rc-old select, margin-bottom: 5px; } } - - & .user-image { - float: right; - - margin-left: 12px; - } } } @@ -1970,14 +1777,6 @@ rc-old select, width: 50%; } - & .room-topic { - margin-left: 10px; - - opacity: 0.4; - - font-size: 14px; - } - & .wrapper { position: absolute; top: 0; @@ -1997,287 +1796,11 @@ rc-old select, flex-shrink: 0; } - & .message-form { - margin-bottom: 18px; - - & > .message-input { - position: relative; - - display: flex; - overflow: hidden; - - border-width: 1px; - border-radius: 5px; - - & > .share-items { - position: relative; - - display: flex; - - & input { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - - overflow: hidden; - - cursor: pointer; - - opacity: 0; - - &::-webkit-file-upload-button { - cursor: pointer; - } - } - - & i { - font-size: 18px; - } - - & > .message-buttons { - position: relative; - - display: flex; - overflow: hidden; - - width: 35px; - height: 35px; - - cursor: pointer; - text-align: center; - - border: 0; - align-items: center; - justify-content: center; - - & input { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - - overflow: hidden; - - cursor: pointer; - - opacity: 0; - - &::-webkit-file-upload-button { - cursor: pointer; - } - } - - & i { - font-size: 18px; - } - } - } - - & .input-message-container { - position: relative; - - width: 100%; - - & .inner-left-toolbar { - position: absolute; - top: 8px; - left: 13px; - } - } - - & > .message-buttons { - position: relative; - - display: flex; - flex: 0 0 35px; - - cursor: pointer; - transition: background-color 0.1s linear, color 0.1s linear; - text-align: center; - - border: 0; - align-items: center; - justify-content: center; - - & i { - transition: transform 0.3s ease-out; - transform: rotate(0deg); - - font-size: 18px; - } - - & input { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - - overflow: hidden; - - width: 100%; - - cursor: pointer; - - opacity: 0; - - &::-webkit-file-upload-button { - cursor: pointer; - } - } - } - } - - & textarea { - display: block; - overflow-y: auto; - - max-height: 155px; - margin: 0; - padding-top: 9px; - padding-bottom: 9px; - padding-left: 49px; - - resize: none; - - border-width: 0 1px 0 0; - border-radius: 0; - - line-height: 16px; - } - - & .users-typing { - position: relative; - - display: inline-block; - float: left; - overflow: hidden; - - max-width: 100%; - height: 23px; - padding: 3px; - - white-space: nowrap; - text-overflow: ellipsis; - - background-color: var(--color-white); - - font-size: 12px; - } - - & .formatting-tips { - display: flex; - float: right; - overflow: hidden; - - height: 25px; - padding: 3px; - - transition: opacity 0.2s linear; - white-space: nowrap; - - opacity: 0.5; - - font-size: 11px; - align-items: center; - - & > * { - margin: 0 3px; - } - - &:hover { - opacity: 1; - } - - & q { - padding: 0 0 0 3px; - - border-width: 0 0 0 3px; - - &::before { - content: none !important; - } - } - - & code { - overflow: hidden; - - vertical-align: top; - white-space: nowrap; - - font-size: 10px; - line-height: 13px; - } - - & .hidden-br { - display: inline-block; - } - - & .icon-level-down::before { - transform: rotate(90deg); - } - } - - & .editing-commands { - display: none; - - text-transform: lowercase; - - & .editing-commands-cancel { - float: left; - - height: 23px; - padding: 3px; - - font-size: 11px; - } - - & .editing-commands-save { - float: right; - - height: 23px; - padding: 3px; - - font-size: 11px; - } - } - - &.editing { - & .formatting-tips, - & .users-typing { - display: none; - } - - & .editing-commands { - display: block; - } - } - } - - & .add-user-search { - display: inline-block; - overflow: hidden; - - width: 100%; - height: 100%; - - vertical-align: top; - } - &.admin { & .message:hover:not(.system) .message-action { display: inline-block; } } - - & .secondary-name { - color: #666666; - - font-size: 15px; - } } .rc-old .message-popup-position { @@ -2373,84 +1896,30 @@ rc-old select, } .rc-old .reply-preview .cancel-reply { - padding: 10px; -} - -.rc-message-box__icon.cancel-reply .rc-input__icon-svg--cross { - font-size: 1em; -} - -.rc-old .message-popup.popup-with-reply-preview { - border-radius: 5px 5px 0 0; -} - -.rc-old .message-popup { - position: absolute; - z-index: 101; - right: 0; - bottom: 0; - left: 0; - - overflow: hidden; - - border-radius: 5px; - box-shadow: - 0 -1px 10px 0 rgba(0, 0, 0, 0.2), - 0 1px 1px rgba(0, 0, 0, 0.16); - - &.popup-down { - top: 0; - bottom: auto; - } - - &.search-results-list { - top: 0; - - overflow-y: auto; - - height: calc(100vh - calc(var(--header-min-height) + calc(var(--toolbar-height) + var(--footer-min-height)))); - padding: 25px 0 0 8px; - - text-align: left; - - border-radius: 0; - box-shadow: none; - direction: rtl; - - & .popup-item { - position: relative; - - overflow: hidden; - - height: 30px; - padding-left: 6px; - - white-space: nowrap; - text-overflow: ellipsis; - direction: ltr; + padding: 10px; +} - & i::before { - margin-right: 0; - } - } +.rc-message-box__icon.cancel-reply .rc-input__icon-svg--cross { + font-size: 1em; +} - & .room-title { - font-size: 15px; - line-height: 30px; - } +.rc-old .message-popup.popup-with-reply-preview { + border-radius: 5px 5px 0 0; +} - & .bold { - font-weight: 700; - } +.rc-old .message-popup { + position: absolute; + z-index: 101; + right: 0; + bottom: 0; + left: 0; - & .unread { - top: 8px; - } + overflow: hidden; - & .loading-animation { - position: relative; - } - } + border-radius: 5px; + box-shadow: + 0 -1px 10px 0 rgba(0, 0, 0, 0.2), + 0 1px 1px rgba(0, 0, 0, 0.16); } .rc-old .message-popup-title { @@ -2851,10 +2320,6 @@ rc-old select, } } - & .avatar-initials { - line-height: 40px; - } - & .body { transition: opacity 0.3s linear; @@ -3313,36 +2778,6 @@ rc-old select, } } } - - /* - & .close-flex-tab { - position: absolute; - z-index: 20; - top: 3px; - right: 5px; - - width: 30px; - height: 30px; - - text-align: center; - - & span { - display: inline-block; - - width: 21px; - height: 20px; - - & i { - display: inline-block; - - width: 18px; - height: 18px; - - font-size: 10px; - } - } - } - */ } & .flex-tab-bar { @@ -3623,12 +3058,6 @@ rc-old select, } } - & .contact-code { - margin: -5px 0 10px; - - font-size: 12px; - } - & .channels { & h3 { margin-bottom: 8px; @@ -3677,10 +3106,6 @@ rc-old select, } } } - - & .room-info-content > div { - margin: 0 0 20px; - } } .rc-old .edit-form { @@ -3733,156 +3158,6 @@ rc-old select, } } -.rc-old .user-image { - position: relative; - - display: inline-block; - - width: var(--user-image-square); - height: var(--user-image-square); - margin: 4px; - - cursor: pointer; - - font-size: 12px; - - &:hover, - &.selected .avatar::after { - transform: scaleX(1); - } - - & .avatar { - overflow: visible; - - &::before { - font-size: 10px; - } - - &::after { - position: absolute; - z-index: 1; - top: 8px; - left: -12px; - - width: 6px; - height: 6px; - - content: " "; - - border-radius: 3px; - } - - & .avatar-initials { - line-height: var(--user-image-square); - } - } - - & p { - display: none; - } - - & button { - display: block; - - width: 100%; - height: 100%; - } -} - -.rc-old .lines .user-image { - width: 100%; - margin: 0; - - &::after { - display: none; - } - - & button { - display: block; - clear: both; - - height: 30px; - padding: 5px 0; - - &::after { - display: table; - clear: both; - - content: ""; - } - - & > div { - float: left; - - width: var(--user-image-square); - height: var(--user-image-square); - - margin-left: 1rem; - } - } - - & p { - position: relative; - - display: block; - float: left; - overflow: hidden; - - width: calc(100% - 45px); - padding-left: 10px; - - text-overflow: ellipsis; - - font-size: 15px; - font-weight: 400; - line-height: var(--user-image-square); - } -} - -.rc-old .user-profile { - overflow: hidden; - - white-space: normal; - - & .thumb { - float: left; - - width: 75px; - - & img { - width: 60px; - height: 60px; - } - } - - & .info { - display: block; - - margin-left: 75px; - - & h3 { - margin-bottom: 8px; - - font-size: 14px; - font-weight: 600; - } - - & p { - margin-bottom: 6px; - - font-size: 12px; - } - - & a:hover { - text-decoration: none; - } - } -} - -.rc-old .profile-buttons { - margin-top: 1em; -} - .rc-old .avatarPrompt { & header p { font-size: 14px; @@ -3895,14 +3170,6 @@ rc-old select, } } -.rc-old .select-arrow { - position: absolute; - right: 4px; - bottom: 11px; - - color: #a9a9a9; -} - .rc-old #login-card { position: relative; z-index: 1; @@ -4234,15 +3501,6 @@ rc-old select, } } -.rc-old #particles-js { - position: fixed; - top: 0; - left: 0; - - width: 100%; - height: 100%; -} - .rc-old .highlight-text { padding: 2px; @@ -4347,36 +3605,6 @@ rc-old select, } } -.rc-old .rocket-team { - display: block; - - & li { - display: inline-block; - } - - & a { - display: inline-block; - - width: 50px; - height: 50px; - margin-right: 5px; - - border-radius: 50%; - background-position: 50% 50%; - background-size: 100%; - } -} - -.rc-old #fullscreendiv:-webkit-full-screen { - position: fixed; - top: 0; - - width: 100%; - height: 100%; - - background: none; -} - .rc-old .dropzone { & .dropzone-overlay { @@ -4430,25 +3658,6 @@ rc-old select, } } -.zoomIn { - -webkit-animation-name: zoomIn; - animation-name: zoomIn; -} - -.rc-old .is-cordova { - & .flex-tab { - & .control { - padding-left: 50px; - } - - & button.more { - width: 60px; - - transform: translateX(-57px); - } - } -} - .rc-old .touch .footer { padding-right: 10px; padding-left: 10px; @@ -4610,24 +3819,6 @@ rc-old select, font-size: 80px; } -.rc-old .colorpicker-input { - text-indent: 34px; -} - -.rc-old .colorpicker-swatch { - position: absolute; - top: 4px; - left: 4px; - - display: block; - overflow: hidden; - - width: 32px; - height: 32px; - - border-radius: 2px; -} - .rc-old .inline-video { width: 100%; max-width: 480px; @@ -4785,10 +3976,6 @@ rc-old select, } } -.sweet-alert .sa-input-error { - top: 19px; -} - .rc-old .collapse-switch { cursor: pointer; } @@ -4880,14 +4067,6 @@ rc-old select, min-height: 36px; padding: 0; - & .message-form { - margin-bottom: 0; - } - - & .message-input { - border-width: 0; - } - & .users-typing { display: none; } @@ -4922,10 +4101,6 @@ rc-old select, .rc-old.main-content { transform: translateX(0) !important; } - - .sweet-alert { - margin-left: -239px !important; - } } @media (width <= 780px) { @@ -4949,20 +4124,6 @@ rc-old select, } } - .rc-old .sweet-alert { - & h2 { - margin: 10px 0; - - font-size: 20px; - line-height: 30px; - } - - & button { - margin-top: 6px; - padding: 10px 22px; - } - } - .rc-old .code-mirror-box.code-mirror-box-fullscreen { left: 0; } @@ -4989,10 +4150,6 @@ rc-old select, } @media (width <= 500px) { - .rc-old .messages-container .message-form > .formatting-tips { - display: none; - } - .cms-page { padding: 0; @@ -5024,10 +4181,6 @@ rc-old select, .rc-old .oauth-login { margin-bottom: 6px; } - - .rc-old .message-form textarea { - max-height: 100px !important; - } } @media (width <= 440px) { @@ -5048,12 +4201,6 @@ rc-old select, } } -@media (height <= 260px) { - .rc-old .message-form textarea { - max-height: 50px !important; - } -} - .room-leader .chat-now { position: absolute; right: 25px; diff --git a/app/theme/client/imports/general/forms.css b/app/theme/client/imports/general/forms.css index ba214e96548a..9516f91a2072 100644 --- a/app/theme/client/imports/general/forms.css +++ b/app/theme/client/imports/general/forms.css @@ -1,63 +1,4 @@ .input { - &.radio { - position: relative; - - min-height: 13px; - - & input { - position: absolute; - z-index: -1; - top: 0; - left: 0; - - width: 0; - height: 0; - - opacity: 0; - outline: 0; - - &:checked + label::after { - opacity: 1; - } - } - - & label { - padding-left: 20px; - - cursor: pointer; - user-select: none; - - &::before { - position: absolute; - top: 0; - left: 0; - - width: 15px; - height: 15px; - - content: ''; - - border-width: 1px; - border-radius: 50%; - } - - &::after { - position: absolute; - top: 4px; - left: 4px; - - width: 7px; - height: 7px; - - content: ''; - transition: opacity 0.2s ease-out; - - opacity: 0; - border-radius: 50%; - } - } - } - &.checkbox.toggle { position: relative; diff --git a/app/theme/client/imports/general/rtl.css b/app/theme/client/imports/general/rtl.css index 2be992c93dbe..dc230d84010d 100644 --- a/app/theme/client/imports/general/rtl.css +++ b/app/theme/client/imports/general/rtl.css @@ -18,10 +18,6 @@ text-align: right; } - & .text-right { - text-align: left; - } - & .main-content { left: 0; @@ -102,37 +98,6 @@ right: 0; left: auto; } - - & .message-form { - & > div .input-message-container .inner-left-toolbar { - right: 13px; - left: auto; - } - - & textarea { - padding-right: 49px; - padding-left: 8px; - - text-align: right; - - border-width: 0 0 0 1px; - border-right-width: 0; - } - - & > .formatting-tips { - position: relative; - right: auto; - - float: left; - - & q { - padding: 0 3px 0 0; - - border-right: 3px solid; - border-left: 0 none; - } - } - } } & .account-box .options { @@ -250,24 +215,6 @@ } } - & .user-image .avatar::after { - right: -12px; - left: auto; - } - - & .lines .user-image { - & button > div { - float: right; - } - - & p { - float: right; - - padding-right: 10px; - padding-left: auto; - } - } - & .user-view { & nav { margin-right: -4px; @@ -454,13 +401,6 @@ margin-left: auto; } - & .user-image { - float: left; - - margin-right: 12px; - margin-left: auto; - } - & table thead th { text-align: right; } @@ -490,10 +430,6 @@ right: 0; } - & .logoutOthers { - text-align: left; - } - & .submit { text-align: left; } @@ -505,26 +441,6 @@ left: 12px; } - & .toolbar-search__icon { - right: 0; - } - - & .toolbar-search__icon--cancel { - right: auto; - left: 0; - } - - & .message-popup.search-results-list { - padding: 25px 8px 0 0; - - text-align: right; - direction: ltr; - - & .popup-item { - direction: rtl; - } - } - @media (width <= 1100px) { & #rocket-chat .flex-opened { left: 0; diff --git a/app/theme/client/imports/general/theme_old.css b/app/theme/client/imports/general/theme_old.css new file mode 100644 index 000000000000..657ebb4f3c41 --- /dev/null +++ b/app/theme/client/imports/general/theme_old.css @@ -0,0 +1,557 @@ +.content-background-color { + background-color: var(--content-background-color); +} + +.color-content-background-color { + color: var(--content-background-color); +} + +.primary-background-color { + background-color: var(--primary-background-color); +} + +.color-primary-font-color { + color: var(--primary-font-color); +} + +.color-primary-action-color { + color: var(--primary-action-color); +} + +.background-primary-action-color { + background-color: var(--primary-action-color); +} + +.secondary-background-color { + background-color: var(--secondary-background-color); +} + +.border-secondary-background-color { + border-color: var(--secondary-background-color); +} + +.secondary-font-color { + color: var(--secondary-font-color); +} + +.border-component-color { + border-color: var(--component-color); +} + +.background-component-color { + background-color: var(--component-color); +} + +.color-component-color { + color: var(--component-color); +} + +.success-color { + color: var(--success-color); +} + +.pending-color { + color: var(--pending-color); +} + +.pending-background { + background-color: var(--pending-background); +} + +.pending-border { + border-color: var(--pending-border); +} + +.error-color { + color: var(--error-color); +} + +.background-error-color { + background-color: var(--error-color); +} + +.color-info-font-color { + color: var(--info-font-color); +} + +.background-info-font-color { + background-color: var(--info-font-color); +} + +.background-attention-color { + background-color: var(--attention-color); +} + +.tertiary-background-color { + background-color: var(--tertiary-background-color); +} + +.border-tertiary-background-color { + border-color: var(--tertiary-background-color); +} + +.color-tertiary-font-color { + color: var(--tertiary-font-color); +} + +.error-background { + background-color: var(--error-background); +} + +.error-border { + border-color: var(--error-border); +} + +.color-error-contrast { + color: var(--error-contrast); +} + +.background-transparent-darkest { + background-color: var(--transparent-darkest); +} + +.background-transparent-darker { + background-color: var(--transparent-darker); +} + +.background-transparent-darker-hover:hover { + background-color: var(--transparent-darker); +} + +.background-transparent-darker-before::before { + background-color: var(--transparent-darker); +} + +.background-transparent-dark { + background-color: var(--transparent-dark); +} + +.background-transparent-dark-hover:hover { + background-color: var(--transparent-dark); +} + +.border-transparent-dark { + border-color: var(--transparent-dark); +} + +.background-transparent-light { + background-color: var(--transparent-light); +} + +.border-transparent-lighter { + border-color: var(--transparent-lighter); +} + +.background-transparent-lightest { + background-color: var(--transparent-lightest); +} + +.color-primary-action-contrast { + color: var(--primary-action-contrast); +} + +* { + -webkit-overflow-scrolling: touch; + + &::-webkit-scrollbar { + width: 8px; + height: 8px; + + background: var(--transparent-dark); + } + + &::-webkit-scrollbar-thumb { + border-radius: 50px; + background-color: var(--custom-scrollbar-color); + } + + &::-webkit-scrollbar-corner { + background-color: var(--transparent-dark); + } +} + +.filter-item { + &:hover { + border-color: var(--info-font-color); + } + + &.active { + border-color: var(--primary-background-color); + } +} + +.burger i { + background-color: var(--primary-font-color); +} + +.input-line { + &.setting-changed > label { + color: var(--selection-color); + } +} + +input:-webkit-autofill { + color: var(--primary-font-color) !important; + background-color: transparent !important; +} + +input, +select, +textarea { + color: var(--primary-font-color); + border-style: solid; + border-color: var(--input-border-color); + background-color: transparent; + + &::placeholder { + color: var(--input-placeholder-color); + } + + &[disabled] { + background-color: var(--button-disabled-background); + } +} + +.disabled label, +[disabled] label { + color: var(--input-placeholder-color); +} + +.-autocomplete-container { + background-color: var(--popup-list-background); +} + +.-autocomplete-item.selected { + background-color: var(--popup-list-selected-background); +} + +.rc-old input[type="button"], +.rc-old input[type="submit"] { + color: var(--button-secondary-text-color); + border-color: var(--button-secondary-background); + background: var(--button-secondary-background); +} + +.input { + &.checkbox.toggle { + input:checked + label::before { + background-color: var(--button-primary-background); + } + + input:disabled + label::before { + background-color: var(--button-disabled-background) !important; + } + + label { + &::before { + background-color: var(--button-secondary-background); + } + + &::after { + background-color: var(--button-primary-text-color); + } + + &:hover { + &::before { + opacity: 0.6; + } + } + } + } +} + +.message, +.flex-tab { + a i, + a[class^="icon-"] { + color: var(--primary-font-color); + + &:hover { + opacity: 0.6; + } + } +} + +.error { + border-color: var(--error-color); +} + +.page-list, +.page-settings { + a:not(.rc-button) { + color: var(--primary-font-color); + + &:hover { + color: var(--primary-action-color); + } + } +} + +.admin-table-row { + background-color: var(--transparent-light); + + &:nth-of-type(even) { + background-color: var(--transparent-lightest); + } +} + +.avatar-suggestion-item { + .question-mark::before { + color: var(--secondary-font-color); + } +} + +.full-page, +.page-loading { + a { + color: var(--tertiary-font-color); + } + + a:hover { + color: var(--primary-background-contrast); + } +} + +#login-card { + .input-text { + input:-webkit-autofill { + box-shadow: 0 0 0 20px var(--content-background-color) inset; + } + } +} + +.toggle-favorite { + color: var(--component-color); +} + +.upload-progress-progress { + background-color: var(--success-background); +} + +.messages-container { + .footer { + background: var(--content-background-color); + } +} + +.message.editing { + background-color: var(--message-box-editing-color); +} + +.rc-old { + & .popup-item { + &.selected { + color: var(--primary-action-contrast); + background-color: var(--primary-action-color); + } + } +} + +.messages-box { + &.selectable .selected { + background-color: var(--selection-background); + } +} + +.message { + &.new-day::before { + background-color: var(--content-background-color); + } + + &.new-day::after { + border-color: var(--component-color); + } + + a { + color: var(--link-font-color); + + &:hover { + opacity: 0.6; + } + } + + .highlight-text { + background-color: var(--selection-background); + } +} + +.sidebar-item__last-message { + a:not(.mention-link) { + color: var(--link-font-color); + + &:hover { + opacity: 0.6; + } + } +} + +.flex-tab-bar { + .tab-button { + &:hover { + background-color: var(--secondary-background-color); + } + + &.active { + border-right-color: var(--selection-color); + background-color: var(--secondary-background-color); + } + + &.attention { + animation-name: blink; + animation-duration: 1000ms; + animation-iteration-count: infinite; + animation-direction: alternate; + } + } + + .counter { + color: white; + background: var(--secondary-font-color); + } +} + +i.status-online { + color: var(--status-online); +} + +.status-bg-online { + background-color: var(--status-online); +} + +.account-box .status-online .thumb::after, +.account-box .status.online::after, +.popup-user-status-online, +.status-online::after { + border-color: var(--status-online-darken-10); + background-color: var(--status-online); +} + +.account-box .status-offline .thumb::after, +.account-box .status.offline::after { + background-color: var(--transparent-lighter); +} + +i.status-away { + color: var(--status-away); +} + +.status-bg-away { + background-color: var(--status-away); +} + +.account-box .status-away .thumb::after, +.account-box .status.away::after, +.popup-user-status-away, +.status-away::after, +.status-pending::after { + border-color: var(--status-away-darken-10); + background-color: var(--status-away); +} + +i.status-busy { + color: var(--status-busy); +} + +.status-bg-busy { + background-color: var(--status-busy); +} + +.account-box .status-busy .thumb::after, +.account-box .status.busy::after, +.popup-user-status-busy, +.status-busy::after { + border-color: var(--status-busy-darken-10); + background-color: var(--status-busy); +} + +i.status-offline { + color: var(--status-offline); +} + +.status-bg-offline { + background-color: var(--status-offline); +} + +.popup-user-status-offline, +.status-offline::after { + border-color: var(--status-offline-darken-10); + background-color: var(--status-offline); +} + +.alert-warning { + color: var(--primary-font-color); + border-color: var(--rc-color-alert); + background-color: var(--message-box-editing-color); +} + +.alert-link { + color: var(--link-font-color); + + &:hover { + opacity: 0.6; + } +} + +label.required::after { + color: var(--error-color); +} + +.main-content, +.flex-tab { + .loading-animation > .bounce { + background-color: var(--primary-font-color); + } +} + +.loading-animation.loading-animation--primary > .bounce { + background-color: var(--primary-font-color); +} + +@keyframes blink { + from { + color: var(--selection-color); + } + + to { + opacity: inherit; + } +} + +.range-slider-range::-webkit-slider-thumb { + background-color: var(--button-primary-background); +} + +.range-slider-range::-webkit-slider-thumb:hover { + opacity: 0.6; +} + +.range-slider-range:active::-webkit-slider-thumb { + opacity: 0.9; +} + +.range-slider-range::-moz-range-thumb { + background-color: var(--button-primary-background); +} + +.range-slider-range::-moz-range-thumb:hover { + opacity: 0.6; +} + +.range-slider-range:active::-moz-range-thumb { + opacity: 0.9; +} + +.range-slider-range::-moz-range-track { + background-color: var(--tertiary-background-color); +} + +.range-slider-value { + color: var(--button-primary-text-color); + background-color: var(--button-primary-background); +} + +.range-slider-value::after { + border-top-color: transparent; + border-right-color: var(--rc-color-button-primary); + border-bottom-color: transparent; +} diff --git a/app/theme/client/imports/general/variables.css b/app/theme/client/imports/general/variables.css index 2cfb61fd812f..01325d295175 100644 --- a/app/theme/client/imports/general/variables.css +++ b/app/theme/client/imports/general/variables.css @@ -1,4 +1,66 @@ :root { + /* #region colors Colors */ + --rc-color-error: var(--color-red); + --rc-color-error-light: #e1364c; + --rc-color-alert: var(--color-yellow); + --rc-color-alert-light: var(--color-dark-yellow); + --rc-color-success: var(--color-green); + --rc-color-success-light: #25d198; + --rc-color-button-primary: var(--color-blue); + --rc-color-button-primary-light: var(--color-dark-blue); + --rc-color-alert-message-primary: var(--color-blue); + --rc-color-alert-message-primary-background: #f1f6ff; + --rc-color-alert-message-secondary: #7ca52b; + --rc-color-alert-message-secondary-background: #fafff1; + --rc-color-alert-message-warning: #d52d24; + --rc-color-alert-message-warning-background: #fff3f3; + --rc-color-primary: var(--color-dark); + --rc-color-primary-background: var(--color-dark); + --rc-color-primary-darkest: var(--color-darkest); + --rc-color-primary-dark: var(--color-dark-medium); + --rc-color-primary-light: var(--color-gray); + --rc-color-primary-light-medium: var(--color-gray-medium); + --rc-color-primary-lightest: var(--color-gray-lightest); + --rc-color-content: var(--color-white); + --rc-color-link-active: var(--rc-color-button-primary); + + /* #endregion */ + + /* #region colors Old Colors */ + --content-background-color: #ffffff; + --primary-background-color: #04436a; + --primary-font-color: #444444; + --primary-action-color: #1d74f5; + --secondary-background-color: #f4f4f4; + --secondary-font-color: #a0a0a0; + --secondary-action-color: #dddddd; + --component-color: #f2f3f5; + --success-color: #4dff4d; + --pending-color: #fcb316; + --error-color: #bc2031; + --selection-color: #02acec; + --attention-color: #9c27b0; + + /* #endregion */ + + /* #region less-colors Old Colors (minor) */ + --tertiary-background-color: var(--component-color); + --tertiary-font-color: var(--transparent-lightest); + --link-font-color: var(--primary-action-color); + --info-font-color: var(--secondary-font-color); + --custom-scrollbar-color: var(--transparent-darker); + --status-online: var(--success-color); + --status-away: var(--pending-color); + --status-busy: var(--error-color); + --status-offline: var(--transparent-darker); + + /* #endregion */ + + /* #region fonts Fonts */ + --body-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Meiryo UI', Arial, sans-serif; + + /* #endregion */ + /* * Color palette */ @@ -36,29 +98,6 @@ --color-gray-lightest: #f2f3f5; --color-black: #000000; --color-white: #ffffff; - --rc-color-error: var(--color-red); - --rc-color-error-light: #e1364c; - --rc-color-alert: var(--color-yellow); - --rc-color-alert-light: var(--color-dark-yellow); - --rc-color-success: var(--color-green); - --rc-color-success-light: #25d198; - --rc-color-button-primary: var(--color-blue); - --rc-color-button-primary-light: var(--color-dark-blue); - --rc-color-alert-message-primary: var(--color-blue); - --rc-color-alert-message-primary-background: #f1f6ff; - --rc-color-alert-message-secondary: #7ca52b; - --rc-color-alert-message-secondary-background: #fafff1; - --rc-color-alert-message-warning: #d52d24; - --rc-color-alert-message-warning-background: #fff3f3; - --rc-color-primary: var(--color-dark); - --rc-color-primary-background: var(--color-dark); - --rc-color-primary-darkest: var(--color-darkest); - --rc-color-primary-dark: var(--color-dark-medium); - --rc-color-primary-light: var(--color-gray); - --rc-color-primary-light-medium: var(--color-gray-medium); - --rc-color-primary-lightest: var(--color-gray-lightest); - --rc-color-content: var(--color-white); - --rc-color-link-active: var(--rc-color-button-primary); /* * General @@ -71,7 +110,6 @@ --flex-tab-width: 400px; --flex-tab-webrtc-width: 400px; --flex-tab-webrtc-2-width: 850px; - --user-image-square: 20px; --border: 2px; --border-radius: 2px; --status-online: var(--rc-color-success); diff --git a/app/theme/client/main.css b/app/theme/client/main.css index 56d02e89df83..fa98f893547c 100644 --- a/app/theme/client/main.css +++ b/app/theme/client/main.css @@ -58,3 +58,6 @@ /* RTL */ @import 'imports/general/rtl.css'; + +/* Legacy theming */ +@import 'imports/general/theme_old.css'; diff --git a/app/theme/server/server.js b/app/theme/server/server.js index 9cde1fc67536..1b3ee5ed7435 100644 --- a/app/theme/server/server.js +++ b/app/theme/server/server.js @@ -26,7 +26,6 @@ export const theme = new class { constructor() { this.variables = {}; this.packageCallbacks = []; - this.files = ['server/colors.less']; this.customCSS = ''; settings.add('css', ''); settings.addGroup('Layout'); @@ -59,9 +58,7 @@ export const theme = new class { } compile() { - let content = [this.getVariablesAsLess()]; - - content.push(...this.files.map((name) => Assets.getText(name))); + let content = []; content.push(...this.packageCallbacks.map((name) => name())); @@ -122,14 +119,6 @@ export const theme = new class { } } - addPublicColor(name, value, section, editor = 'color', property) { - return this.addVariable('color', name, value, section, true, editor, ['color', 'expression'], property); - } - - addPublicFont(name, value) { - return this.addVariable('font', name, value, 'Fonts', true); - } - getVariablesAsObject() { return Object.keys(this.variables).reduce((obj, name) => { obj[name] = this.variables[name].value; @@ -137,13 +126,6 @@ export const theme = new class { }, {}); } - getVariablesAsLess() { - return Object.keys(this.variables).map((name) => { - const variable = this.variables[name]; - return `@${ name }: ${ variable.value };`; - }).join('\n'); - } - addPackageAsset(cb) { this.packageCallbacks.push(cb); return this.compileDelayed(); diff --git a/app/theme/server/variables.js b/app/theme/server/variables.js index cf4d7bd587f5..c95c243ffeb6 100644 --- a/app/theme/server/variables.js +++ b/app/theme/server/variables.js @@ -10,62 +10,43 @@ import { settings } from '../../settings'; // Major colors form the core of the scheme // Names changed to reflect usage, comments show pre-refactor names -const reg = /--(rc-color-.*?): (.*?);/igm; - -const colors = [...Assets.getText('client/imports/general/variables.css').match(reg)].map((color) => { - const [name, value] = color.split(': '); - return [name.replace('--', ''), value.replace(';', '')]; -}); - -colors.forEach(([key, color]) => { - if (/var/.test(color)) { - const [, value] = color.match(/var\(--(.*?)\)/i); - return theme.addPublicColor(key, value, 'Colors', 'expression'); - } - theme.addPublicColor(key, color, 'Colors'); -}); - -const majorColors = { - 'content-background-color': '#FFFFFF', - 'primary-background-color': '#04436A', - 'primary-font-color': '#444444', - 'primary-action-color': '#1d74f5', // was action-buttons-color - 'secondary-background-color': '#F4F4F4', - 'secondary-font-color': '#A0A0A0', - 'secondary-action-color': '#DDDDDD', - 'component-color': '#f2f3f5', - 'success-color': '#4dff4d', - 'pending-color': '#FCB316', - 'error-color': '#BC2031', - 'selection-color': '#02ACEC', - 'attention-color': '#9C27B0', -}; - -// Minor colours implement major colours by default, but can be overruled -const minorColors = { - 'tertiary-background-color': '@component-color', - 'tertiary-font-color': '@transparent-lightest', - 'link-font-color': '@primary-action-color', - 'info-font-color': '@secondary-font-color', - 'custom-scrollbar-color': '@transparent-darker', - 'status-online': '@success-color', - 'status-away': '@pending-color', - 'status-busy': '@error-color', - 'status-offline': '@transparent-darker', -}; - -// Bulk-add settings for color scheme -Object.keys(majorColors).forEach((key) => { - const value = majorColors[key]; - theme.addPublicColor(key, value, 'Old Colors'); -}); - -Object.keys(minorColors).forEach((key) => { - const value = minorColors[key]; - theme.addPublicColor(key, value, 'Old Colors (minor)', 'expression'); -}); - -theme.addPublicFont('body-font-family', '-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Oxygen, Ubuntu, Cantarell, \'Helvetica Neue\', \'Apple Color Emoji\', \'Segoe UI Emoji\', \'Segoe UI Symbol\', \'Meiryo UI\', Arial, sans-serif'); +const variablesContent = Assets.getText('client/imports/general/variables.css'); + +const regionRegex = /\/\*\s*#region\s+([^ ]*?)\s+(.*?)\s*\*\/((.|\s)*?)\/\*\s*#endregion\s*\*\//igm; + +for (let matches = regionRegex.exec(variablesContent); matches; matches = regionRegex.exec(variablesContent)) { + const [, type, section, content] = matches; + [...content.match(/--(.*?):\s*(.*?);/igm)].forEach((entry) => { + const matches = /--(.*?):\s*(.*?);/im.exec(entry); + const [, name, value] = matches; + + if (type === 'fonts') { + theme.addVariable('font', name, value, 'Fonts', true); + return; + } + + if (type === 'colors') { + if (/var/.test(value)) { + const [, variableName] = value.match(/var\(--(.*?)\)/i); + theme.addVariable('color', name, variableName, section, true, 'expression', ['color', 'expression']); + return; + } + + theme.addVariable('color', name, value, section, true, 'color', ['color', 'expression']); + return; + } + + if (type === 'less-colors') { + if (/var/.test(value)) { + const [, variableName] = value.match(/var\(--(.*?)\)/i); + theme.addVariable('color', name, `@${ variableName }`, section, true, 'expression', ['color', 'expression']); + return; + } + + theme.addVariable('color', name, value, section, true, 'color', ['color', 'expression']); + } + }); +} settings.add('theme-custom-css', '', { group: 'Layout', diff --git a/app/tokenpass/client/tokenpassChannelSettings.html b/app/tokenpass/client/tokenpassChannelSettings.html index 4f9ab15e9f37..f0e5490ab438 100644 --- a/app/tokenpass/client/tokenpassChannelSettings.html +++ b/app/tokenpass/client/tokenpassChannelSettings.html @@ -1,7 +1,7 @@ diff --git a/app/ui-account/client/avatar/prompt.html b/app/ui-account/client/avatar/prompt.html index 5a6d482dd20d..d1a8aaaf015f 100644 --- a/app/ui-account/client/avatar/prompt.html +++ b/app/ui-account/client/avatar/prompt.html @@ -4,7 +4,7 @@
- +
{{/if}} @@ -15,7 +15,7 @@
- +
{{/if}} @@ -35,7 +35,7 @@ {{> avatar username=initialsUsername }} {{#with service='initials'}}
- +
{{/with}}
@@ -43,11 +43,11 @@
-
{{_ "Select_file"}} +
{{_ "Select_file"}}
{{#with upload}} - + {{/with}}
@@ -57,7 +57,7 @@
- +
{{/with}} @@ -100,7 +100,7 @@ {{#if username.ready}}
- +
{{/if}}
diff --git a/app/ui-flextab/client/tabs/userInfo.html b/app/ui-flextab/client/tabs/userInfo.html index 69e6128cf614..69c85ecd4075 100644 --- a/app/ui-flextab/client/tabs/userInfo.html +++ b/app/ui-flextab/client/tabs/userInfo.html @@ -29,7 +29,7 @@

{{_ "User_Info"}}

- + {{#if username}}{{/if}} {{# userPresence uid=uid}}
diff --git a/app/ui-login/client/reset-password/resetPassword.html b/app/ui-login/client/reset-password/resetPassword.html index b1d6c4f3d8fb..549d1fafb753 100644 --- a/app/ui-login/client/reset-password/resetPassword.html +++ b/app/ui-login/client/reset-password/resetPassword.html @@ -23,7 +23,7 @@
- +
diff --git a/app/ui-master/.eslintrc b/app/ui-master/.eslintrc deleted file mode 100644 index 275f73194ad6..000000000000 --- a/app/ui-master/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "globals": { - "DynamicCss": false - } -} \ No newline at end of file diff --git a/app/ui-master/client/main.html b/app/ui-master/client/main.html index 040c1eae7678..22cfc0b1d330 100644 --- a/app/ui-master/client/main.html +++ b/app/ui-master/client/main.html @@ -1,4 +1,4 @@ - +
diff --git a/app/ui-master/client/main.js b/app/ui-master/client/main.js index 0a7e0753ecc8..e5580d61ea27 100644 --- a/app/ui-master/client/main.js +++ b/app/ui-master/client/main.js @@ -30,8 +30,6 @@ function customScriptsOnLogout() { } } -settings.collection.find({ _id: /theme-color-rc/i }, { fields: { value: 1 } }).observe({ changed: () => { DynamicCss.run(true, settings); } }); - callbacks.add('afterLogoutCleanUp', () => customScriptsOnLogout(), callbacks.priority.LOW, 'custom-script-on-logout'); Template.body.onRendered(function() { diff --git a/app/ui-master/server/inject.js b/app/ui-master/server/inject.js index 62b08f405849..5f0ac8fcaed3 100644 --- a/app/ui-master/server/inject.js +++ b/app/ui-master/server/inject.js @@ -35,7 +35,6 @@ Meteor.startup(() => { }); injectIntoHead('noreferrer', ''); - injectIntoHead('dynamic', ``); if (process.env.DISABLE_ANIMATION || process.env.TEST_MODE === 'true') { injectIntoHead('disable-animation', ` diff --git a/app/ui-message/client/message.html b/app/ui-message/client/message.html index f6dccc66a445..d8624209a8dd 100644 --- a/app/ui-message/client/message.html +++ b/app/ui-message/client/message.html @@ -158,7 +158,7 @@
diff --git a/imports/client/mimic-fn b/imports/client/mimic-fn deleted file mode 120000 index 6e14eb82385a..000000000000 --- a/imports/client/mimic-fn +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/mimic-fn \ No newline at end of file diff --git a/imports/client/mimic-fn/index.js b/imports/client/mimic-fn/index.js new file mode 120000 index 000000000000..3e62681b7465 --- /dev/null +++ b/imports/client/mimic-fn/index.js @@ -0,0 +1 @@ +../../../node_modules/mem/node_modules/mimic-fn/index.js \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7166d2061ff9..715b28d31286 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15831,28 +15831,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "resolved": false, "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, @@ -15863,14 +15863,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -15888,28 +15888,28 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true @@ -15926,21 +15926,21 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "resolved": false, "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true @@ -15957,14 +15957,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -15996,14 +15996,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "resolved": false, "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, @@ -16023,7 +16023,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -16041,14 +16041,14 @@ }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -16058,14 +16058,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -16075,7 +16075,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true @@ -16103,7 +16103,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -16158,7 +16158,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -16187,7 +16187,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -16200,21 +16200,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -16224,21 +16224,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -16249,7 +16249,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true @@ -16263,7 +16263,7 @@ }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "resolved": false, "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, @@ -16276,7 +16276,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -16285,7 +16285,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -16311,21 +16311,21 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true @@ -16339,21 +16339,21 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -16365,7 +16365,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -16375,7 +16375,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -16385,7 +16385,7 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true @@ -16408,14 +16408,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "resolved": false, "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, @@ -16425,7 +16425,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true @@ -21459,7 +21459,7 @@ "dependencies": { "asn1.js": { "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "resolved": false, "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "requires": { "bn.js": "^4.0.0", @@ -21469,7 +21469,7 @@ }, "assert": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "resolved": false, "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", "requires": { "util": "0.10.3" @@ -21477,7 +21477,7 @@ "dependencies": { "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": false, "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "requires": { "inherits": "2.0.1" @@ -21487,22 +21487,22 @@ }, "base64-js": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "resolved": false, "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "bn.js": { "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "resolved": false, "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "brorand": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "resolved": false, "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": false, "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", @@ -21515,7 +21515,7 @@ }, "browserify-cipher": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "resolved": false, "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { "browserify-aes": "^1.0.4", @@ -21525,7 +21525,7 @@ }, "browserify-des": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "resolved": false, "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { "cipher-base": "^1.0.1", @@ -21536,7 +21536,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": false, "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { "bn.js": "^4.1.0", @@ -21545,7 +21545,7 @@ }, "browserify-sign": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "resolved": false, "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "requires": { "bn.js": "^4.1.1", @@ -21559,7 +21559,7 @@ }, "browserify-zlib": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "resolved": false, "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { "pako": "~1.0.5" @@ -21567,7 +21567,7 @@ }, "buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "resolved": false, "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "requires": { "base64-js": "^1.0.2", @@ -21576,17 +21576,17 @@ }, "buffer-xor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "resolved": false, "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, "builtin-status-codes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "resolved": false, "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, "cipher-base": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "resolved": false, "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { "inherits": "^2.0.1", @@ -21595,7 +21595,7 @@ }, "console-browserify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "resolved": false, "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "requires": { "date-now": "^0.1.4" @@ -21603,17 +21603,17 @@ }, "constants-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "resolved": false, "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-ecdh": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "resolved": false, "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "requires": { "bn.js": "^4.1.0", @@ -21622,7 +21622,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": false, "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", @@ -21634,7 +21634,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": false, "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", @@ -21647,7 +21647,7 @@ }, "crypto-browserify": { "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "resolved": false, "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { "browserify-cipher": "^1.0.0", @@ -21665,12 +21665,12 @@ }, "date-now": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "resolved": false, "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" }, "des.js": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "resolved": false, "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "requires": { "inherits": "^2.0.1", @@ -21679,7 +21679,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": false, "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", @@ -21689,12 +21689,12 @@ }, "domain-browser": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "resolved": false, "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" }, "elliptic": { "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "resolved": false, "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "requires": { "bn.js": "^4.4.0", @@ -21708,12 +21708,12 @@ }, "events": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "resolved": false, "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" }, "evp_bytestokey": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "resolved": false, "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { "md5.js": "^1.3.4", @@ -21722,7 +21722,7 @@ }, "hash-base": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "resolved": false, "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { "inherits": "^2.0.1", @@ -21731,7 +21731,7 @@ }, "hash.js": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "resolved": false, "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { "inherits": "^2.0.3", @@ -21740,14 +21740,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "hmac-drbg": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "resolved": false, "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { "hash.js": "^1.0.3", @@ -21757,27 +21757,27 @@ }, "https-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "resolved": false, "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "ieee754": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "resolved": false, "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "inherits": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "resolved": false, "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "md5.js": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "resolved": false, "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", @@ -21787,7 +21787,7 @@ }, "miller-rabin": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "resolved": false, "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { "bn.js": "^4.0.0", @@ -21796,27 +21796,27 @@ }, "minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "resolved": false, "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "resolved": false, "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "os-browserify": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "resolved": false, "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" }, "pako": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "resolved": false, "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" }, "parse-asn1": { "version": "5.1.4", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "resolved": false, "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "requires": { "asn1.js": "^4.0.0", @@ -21829,12 +21829,12 @@ }, "path-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.0.tgz", + "resolved": false, "integrity": "sha512-Hkavx/nY4/plImrZPHRk2CL9vpOymZLgEbMNX1U0bjcBL7QN9wODxyx0yaMZURSQaUtSEvDrfAvxa9oPb0at9g==" }, "pbkdf2": { "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "resolved": false, "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "requires": { "create-hash": "^1.1.2", @@ -21846,17 +21846,17 @@ }, "process": { "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "resolved": false, "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "public-encrypt": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "resolved": false, "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { "bn.js": "^4.1.0", @@ -21869,22 +21869,22 @@ }, "punycode": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "resolved": false, "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "querystring": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "resolved": false, "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, "querystring-es3": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "resolved": false, "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "resolved": false, "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" @@ -21892,7 +21892,7 @@ }, "randomfill": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "resolved": false, "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { "randombytes": "^2.0.5", @@ -21901,7 +21901,7 @@ }, "readable-stream": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "resolved": false, "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", "requires": { "inherits": "^2.0.3", @@ -21911,14 +21911,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "ripemd160": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "resolved": false, "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { "hash-base": "^3.0.0", @@ -21927,17 +21927,17 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "resolved": false, "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": false, "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", @@ -21946,7 +21946,7 @@ }, "stream-browserify": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "resolved": false, "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "requires": { "inherits": "~2.0.1", @@ -21955,7 +21955,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -21969,14 +21969,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -21986,7 +21986,7 @@ }, "stream-http": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.0.0.tgz", + "resolved": false, "integrity": "sha512-JELJfd+btL9GHtxU3+XXhg9NLYrKFnhybfvRuDghtyVkOFydz3PKNT1df07AMr88qW03WHF+FSV0PySpXignCA==", "requires": { "builtin-status-codes": "^3.0.0", @@ -21997,7 +21997,7 @@ }, "string_decoder": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "resolved": false, "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "requires": { "safe-buffer": "~5.1.0" @@ -22005,7 +22005,7 @@ }, "timers-browserify": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "resolved": false, "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "requires": { "setimmediate": "^1.0.4" @@ -22013,12 +22013,12 @@ }, "tty-browserify": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "resolved": false, "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" }, "url": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "resolved": false, "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "requires": { "punycode": "1.3.2", @@ -22027,14 +22027,14 @@ "dependencies": { "punycode": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "resolved": false, "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" } } }, "util": { "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "resolved": false, "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", "requires": { "inherits": "2.0.3" @@ -22042,24 +22042,24 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "vm-browserify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "resolved": false, "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==" }, "xtend": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "resolved": false, "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } diff --git a/private/client/imports/general/variables.css b/private/client/imports/general/variables.css deleted file mode 100644 index 92c5124c4d22..000000000000 --- a/private/client/imports/general/variables.css +++ /dev/null @@ -1,380 +0,0 @@ -:root { - /* - * Color palette - */ - --color-dark-100: #0c0d0f; - --color-dark-90: #1e232a; - --color-dark-80: #2e343e; - --color-dark-70: #53585f; - --color-dark-30: #9da2a9; - --color-dark-20: #caced1; - --color-dark-10: #e0e5e8; - --color-dark-05: #f1f2f4; - --color-dark-blue: #175cc4; - --color-blue: #1d74f5; - --color-light-blue: #4eb2f5; - --color-lighter-blue: #e8f2ff; - --color-purple: #861da8; - --color-red: #f5455c; - --color-dark-red: #e0364d; - --color-orange: #f59547; - --color-yellow: #ffd21f; - --color-dark-yellow: #f6c502; - --color-green: #2de0a5; - --color-dark-green: #26d198; - - /* - * General Colors - */ - --color-darkest: #1f2329; - --color-dark: #2f343d; - --color-dark-medium: #414852; - --color-dark-light: #6c727a; - --color-gray: #9ea2a8; - --color-gray-medium: #cbced1; - --color-gray-light: #e1e5e8; - --color-gray-lightest: #f2f3f5; - --color-black: #000000; - --color-white: #ffffff; - --rc-color-error: var(--color-red); - --rc-color-error-light: #e1364c; - --rc-color-alert: var(--color-yellow); - --rc-color-alert-light: var(--color-dark-yellow); - --rc-color-success: var(--color-green); - --rc-color-success-light: #25d198; - --rc-color-button-primary: var(--color-blue); - --rc-color-button-primary-light: var(--color-dark-blue); - --rc-color-alert-message-primary: var(--color-blue); - --rc-color-alert-message-primary-background: #f1f6ff; - --rc-color-alert-message-secondary: #7ca52b; - --rc-color-alert-message-secondary-background: #fafff1; - --rc-color-alert-message-warning: #d52d24; - --rc-color-alert-message-warning-background: #fff3f3; - --rc-color-primary: var(--color-dark); - --rc-color-primary-background: var(--color-dark); - --rc-color-primary-darkest: var(--color-darkest); - --rc-color-primary-dark: var(--color-dark-medium); - --rc-color-primary-light: var(--color-gray); - --rc-color-primary-light-medium: var(--color-gray-medium); - --rc-color-primary-lightest: var(--color-gray-lightest); - --rc-color-content: var(--color-white); - --rc-color-link-active: var(--rc-color-button-primary); - - /* - * General - */ - --text-size: 0.875rem; - --header-min-height: 60px; - --toolbar-height: 55px; - --footer-min-height: 70px; - --rooms-box-width: 280px; - --flex-tab-width: 400px; - --flex-tab-webrtc-width: 400px; - --flex-tab-webrtc-2-width: 850px; - --user-image-square: 20px; - --border: 2px; - --border-radius: 2px; - --status-online: var(--rc-color-success); - --status-away: var(--rc-color-alert); - --status-busy: var(--rc-color-error); - --status-invisible: var(--color-gray-medium); - --status-invisible-sidebar: var(--rc-color-primary-darkest); - --default-padding: 1.5rem; - --default-small-padding: 1rem; - --status-bullet-size: 10px; - --status-bullet-radius: 50%; - --account-username-weight: 700; - --status-name-weight: 400; - --default-font-weight-header: 500; - - /* - * General Typography - */ - --text-default-size: 1rem; - --text-default-weight: 500; - --text-small-size: 0.875rem; - --text-small-weight: 500; - --text-heading-size: 1.375rem; - --text-heading-weight: 700; - --text-label-size: 075rem; - --text-label-weight: 600; - --text-tiny-size: 075rem; - --text-tiny-weight: 400; - --text-micro-size: 0.625rem; - --text-micro-weight: 700; - - /* - * Forms - */ - --gap-between-elements: 2.5rem; - --label-margin-bottom: 1rem; - - /* - * Forms - Button - */ - --button-square-size: 36px; - --button-padding: 0.782rem; - --button-padding-small: 0 0.5rem; - --button-height-small: 28px; - --button-text-size-small: 13px; - --button-text-size: var(--input-font-size); - --button-border-width: var(--border); - --button-border-radius: var(--border-radius); - --button-disabled-background: var(--color-gray-light); - --button-disabled-text-color: var(--color-white); - --button-primary-background: var(--rc-color-button-primary); - --button-primary-text-color: var(--color-white); - --button-cancel-color: var(--rc-color-error); - --button-secondary-background: var(--color-gray-medium); - --button-secondary-text-color: var(--color-dark-medium); - - /* - * Forms - Input - */ - --input-font-size: 0.875rem; - --input-title-text-size: var(--input-font-size); - --input-title-color: #2d343d; - --input-text-color: var(--color-dark-medium); - --input-placeholder-color: var(--color-gray-medium); - --input-icon-color: var(--color-dark); - --input-border-color: var(--color-gray-light); - --input-border-width: var(--border); - --input-border-radius: var(--border-radius); - --input-description-text-color: var(--color-gray); - --input-description-text-size: var(--input-font-size); - --input-error-color: var(--rc-color-error); - - /* - * Forms - popup list - */ - --popup-list-border-radius: var(--border-radius); - --popup-list-background: var(--color-white); - --popup-list-background-hover: var(--color-gray-lightest); - --popup-list-selected-background: var(--color-gray-lightest); - --popup-list-name-color: #2d343d; - --popup-list-name-size: 1rem; - - /* - * Forms - tags - */ - --tags-border-width: var(--border); - --tags-border-radius: var(--border-radius); - --tags-border-color: var(--color-gray-light); - --tags-text-color: var(--rc-color-primary); - --tags-background: #f2f3f5; - --tags-avatar-size: 20px; - - /* - * Forms - select avatar - */ - --select-avatar-size: 48px; - --select-avatar-preview-size: 150px; - --select-avatar-upload-background: var(--color-gray-light); - --select-avatar-upload-color: #2d343d; - - /* - * Sidebar - */ - --sidebar-width: 280px; - --sidebar-small-width: 90%; - --sidebar-background: var(--rc-color-primary); - --sidebar-background-hover: var(--rc-color-primary-dark); - --sidebar-background-light: var(--rc-color-primary-lightest); - --sidebar-background-light-hover: var(--rc-color-primary-light); - --sidebar-background-light-active: var(--rc-color-primary-light-medium); - --sidebar-default-padding: 24px; - --sidebar-small-default-padding: 16px; - --sidebar-extra-small-default-padding: 12px; - --sidebar-footer-height: 48px; - --sidebar-small-header-padding: var(--sidebar-small-default-padding); - - /* - * Sidebar flex - */ - --sidebar-flex-search-background: var(--color-white); - --sidebar-flex-search-placeholder-color: var(--color-gray); - - /* - * Sidebar Account - */ - --sidebar-account-thumb-size: 23px; - --sidebar-small-account-thumb-size: 40px; - --sidebar-account-status-bullet-size: 10px; - --sidebar-small-account-status-bullet-size: 8px; - --sidebar-account-status-bullet-radius: 50%; - --sidebar-account-username-size: 1rem; - --sidebar-account-username-weight: 700; - --sidebar-small-account-username-weight: 400; - --sidebar-account-username-color: var(--color-white); - --sidebar-account-username-color-darker: var(--color-dark); - --sidebar-account-status-font-size: 0.875rem; - --sidebar-account-status-color: var(--color-gray); - - /* - * Sidebar Item - */ - --sidebar-item-radius: 2px; - --sidebar-item-height: 24px; - --sidebar-item-height-medium: 34px; - --sidebar-item-height-extended: 52px; - --sidebar-item-thumb-size: 18px; - --sidebar-item-thumb-size-medium: 27px; - --sidebar-item-thumb-size-extended: 36px; - --sidebar-item-text-color: var(--rc-color-primary-light); - --sidebar-item-background: inherit; - --sidebar-item-hover-background: var(--rc-color-primary-darkest); - --sidebar-item-active-background: var(--rc-color-primary-dark); - --sidebar-item-active-color: var(--sidebar-item-text-color); - --sidebar-item-unread-color: var(--rc-color-content); - --sidebar-item-unread-font-weight: 600; - --sidebar-item-popup-background: var(--rc-color-primary-dark); - --sidebar-item-user-status-size: 6px; - --sidebar-item-user-status-radius: 50%; - --sidebar-item-text-size: 0.875rem; - - /* - * Modal - */ - --modal-wrapper-width: 650px; - --modal-wrapper-margin: 3rem; - --modal-back-button-color: var(--color-gray); - - /* - * Modal - Create Channel - */ - --create-channel-gap-between-elements: 1rem; - --create-channel-title-color: var(--color-darkest); - --create-channel-title-text-size: 1.375rem; - --create-channel-description-color: var(--color-gray); - --create-channel-description-text-size: 0.875rem; - - /* - * Toolbar - */ - --toolbar-placeholder-color: var(--color-gray); - - /* - * Rooms list - */ - --rooms-list-title-color: var(--rc-color-primary-light); - --rooms-list-title-text-size: 0.75rem; - --rooms-list-empty-text-color: var(--color-gray); - --rooms-list-empty-text-size: 0.75rem; - --rooms-list-padding: var(--sidebar-default-padding); - --rooms-list-small-padding: var(--sidebar-small-default-padding); - - /* - * Chip - */ - --chip-background: #dddddd; - - /* - * Avatar - */ - --avatar-radius: var(--border-radius); - --avatar-initials-text-size: 22px; - --avatar-initials-text-weight: 700; - - /* - * Badge - */ - --badge-text-color: var(--color-white); - --badge-radius: 12px; - --badge-text-size: 0.75rem; - --badge-background: var(--rc-color-primary-dark); - --badge-unread-background: var(--rc-color-primary-dark); - --badge-user-mentions-background: var(--color-dark-blue); - --badge-group-mentions-background: var(--rc-color-primary-dark); - - /* - * Mention link - */ - --mention-link-radius: 10px; - --mention-link-background: var(--color-lighter-blue); - --mention-link-text-color: var(--color-dark-blue); - --mention-link-me-background: var(--color-dark-blue); - --mention-link-me-text-color: var(--color-white); - --mention-link-group-background: var(--rc-color-primary-dark); - --mention-link-group-text-color: var(--color-white); - - /* - * Message box - */ - --message-box-text-size: var(--input-font-size); - --message-box-placeholder-color: var(--color-gray-medium); - --message-box-markdown-color: var(--color-gray); - --message-box-markdown-hover-color: var(--color-dark); - --message-box-user-typing-color: var(--color-gray); - --message-box-user-typing-text-size: 0.75rem; - --message-box-user-typing-user-color: var(--color-dark); - --message-box-container-border-color: var(--color-gray-medium); - --message-box-container-border-width: var(--border); - --message-box-container-border-radius: var(--border-radius); - --message-box-editing-color: #fff5df; - --message-box-popover-title-text-color: var(--color-gray); - --message-box-popover-title-text-size: 0.75rem; - - /* - * Header - */ - --header-height: 77px; - --header-padding: 16px; - --header-toggle-favorite-color: var(--color-gray-medium); - --header-toggle-favorite-star-color: var(--rc-color-alert-light); - --header-toggle-encryption-off-color: var(--color-gray-medium); - --header-toggle-encryption-on-color: var(--rc-color-alert-message-secondary); - --header-title-username-color-darker: var(--color-dark); - --header-title-font-size: var(--text-default-size); - --header-title-font-size--subtitle: var(--text-small-size); - --header-title-status-color: var(--color-gray); - --header-title-username-weight: 400; - --header-title-status-name-weight: 400; - --header-title-status-bullet-radius: var(--status-bullet-radius); - --header-title-status-bullet-size: var(--status-bullet-size); - --header-background-color: var(--color-white); - - /* - * Flex nav - */ - --flex-nav-background: var(--color-gray-lightest); - - /* - * Popover - */ - --popover-padding: 1rem; - --popover-radius: var(--border-radius); - --popover-background: var(--color-white); - --popover-column-min-width: 130px; - --popover-column-padding: 1rem; - --popover-title-color: var(--color-dark); - --popover-title-text-size: 0.75rem; - --popover-item-color: var(--color-dark); - --popover-item-text-size: 0.875rem; - --popover-divider-height: 2px; - --popover-divider-color: var(--color-gray-light); - - /* - * Tooltip - */ - --tooltip-background: var(--color-darkest); - --tooltip-text-color: var(--color-white); - --tooltip-text-size: 0.75rem; - --tooltip-radius: var(--border-radius); - - /* - * alert - */ - --alerts-padding: var(--sidebar-default-padding); - --alerts-padding-vertical: 10px; - --alerts-padding-vertical-large: 20px; - --alerts-background: #1d73f5; - --alerts-color: var(--color-white); - --alerts-font-size: var(--text-default-size); - --content-page-padding: 2.5rem; - - /* - * badge - */ - --badge-size: 14px; - --badge-font-size: 0.625rem; -} diff --git a/private/client/imports/general/variables.css b/private/client/imports/general/variables.css new file mode 120000 index 000000000000..5593377224c7 --- /dev/null +++ b/private/client/imports/general/variables.css @@ -0,0 +1 @@ +../../../../app/theme/client/imports/general/variables.css \ No newline at end of file diff --git a/private/server/colors.less b/private/server/colors.less deleted file mode 100755 index 638946d86c82..000000000000 --- a/private/server/colors.less +++ /dev/null @@ -1,893 +0,0 @@ -/** ---------------------------------------------------------------------------- - * Derivative colours (fixed variants of inherited variables) - */ -@default-action-color: darken(@secondary-background-color, 15%); -@default-action-contrast: contrast(@default-action-color, #444444); -@primary-background-contrast: contrast(@primary-background-color, #444444); -@primary-action-contrast: contrast(@primary-action-color, #444444); -@secondary-background-contrast: contrast(@secondary-background-color, #444444); -@secondary-action-contrast: contrast(@secondary-action-color, #444444); -@selection-background: lighten(@selection-color, 30%); -@success-background: lighten(@success-color, 45%); -@success-border: lighten(@success-color, 30%); -@error-background: lighten(@error-color, 45%); -@error-border: lighten(@error-color, 30%); -@error-contrast: contrast(@error-color); -@pending-background: lighten(@pending-color, 45%); -@pending-border: lighten(@pending-color, 30%); - -/** ---------------------------------------------------------------------------- - * Transparency variables - */ - -@transparent-darkest: rgba(17, 12, 12, 0.5); -@transparent-darker: rgba(0, 0, 0, 0.15); -@transparent-dark: rgba(15, 34, 0, 0.05); -@transparent-light: rgba(255, 255, 255, 0.1); -@transparent-lighter: rgba(255, 255, 255, 0.3); -@transparent-lightest: rgba(255, 255, 255, 0.6); - -:root { - --legacy-default-action-color: @default-action-color; - --legacy-default-action-contrast: @default-action-contrast; - --legacy-primary-background-contrast: @primary-background-contrast; - --legacy-primary-action-contrast: @primary-action-contrast; - --legacy-secondary-background-contrast: @secondary-background-contrast; - --legacy-secondary-action-contrast: @secondary-action-contrast; - --legacy-selection-background: @selection-background; - --legacy-success-background: @success-background; - --legacy-success-border: @success-border; - --legacy-error-background: @error-background; - --legacy-error-border: @error-border; - --legacy-error-contrast: @error-contrast; - --legacy-pending-background: @pending-background; - --legacy-pending-border: @pending-border; - --legacy-transparent-darkest: @transparent-darkest; - --legacy-transparent-darker: @transparent-darker; - --legacy-transparent-dark: @transparent-dark; - --legacy-transparent-light: @transparent-light; - --legacy-transparent-lighter: @transparent-lighter; - --legacy-transparent-lightest: @transparent-lightest; -} - -/** ---------------------------------------------------------------------------- - * Mixins - */ - -.buttonColors(@color, @bg) { - color: @color; - background-color: @bg; - - &:hover { - color: mix(@color, contrast(@bg), 60%); - background-color: mix(@bg, contrast(@color), 60%); - } -} - -/** ---------------------------------------------------------------------------- - * Classes for variables - */ - -// Major colors - -.content-background-color { - background-color: @content-background-color; -} - -.color-content-background-color { - color: @content-background-color; -} - -.primary-background-color { - background-color: @primary-background-color; -} - -.global-font-family { - font-family: @body-font-family; -} - -.color-primary-font-color { - color: @primary-font-color; -} - -.color-primary-action-color { - color: @primary-action-color; -} - -.background-primary-action-color { - background-color: @primary-action-color; -} - -.secondary-background-color { - background-color: @secondary-background-color; -} - -.border-secondary-background-color { - border-color: @secondary-background-color; -} - -.secondary-font-color { - color: @secondary-font-color; -} - -.border-component-color { - border-color: @component-color; -} - -.background-component-color { - background-color: @component-color; -} - -.color-component-color { - color: @component-color; -} - -.success-color { - color: @success-color; -} - -.pending-color { - color: @pending-color; -} - -.pending-background { - background-color: @pending-background; -} - -.pending-border { - border-color: @pending-border; -} - -.error-color { - color: @error-color; -} - -.background-error-color { - background-color: @error-color; -} - -.color-info-font-color { - color: @info-font-color; -} - -.background-info-font-color { - background-color: @info-font-color; -} - -.background-attention-color { - background-color: @attention-color; -} - -// Minor Colors - -.tertiary-background-color { - background-color: @tertiary-background-color; -} - -.border-tertiary-background-color { - border-color: @tertiary-background-color; -} - -// Derivative Colors - -.color-tertiary-font-color { - color: @tertiary-font-color; -} - -.error-background { - background-color: @error-background; -} - -.error-border { - border-color: @error-border; -} - -.color-error-contrast { - color: @error-contrast; -} - -// transparent - -.background-transparent-darkest { - background-color: @transparent-darkest; -} - -.background-transparent-darker { - background-color: @transparent-darker; -} - -.background-transparent-darker-hover:hover { - background-color: @transparent-darker; -} - -.background-transparent-darker-before::before { - background-color: @transparent-darker; -} - -.background-transparent-dark { - background-color: @transparent-dark; -} - -.background-transparent-dark-hover:hover { - background-color: @transparent-dark; -} - -.border-transparent-dark { - border-color: @transparent-dark; -} - -.background-transparent-light { - background-color: @transparent-light; -} - -.border-transparent-lighter { - border-color: @transparent-lighter; -} - -.background-transparent-lightest { - background-color: @transparent-lightest; -} - -// Derivative Colors -.color-primary-action-contrast { - color: @primary-action-contrast; -} - -/** ---------------------------------------------------------------------------- - * Special components - */ - -* { - -webkit-overflow-scrolling: touch; - - &::-webkit-scrollbar { - height: 8px; - width: 8px; - background: @transparent-dark; - } - - &::-webkit-scrollbar-thumb { - background-color: @custom-scrollbar-color; - -webkit-border-radius: 50px; - } - - &::-webkit-scrollbar-corner { - background-color: @transparent-dark; - } -} - -.filter-item { - &:hover { - border-color: @info-font-color; - } - - &.active { - border-color: @primary-background-color; - } -} - -/** ---------------------------------------------------------------------------- - * Document components - */ - -.burger i { - background-color: @primary-font-color; -} - -/** ---------------------------------------------------------------------------- - * Forms - */ - -input, -select, -textarea { - color: @primary-font-color; - background-color: transparent; - border-color: mix(contrast(@content-background-color), @content-background-color, 10%); - border-style: solid; - - &::placeholder { - color: mix(@primary-font-color, @content-background-color, 75%); - } - - &[disabled] { - background-color: mix(contrast(@content-background-color), @content-background-color, 10%); - } -} - -.disabled label, -[disabled] label { - color: mix(@primary-font-color, @content-background-color, 75%); -} - -.-autocomplete-container { - background-color: mix(contrast(@content-background-color), @content-background-color, 10%); -} - -.-autocomplete-item.selected { - background-color: mix(contrast(@content-background-color), @content-background-color, 20%); -} - -.rc-old input[type="button"], -.rc-old input[type="submit"] { - color: @primary-font-color; - background: mix(contrast(@content-background-color), @content-background-color, 10%); - border-color: mix(contrast(@content-background-color), @content-background-color, 10%); -} - -.toolbar-search__input { - &:focus { - border-color: fade(@primary-background-contrast, 50%); - } - - &::placeholder { - color: @transparent-lighter; - } -} - -.toolbar-search__buttons i:hover { - color: fade(@primary-background-contrast, 50%); -} - -// .flex-nav { -// input, -// select, -// textarea { -// color: @primary-background-contrast; -// background-color: transparent; -// border-color: mix(contrast(@transparent-lighter), @transparent-lighter, 10%); -// border-style: solid; - -// &::placeholder { -// color: mix(@primary-background-contrast, @transparent-lighter, 75%); -// } - -// &[disabled] { -// background-color: mix(contrast(@transparent-lighter), @transparent-lighter, 10%); -// } -// } - -// .disabled label, -// [disabled] label { -// color: mix(@primary-background-contrast, @transparent-lighter, 75%); -// } - -// .-autocomplete-container { -// background-color: mix(contrast(@transparent-lighter), @transparent-lighter, 10%); -// } - -// .-autocomplete-item.selected { -// background-color: mix(contrast(@transparent-lighter), @transparent-lighter, 20%); -// } - -// input[type="button"], -// input[type="submit"] { -// color: @primary-background-contrast; -// background: mix(contrast(@transparent-lighter), @transparent-lighter, 10%); -// border-color: mix(contrast(@transparent-lighter), @transparent-lighter, 10%); -// } - -// input { -// &:focus { -// border-color: fade(@primary-background-contrast, 50%); -// } -// } - -// .input.checkbox.toggle { -// input:checked + label::before { -// background-color: @primary-action-color; -// } -// } -// } - -.input-line { - &.setting-changed > label { - color: @selection-color; - } -} - -input:-webkit-autofill { - color: @primary-font-color !important; - background-color: transparent !important; -} - -.input { - &.radio { - label { - &::before { - border-color: lighten(@secondary-background-contrast, 30%); - background-color: @content-background-color; - } - - &::after { - background-color: @secondary-background-contrast; - } - } - } - - &.checkbox.toggle { - input:checked + label::before { - background-color: @secondary-background-contrast; - } - - input:disabled + label::before { - background-color: lighten(@secondary-background-contrast, 50%) !important; - } - - label { - &::before { - background-color: lighten(@secondary-background-contrast, 30%); - } - - &::after { - background-color: @content-background-color; - } - - &:hover { - &::before { - background-color: lighten(@secondary-background-contrast, 20%); - } - } - } - } -} - -/** ---------------------------------------------------------------------------- - * Misc typography variants - */ - -// a:active, -// a:hover { -// color: @primary-action-color; -// } - -.message, -.flex-tab { - a i, - a[class^="icon-"] { - color: @primary-font-color; - - &:hover { - color: darken(@primary-font-color, 10%); - } - } -} - -.error { - border-color: @error-color; -} - -/** ---------------------------------------------------------------------------- - * Admin and settings styles - */ - -.page-list, -.page-settings { - a:not(.rc-button) { - color: @primary-font-color; - - &:hover { - color: @primary-action-color; - } - } -} - -.admin-table-row { - background-color: @transparent-light; - - &:nth-of-type(even) { - background-color: @transparent-lightest; - } -} - -.avatar-suggestion-item { - .question-mark::before { - color: @secondary-font-color; - } -} - -/** ---------------------------------------------------------------------------- - * Asides (external to main application views) - */ - -.full-page, -.page-loading { - a { - color: @tertiary-font-color; - } - - a:hover { - color: @primary-background-contrast; - } -} - -#login-card { - .input-text { - input:-webkit-autofill { - -webkit-box-shadow: 0 0 0 20px @content-background-color inset; - } - } -} - -/** ---------------------------------------------------------------------------- - * Room components - */ - -.toggle-favorite { - color: @component-color; -} - -.upload-progress-progress { - background-color: @success-background; -} - -.messages-container { - .footer { - background: @content-background-color; - } -} - -.message-form { - .message-buttons { - .buttonColors(lighten(@primary-font-color, 25%), @secondary-background-color); - - &:hover { - background-color: mix(@secondary-background-color, contrast(@primary-font-color), 20%); - } - } - - .message-form-text { - &.editing { - background-color: lighten(@pending-color, 40%); - } - } -} - -.message.editing { - background-color: lighten(@pending-color, 40%); -} - -.rc-old { - & .popup-item { - &.selected { - color: @primary-action-contrast; - background-color: @primary-action-color; - } - } -} - -.messages-box { - &.selectable .selected { - background-color: @selection-background; - } -} - -/** ---------------------------------------------------------------------------- - * Message content - */ - -.message { - &.new-day::before { - background-color: @content-background-color; - } - - &.new-day::after { - border-color: @component-color; - } - - .options-menu { - color: lighten(@primary-font-color, 13%); - - ul li:hover { - background-color: @tertiary-background-color; - } - } - - a { - color: @link-font-color; - - &:hover { - color: darken(@link-font-color, 10%); - } - } - - .highlight-text { - background-color: @selection-background; - } -} - -/** ---------------------------------------------------------------------------- - * Sidebar - */ -.sidebar-item__last-message { - a:not(.mention-link) { - color: @link-font-color; - - &:hover { - color: darken(@link-font-color, 10%); - } - } -} - -.message-popup.search-results-list { - background-color: lighten(@primary-background-color, 2.5%); - - .popup-item.selected { - background-color: @transparent-darker; - } -} - -/** ---------------------------------------------------------------------------- - * Flex tabs / admin fly-out panels - */ -.flex-tab { - .channel-settings { - .buttons { - .button { - .buttonColors(lighten(@primary-font-color, 25%), @secondary-background-color); - } - } - - .input.checkbox.toggle { - input:checked + label::before { - background-color: @primary-background-color; - } - } - } -} - -.flex-tab-bar { - .tab-button { - &:hover { - background-color: @secondary-background-color; - } - - &.active { - background-color: @secondary-background-color; - border-right-color: @selection-color; - } - - &.attention { - animation-duration: 1000ms; - animation-name: blink; - animation-iteration-count: infinite; - animation-direction: alternate; - } - } - - .counter { - background: @secondary-font-color; - color: white; - } -} - -/** ---------------------------------------------------------------------------- - * User status / user meta - */ -i.status-online { - color: @status-online; -} - -.status-bg-online { - background-color: @status-online; -} - -.account-box .status-online .thumb::after, -.account-box .status.online::after, -.popup-user-status-online, -.status-online::after, -.user-image.status-online .avatar::after { - background-color: @status-online; - border-color: darken(@status-online, 10%); -} - -.account-box .status-offline .thumb::after, -.account-box .status.offline::after { - background-color: @transparent-lighter; -} - -i.status-away { - color: @status-away; -} - -.status-bg-away { - background-color: @status-away; -} - -.account-box .status-away .thumb::after, -.account-box .status.away::after, -.popup-user-status-away, -.status-away::after, -.status-pending::after, -.user-image.status-away .avatar::after { - background-color: @status-away; - border-color: darken(@status-away, 10%); -} - -i.status-busy { - color: @status-busy; -} - -.status-bg-busy { - background-color: @status-busy; -} - -.account-box .status-busy .thumb::after, -.account-box .status.busy::after, -.popup-user-status-busy, -.status-busy::after, -.user-image.status-busy .avatar::after { - background-color: @status-busy; - border-color: darken(@status-busy, 10%); -} - -i.status-offline { - color: @status-offline; -} - -.status-bg-offline { - background-color: @status-offline; -} - -.popup-user-status-offline, -.status-offline::after, -.user-image.status-offline .avatar::after { - background-color: @status-offline; - border-color: darken(@status-offline, 10%); -} - -// .popup-user-status-system { -// border-color: transparent; -// } - -// .user-view { -// .box::after, -// .stats li, -// .tags li { -// background-color: @component-color; -// } -// } - -/** ---------------------------------------------------------------------------- - * Buttons! - */ -.actionLinks li .action-link { - .buttonColors(@primary-action-contrast, @primary-action-color); -} - -// new layout buttons - -.button { - .buttonColors(@default-action-contrast, @default-action-color); - - &.primary { - .buttonColors(@primary-action-contrast, @primary-action-color); - - &[disabled] { - background-color: lighten(desaturate(@primary-action-color, 50%), 30%); - } - } - - &.secondary { - .buttonColors(@secondary-action-contrast, @secondary-action-color); - - &[disabled] { - background-color: lighten(desaturate(@secondary-action-color, 50%), 30%); - } - } - - &.tertiary { - .buttonColors(@primary-action-contrast, @selection-color); - - &[disabled] { - background-color: lighten(desaturate(@selection-color, 50%), 30%); - } - } - - &.danger { - .buttonColors(@error-contrast, @error-color); - - &[disabled] { - background-color: lighten(desaturate(@error-color, 50%), 30%); - } - } -} - -/** ---------------------------------------------------------------------------- - * Feedback and overlay content - */ - -.alert-warning { - color: darken(@pending-color, 25%); - background-color: @pending-background; -} - -.alert-link { - color: @link-font-color; - - &:hover { - color: darken(@link-font-color, 10%); - } -} - -label.required::after { - color: @error-color; -} - -/** ---------------------------------------------------------------------------- - * Loading - */ - -.main-content, -.flex-tab { - .loading-animation > .bounce { - background-color: @primary-font-color; - } -} - -.loading-animation.loading-animation--primary > .bounce { - background-color: @primary-font-color; -} - -@keyframes blink { - from { - color: @selection-color; - } - - to { - opacity: inherit; - } -} - -/** ---------------------------------------------------------------------------- - * Input Range Slider - */ - -.range-slider-range::-webkit-slider-thumb { - background-color: @primary-background-color; -} - -.range-slider-range::-webkit-slider-thumb:hover { - background-color: darken(@success-color, 30%); -} - -.range-slider-range:active::-webkit-slider-thumb { - background-color: darken(@success-color, 10%); -} - -.range-slider-range::-moz-range-thumb { - background-color: @primary-background-color; -} - -.range-slider-range::-moz-range-thumb:hover { - background-color: darken(@success-color, 30%); -} - -.range-slider-range:active::-moz-range-thumb { - background-color: darken(@success-color, 10%); -} - -.range-slider-value { - color: lighten(@tertiary-background-color, 50%); - background-color: @primary-background-color; -} - -.range-slider-value::after { - border-top-color: transparent; - border-right-color: @primary-background-color; - border-bottom-color: transparent; -} - -.range-slider-range::-moz-range-track { - background-color: @tertiary-background-color; -} - -.announcement { - background-color: @primary-background-color; - &.warning { - background-color: var(--rc-color-alert); - } - &.error { - background-color: var(--rc-color-alert-message-warning); - } -} diff --git a/private/server/dynamic-css.js b/private/server/dynamic-css.js deleted file mode 100644 index 2a17c4c073a3..000000000000 --- a/private/server/dynamic-css.js +++ /dev/null @@ -1,187 +0,0 @@ -/* eslint-disable */ - -'use strict'; -(function() { - var debounce = function debounce(func, wait, immediate) { - var timeout = void 0; - return function () { - var _this = this; - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var later = function later() { - timeout = null; - !immediate && func.apply(_this, args); - }; - - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - callNow && func.apply(this, args); - }; - }; - - var cssVarPoly = { - test: function test() { - return window.CSS && window.CSS.supports && window.CSS.supports('(--foo: red)'); - }, - init: function init() { - if (this.test()) { - return; - } - - console.time('cssVarPoly'); - cssVarPoly.ratifiedVars = {}; - cssVarPoly.varsByBlock = []; - cssVarPoly.oldCSS = []; - cssVarPoly.findCSS(); - cssVarPoly.updateCSS(); - console.timeEnd('cssVarPoly'); - }, - findCSS: function findCSS() { - var styleBlocks = Array.prototype.concat.apply([], document.querySelectorAll('#css-variables, link[type="text/css"].__meteor-css__')); - var counter = 1; - styleBlocks.map(function (block) { - if (block.nodeName === 'STYLE') { - var theCSS = block.innerHTML; - cssVarPoly.findSetters(theCSS, counter); - cssVarPoly.oldCSS[counter++] = theCSS; - } else if (block.nodeName === 'LINK') { - var url = block.getAttribute('href'); - cssVarPoly.oldCSS[counter] = ''; - cssVarPoly.getLink(url, counter, function (counter, request) { - cssVarPoly.findSetters(request.responseText, counter); - cssVarPoly.oldCSS[counter++] = request.responseText; - cssVarPoly.updateCSS(); - }); - } - }); - }, - findSetters: function findSetters(theCSS, counter) { - cssVarPoly.varsByBlock[counter] = theCSS.match(/(--[^:; ]+:..*?;)/g); - }, - - - updateCSS: debounce(function () { - cssVarPoly.ratifySetters(cssVarPoly.varsByBlock); - cssVarPoly.oldCSS.filter(function (e) { - return e; - }).forEach(function (css, id) { - var newCSS = cssVarPoly.replaceGetters(css, cssVarPoly.ratifiedVars); - var el = document.querySelector('#inserted' + id); - - if (el) { - el.innerHTML = newCSS; - } else { - var style = document.createElement('style'); - style.type = 'text/css'; - style.innerHTML = newCSS; - style.classList.add('inserted'); - style.id = 'inserted' + id; - document.getElementsByTagName('head')[0].appendChild(style); - } - }); - }, 100), - - replaceGetters: function replaceGetters(oldCSS, varList) { - return oldCSS.replace(/var\((--.*?)\)/gm, function (all, variable) { - return varList[variable]; - }); - }, - ratifySetters: function ratifySetters(varList) { - varList.filter(function (curVars) { - return curVars; - }).forEach(function (curVars) { - curVars.forEach(function (theVar) { - var matches = theVar.split(/:\s*/); - cssVarPoly.ratifiedVars[matches[0]] = matches[1].replace(/;/, ''); - }); - }); - Object.keys(cssVarPoly.ratifiedVars).filter(function (key) { - return cssVarPoly.ratifiedVars[key].indexOf('var') > -1; - }).forEach(function (key) { - cssVarPoly.ratifiedVars[key] = cssVarPoly.ratifiedVars[key].replace(/var\((--.*?)\)/gm, function (all, variable) { - return cssVarPoly.ratifiedVars[variable]; - }); - }); - }, - getLink: function getLink(url, counter, success) { - var request = new XMLHttpRequest(); - request.open('GET', url, true); - request.overrideMimeType('text/css;'); - - request.onload = function () { - if (request.status >= 200 && request.status < 400) { - if (typeof success === 'function') { - success(counter, request); - } - } else { - console.warn('an error was returned from:', url); - } - }; - - request.onerror = function () { - console.warn('we could not get anything from:', url); - }; - - request.send(); - } - }; - var stateCheck = setInterval(function () { - if (document.readyState === 'complete' && typeof Meteor !== 'undefined') { - clearInterval(stateCheck); - cssVarPoly.init(); - } - }, 100); - - var DynamicCss = {}; - - window.DynamicCss = DynamicCss; - - DynamicCss.test = function () { - return window.CSS && window.CSS.supports && window.CSS.supports('(--foo: red)'); - }; - - DynamicCss.run = debounce(function () { - var replace = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - var settings = arguments.length && arguments[1]; - - if (replace && !settings) { - console.error('You must provide settings to the "run" function in DynamicCss'); - } - - if (replace) { - var colors = settings.collection.find({ - _id: /theme-color-rc/i - }, { - fields: { - value: 1, - editor: 1 - } - }).fetch().filter(function (color) { - return color && color.value; - }); - - if (!colors) { - return; - } - - var css = colors.map(function (_ref) { - var _id = _ref._id, - value = _ref.value, - editor = _ref.editor; - - if (editor === 'expression') { - return '--' + _id.replace('theme-color-', '') + ': var(--' + value + ');'; - } - - return '--' + _id.replace('theme-color-', '') + ': ' + value + ';'; - }).join('\n'); - document.querySelector('#css-variables').innerHTML = ':root {' + css + '}'; - } - - cssVarPoly.init(); - }, 1000); -})(); diff --git a/tests/cypress/integration/04-main-elements-render.js b/tests/cypress/integration/04-main-elements-render.js index 1e71d695976b..6f9c19014fbe 100644 --- a/tests/cypress/integration/04-main-elements-render.js +++ b/tests/cypress/integration/04-main-elements-render.js @@ -133,10 +133,6 @@ describe('[Main Elements Render]', function() { mainContent.recordBtn.should('be.visible'); }); - it.skip('it should show the video call button', () => { - mainContent.videoCamBtn.should('be.visible'); - }); - it('it should show the emoji button', () => { mainContent.emojiBtn.should('be.visible'); }); diff --git a/tests/cypress/integration/12-settings.js b/tests/cypress/integration/12-settings.js index a8437627dfc7..be803c1f5c30 100644 --- a/tests/cypress/integration/12-settings.js +++ b/tests/cypress/integration/12-settings.js @@ -160,12 +160,6 @@ describe('[Api Settings Change]', () => { .end(done); }); - it.skip('it should not show the video file button', () => { - // the page needs a refresh to show the changes in the client - mainContent.videoCamBtn.waitForVisible(10000, true); - mainContent.videoCamBtn.should('not.be.visible'); - }); - it('it should change the message video files via api', (done) => { request.post(api('settings/Message_VideoRecorderEnabled')) .set(credentials) diff --git a/tests/cypress/pageobjects/main-content.page.js b/tests/cypress/pageobjects/main-content.page.js index d6d927443f4f..7ba9fe6fce88 100644 --- a/tests/cypress/pageobjects/main-content.page.js +++ b/tests/cypress/pageobjects/main-content.page.js @@ -19,8 +19,6 @@ class MainContent extends Page { get recordBtn() { return browser.element('.js-audio-message-record'); } - get videoCamBtn() { return browser.element('.message-buttons .icon-videocam'); } - get emojiBtn() { return browser.element('.rc-message-box__icon.emoji-picker-icon'); } get messagePopUp() { return browser.element('.message-popup'); } From 11a7ed87bb64fb57424d653e5a0389d87b17297a Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 15 May 2020 15:41:21 -0300 Subject: [PATCH 23/25] [NEW] Admin refactor Second phase (#17551) * [NEW] Redesign Administration > Connectivity Services (#17525) * [NEW] Admin Rewrite -> Integrations Page (#17505) * [NEW] Admin Rewrite -> OAuth Apps (#17646) Co-authored-by: Guilherme Gazzo Co-authored-by: Tasso Evangelista Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> --- app/cloud/client/admin/callback.html | 16 - app/cloud/client/admin/callback.js | 46 --- app/cloud/client/admin/cloud.html | 145 ------- app/cloud/client/admin/cloud.js | 233 ------------ .../client/admin/cloudRegisterManually.css | 26 -- .../client/admin/cloudRegisterManually.html | 36 -- .../client/admin/cloudRegisterManually.js | 106 ------ app/cloud/client/admin/index.js | 2 - app/cloud/client/index.js | 33 -- app/integrations/client/getIntegration.js | 34 -- app/integrations/client/index.js | 3 - app/integrations/client/route.js | 75 ---- app/integrations/client/streamer.js | 3 - .../client/stylesheets/integrations.css | 75 ---- .../client/views/additional/zapier.html | 10 - app/integrations/client/views/index.js | 11 - .../client/views/integrations.html | 74 ---- app/integrations/client/views/integrations.js | 65 ---- .../client/views/integrationsIncoming.html | 138 ------- .../client/views/integrationsIncoming.js | 251 ------------- .../client/views/integrationsNew.html | 51 --- .../client/views/integrationsNew.js | 35 -- .../client/views/integrationsOutgoing.html | 241 ------------ .../client/views/integrationsOutgoing.js | 353 ------------------ .../views/integrationsOutgoingHistory.html | 143 ------- .../views/integrationsOutgoingHistory.js | 191 ---------- .../client/views/messageExample.js | 39 -- .../client/admin/route.js | 28 -- .../client/admin/views/index.js | 4 - .../client/admin/views/oauthApp.html | 72 ---- .../client/admin/views/oauthApp.js | 120 ------ .../client/admin/views/oauthApps.html | 38 -- .../client/admin/views/oauthApps.js | 33 -- app/oauth2-server-config/client/index.js | 1 - app/ui/client/components/GenericTable.js | 78 ++-- app/utils/client/lib/handleError.js | 4 +- client/admin/cloud/CloudPage.js | 146 ++++++++ client/admin/cloud/CloudRoute.js | 17 + client/admin/cloud/ConnectToCloudSection.js | 61 +++ .../cloud/ManualWorkspaceRegistrationModal.js | 183 +++++++++ client/admin/cloud/TroubleshootingSection.js | 63 ++++ client/admin/cloud/WhatIsItSection.js | 32 ++ client/admin/cloud/WorkspaceLoginSection.js | 108 ++++++ .../cloud/WorkspaceRegistrationSection.js | 128 +++++++ client/admin/cloud/constants.js | 3 + client/admin/customSounds/EditSound.js | 202 ++++++++++ client/admin/customSounds/NewSound.js | 101 +++++ .../admin/integrations/IncomingWebhookForm.js | 165 ++++++++ client/admin/integrations/IntegrationsPage.js | 56 +++ .../admin/integrations/IntegrationsRoute.js | 40 ++ .../admin/integrations/IntegrationsTable.js | 97 +++++ .../integrations/OutgoiongWebhookForm.js | 264 +++++++++++++ .../integrations/edit/EditIncomingWebhook.js | 105 ++++++ .../integrations/edit/EditIntegrationsPage.js | 82 ++++ .../integrations/edit/EditOutgoingWebhook.js | 134 +++++++ .../edit/OutgoingWebhookHistoryPage.js | 268 +++++++++++++ .../admin/integrations/exampleIncomingData.js | 20 + client/admin/integrations/new/NewBot.js | 9 + .../integrations/new/NewIncomingWebhook.js | 50 +++ .../integrations/new/NewIntegrationsPage.js | 58 +++ .../integrations/new/NewOutgoingWebhook.js | 68 ++++ client/admin/integrations/new/NewZapier.js | 43 +++ client/admin/oauthApps/OAuthAddApp.js | 87 +++++ client/admin/oauthApps/OAuthAppsPage.js | 39 ++ client/admin/oauthApps/OAuthAppsRoute.js | 15 + client/admin/oauthApps/OAuthAppsTable.js | 40 ++ client/admin/oauthApps/OAuthEditApp.js | 222 +++++++++++ client/admin/rooms/EditRoom.js | 8 +- client/admin/rooms/edit/EditRoom.js | 194 ++++++++++ client/admin/routes.js | 15 + client/admin/sidebarItems.js | 7 + client/admin/users/EditUser.js | 8 +- client/admin/users/InviteUsers.js | 4 +- client/admin/users/UserInfo.js | 8 +- client/components/setupWizard/StepHeader.js | 14 +- client/hooks/useForm.js | 28 ++ client/hooks/useHilightCode.js | 6 + client/importPackages.js | 3 +- package-lock.json | 23 +- package.json | 2 +- packages/rocketchat-i18n/i18n/ca.i18n.json | 7 +- packages/rocketchat-i18n/i18n/cs.i18n.json | 8 +- packages/rocketchat-i18n/i18n/da.i18n.json | 5 +- packages/rocketchat-i18n/i18n/de-IN.i18n.json | 5 +- packages/rocketchat-i18n/i18n/de.i18n.json | 8 +- packages/rocketchat-i18n/i18n/en.i18n.json | 22 +- packages/rocketchat-i18n/i18n/es.i18n.json | 7 +- packages/rocketchat-i18n/i18n/fa.i18n.json | 8 +- packages/rocketchat-i18n/i18n/fr.i18n.json | 4 +- packages/rocketchat-i18n/i18n/hr.i18n.json | 7 +- packages/rocketchat-i18n/i18n/hu.i18n.json | 7 +- packages/rocketchat-i18n/i18n/ja.i18n.json | 8 +- packages/rocketchat-i18n/i18n/km.i18n.json | 8 +- packages/rocketchat-i18n/i18n/ko.i18n.json | 7 +- packages/rocketchat-i18n/i18n/nl.i18n.json | 3 +- packages/rocketchat-i18n/i18n/pl.i18n.json | 8 +- packages/rocketchat-i18n/i18n/pt-BR.i18n.json | 5 +- packages/rocketchat-i18n/i18n/pt.i18n.json | 7 +- packages/rocketchat-i18n/i18n/ru.i18n.json | 8 +- packages/rocketchat-i18n/i18n/sv.i18n.json | 3 +- packages/rocketchat-i18n/i18n/tr.i18n.json | 7 +- packages/rocketchat-i18n/i18n/uk.i18n.json | 8 +- packages/rocketchat-i18n/i18n/zh-TW.i18n.json | 6 +- packages/rocketchat-i18n/i18n/zh.i18n.json | 8 +- 104 files changed, 3304 insertions(+), 2909 deletions(-) delete mode 100644 app/cloud/client/admin/callback.html delete mode 100644 app/cloud/client/admin/callback.js delete mode 100644 app/cloud/client/admin/cloud.html delete mode 100644 app/cloud/client/admin/cloud.js delete mode 100644 app/cloud/client/admin/cloudRegisterManually.css delete mode 100644 app/cloud/client/admin/cloudRegisterManually.html delete mode 100644 app/cloud/client/admin/cloudRegisterManually.js delete mode 100644 app/cloud/client/admin/index.js delete mode 100644 app/cloud/client/index.js delete mode 100644 app/integrations/client/getIntegration.js delete mode 100644 app/integrations/client/index.js delete mode 100644 app/integrations/client/route.js delete mode 100644 app/integrations/client/streamer.js delete mode 100644 app/integrations/client/stylesheets/integrations.css delete mode 100644 app/integrations/client/views/additional/zapier.html delete mode 100644 app/integrations/client/views/index.js delete mode 100644 app/integrations/client/views/integrations.html delete mode 100644 app/integrations/client/views/integrations.js delete mode 100644 app/integrations/client/views/integrationsIncoming.html delete mode 100644 app/integrations/client/views/integrationsIncoming.js delete mode 100644 app/integrations/client/views/integrationsNew.html delete mode 100644 app/integrations/client/views/integrationsNew.js delete mode 100644 app/integrations/client/views/integrationsOutgoing.html delete mode 100644 app/integrations/client/views/integrationsOutgoing.js delete mode 100644 app/integrations/client/views/integrationsOutgoingHistory.html delete mode 100644 app/integrations/client/views/integrationsOutgoingHistory.js delete mode 100644 app/integrations/client/views/messageExample.js delete mode 100644 app/oauth2-server-config/client/admin/route.js delete mode 100644 app/oauth2-server-config/client/admin/views/index.js delete mode 100644 app/oauth2-server-config/client/admin/views/oauthApp.html delete mode 100644 app/oauth2-server-config/client/admin/views/oauthApp.js delete mode 100644 app/oauth2-server-config/client/admin/views/oauthApps.html delete mode 100644 app/oauth2-server-config/client/admin/views/oauthApps.js create mode 100644 client/admin/cloud/CloudPage.js create mode 100644 client/admin/cloud/CloudRoute.js create mode 100644 client/admin/cloud/ConnectToCloudSection.js create mode 100644 client/admin/cloud/ManualWorkspaceRegistrationModal.js create mode 100644 client/admin/cloud/TroubleshootingSection.js create mode 100644 client/admin/cloud/WhatIsItSection.js create mode 100644 client/admin/cloud/WorkspaceLoginSection.js create mode 100644 client/admin/cloud/WorkspaceRegistrationSection.js create mode 100644 client/admin/cloud/constants.js create mode 100644 client/admin/customSounds/EditSound.js create mode 100644 client/admin/customSounds/NewSound.js create mode 100644 client/admin/integrations/IncomingWebhookForm.js create mode 100644 client/admin/integrations/IntegrationsPage.js create mode 100644 client/admin/integrations/IntegrationsRoute.js create mode 100644 client/admin/integrations/IntegrationsTable.js create mode 100644 client/admin/integrations/OutgoiongWebhookForm.js create mode 100644 client/admin/integrations/edit/EditIncomingWebhook.js create mode 100644 client/admin/integrations/edit/EditIntegrationsPage.js create mode 100644 client/admin/integrations/edit/EditOutgoingWebhook.js create mode 100644 client/admin/integrations/edit/OutgoingWebhookHistoryPage.js create mode 100644 client/admin/integrations/exampleIncomingData.js create mode 100644 client/admin/integrations/new/NewBot.js create mode 100644 client/admin/integrations/new/NewIncomingWebhook.js create mode 100644 client/admin/integrations/new/NewIntegrationsPage.js create mode 100644 client/admin/integrations/new/NewOutgoingWebhook.js create mode 100644 client/admin/integrations/new/NewZapier.js create mode 100644 client/admin/oauthApps/OAuthAddApp.js create mode 100644 client/admin/oauthApps/OAuthAppsPage.js create mode 100644 client/admin/oauthApps/OAuthAppsRoute.js create mode 100644 client/admin/oauthApps/OAuthAppsTable.js create mode 100644 client/admin/oauthApps/OAuthEditApp.js create mode 100644 client/admin/rooms/edit/EditRoom.js create mode 100644 client/hooks/useForm.js create mode 100644 client/hooks/useHilightCode.js diff --git a/app/cloud/client/admin/callback.html b/app/cloud/client/admin/callback.html deleted file mode 100644 index 5d6c9c432f4c..000000000000 --- a/app/cloud/client/admin/callback.html +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/app/cloud/client/admin/callback.js b/app/cloud/client/admin/callback.js deleted file mode 100644 index de860026192e..000000000000 --- a/app/cloud/client/admin/callback.js +++ /dev/null @@ -1,46 +0,0 @@ -import './callback.html'; - -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import { Tracker } from 'meteor/tracker'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import queryString from 'query-string'; - -import { SideNav } from '../../../ui-utils/client'; - - -Template.cloudCallback.onCreated(function() { - const instance = this; - - instance.loading = new ReactiveVar(true); - instance.callbackError = new ReactiveVar({ error: false }); - - const params = queryString.parse(location.search); - - if (params.error_code) { - instance.callbackError.set({ error: true, errorCode: params.error_code }); - } else { - Meteor.call('cloud:finishOAuthAuthorization', params.code, params.state, (error) => { - if (error) { - console.warn('cloud:finishOAuthAuthorization', error); - return; - } - - FlowRouter.go('/admin/cloud'); - }); - } -}); - -Template.cloudCallback.helpers({ - callbackError() { - return Template.instance().callbackError.get(); - }, -}); - -Template.cloudCallback.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/cloud/client/admin/cloud.html b/app/cloud/client/admin/cloud.html deleted file mode 100644 index 78c1e053390d..000000000000 --- a/app/cloud/client/admin/cloud.html +++ /dev/null @@ -1,145 +0,0 @@ - diff --git a/app/cloud/client/admin/cloud.js b/app/cloud/client/admin/cloud.js deleted file mode 100644 index cd9edf0a41a6..000000000000 --- a/app/cloud/client/admin/cloud.js +++ /dev/null @@ -1,233 +0,0 @@ -import './cloud.html'; - -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import { Tracker } from 'meteor/tracker'; -import queryString from 'query-string'; -import toastr from 'toastr'; - -import { t } from '../../../utils'; -import { SideNav, modal } from '../../../ui-utils/client'; - - -Template.cloud.onCreated(function() { - const instance = this; - instance.info = new ReactiveVar(); - instance.loading = new ReactiveVar(true); - instance.isLoggedIn = new ReactiveVar(false); - - instance.loadRegStatus = function _loadRegStatus() { - Meteor.call('cloud:checkRegisterStatus', (error, info) => { - if (error) { - console.warn('cloud:checkRegisterStatus', error); - return; - } - - instance.info.set(info); - instance.loading.set(false); - }); - }; - - instance.getLoggedIn = function _getLoggedIn() { - Meteor.call('cloud:checkUserLoggedIn', (error, result) => { - if (error) { - console.warn(error); - return; - } - - instance.isLoggedIn.set(result); - }); - }; - - instance.oauthAuthorize = function _oauthAuthorize() { - Meteor.call('cloud:getOAuthAuthorizationUrl', (error, url) => { - if (error) { - console.warn(error); - return; - } - - window.location.href = url; - }); - }; - - instance.logout = function _logout() { - Meteor.call('cloud:logout', (error) => { - if (error) { - console.warn(error); - return; - } - - instance.getLoggedIn(); - }); - }; - - instance.connectWorkspace = function _connectWorkspace(token) { - Meteor.call('cloud:connectWorkspace', token, (error, success) => { - if (error) { - toastr.error(error); - instance.loadRegStatus(); - return; - } - - if (!success) { - toastr.error('An error occured connecting'); - instance.loadRegStatus(); - return; - } - - toastr.success(t('Connected')); - - instance.loadRegStatus(); - }); - }; - - instance.disconnectWorkspace = function _disconnectWorkspace() { - Meteor.call('cloud:disconnectWorkspace', (error, success) => { - if (error) { - toastr.error(error); - instance.loadRegStatus(); - return; - } - - if (!success) { - toastr.error('An error occured disconnecting'); - instance.loadRegStatus(); - return; - } - - toastr.success(t('Disconnected')); - - instance.loadRegStatus(); - }); - }; - - instance.syncWorkspace = function _syncWorkspace() { - Meteor.call('cloud:syncWorkspace', (error, success) => { - if (error) { - toastr.error(error); - instance.loadRegStatus(); - return; - } - - if (!success) { - toastr.error('An error occured syncing'); - instance.loadRegStatus(); - return; - } - - toastr.success(t('Sync Complete')); - - instance.loadRegStatus(); - }); - }; - - instance.registerWorkspace = function _registerWorkspace() { - Meteor.call('cloud:registerWorkspace', (error, success) => { - if (error) { - toastr.error(error); - instance.loadRegStatus(); - return; - } - - if (!success) { - toastr.error('An error occured'); - instance.loadRegStatus(); - return; - } - - return instance.syncWorkspace(); - }); - }; - - const params = queryString.parse(location.search); - - if (params.token) { - instance.connectWorkspace(params.token); - } else { - instance.loadRegStatus(); - } - - instance.getLoggedIn(); -}); - -Template.cloud.helpers({ - info() { - return Template.instance().info.get(); - }, - isLoggedIn() { - return Template.instance().isLoggedIn.get(); - }, -}); - -Template.cloud.events({ - 'click .js-register'() { - modal.open({ - template: 'cloudRegisterManually', - showCancelButton: false, - showConfirmButton: false, - showFooter: false, - closeOnCancel: true, - html: true, - confirmOnEnter: false, - }); - }, - 'click .update-email-btn'() { - const val = $('input[name=cloudEmail]').val(); - - Meteor.call('cloud:updateEmail', val, false, (error) => { - if (error) { - console.warn(error); - return; - } - - toastr.success(t('Saved')); - }); - }, - - 'click .resend-email-btn'() { - const val = $('input[name=cloudEmail]').val(); - - Meteor.call('cloud:updateEmail', val, true, (error) => { - if (error) { - console.warn(error); - return; - } - - toastr.success(t('Requested')); - }); - }, - - 'click .login-btn'(e, i) { - i.oauthAuthorize(); - }, - - 'click .logout-btn'(e, i) { - i.logout(); - }, - - 'click .connect-btn'(e, i) { - const token = $('input[name=cloudToken]').val(); - - i.connectWorkspace(token); - }, - - 'click .register-btn'(e, i) { - i.registerWorkspace(); - }, - - 'click .disconnect-btn'(e, i) { - i.disconnectWorkspace(); - }, - - 'click .sync-btn'(e, i) { - i.syncWorkspace(); - }, -}); - -Template.cloud.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/cloud/client/admin/cloudRegisterManually.css b/app/cloud/client/admin/cloudRegisterManually.css deleted file mode 100644 index 8cd3c5628e34..000000000000 --- a/app/cloud/client/admin/cloudRegisterManually.css +++ /dev/null @@ -1,26 +0,0 @@ -.rc-promtp { - display: flex; - - min-height: 188px; - padding: 1rem; - - border-radius: 2px; - background: #2f343d; - flex-flow: column wrap; - justify-content: space-between; - - &--element, - &--element[disabled] { - flex: 1 1 auto; - - resize: none; - - color: #cbced1; - border: none; - background: none; - - font-family: Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace; - font-size: 14px; - line-height: 20px; - } -} diff --git a/app/cloud/client/admin/cloudRegisterManually.html b/app/cloud/client/admin/cloudRegisterManually.html deleted file mode 100644 index 738a36423501..000000000000 --- a/app/cloud/client/admin/cloudRegisterManually.html +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/app/cloud/client/admin/cloudRegisterManually.js b/app/cloud/client/admin/cloudRegisterManually.js deleted file mode 100644 index 223d9bc609ce..000000000000 --- a/app/cloud/client/admin/cloudRegisterManually.js +++ /dev/null @@ -1,106 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveDict } from 'meteor/reactive-dict'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import Clipboard from 'clipboard'; -import toastr from 'toastr'; - -import { APIClient } from '../../../utils/client'; -import { modal } from '../../../ui-utils/client'; - -import './cloudRegisterManually.html'; -import './cloudRegisterManually.css'; - -const CLOUD_STEPS = { - COPY: 0, - PASTE: 1, - DONE: 2, - ERROR: 3, -}; - -Template.cloudRegisterManually.events({ - 'submit form'(e) { - e.preventDefault(); - }, - 'input .js-cloud-key'(e, instance) { - instance.state.set('cloudKey', e.currentTarget.value); - }, - 'click .js-next'(event, instance) { - instance.state.set('step', CLOUD_STEPS.PASTE); - }, - 'click .js-back'(event, instance) { - instance.state.set('step', CLOUD_STEPS.COPY); - }, - 'click .js-finish'(event, instance) { - instance.state.set('loading', true); - - APIClient - .post('v1/cloud.manualRegister', {}, { cloudBlob: instance.state.get('cloudKey') }) - .then(() => modal.open({ - type: 'success', - title: TAPi18n.__('Success'), - text: TAPi18n.__('Cloud_register_success'), - confirmButtonText: TAPi18n.__('Ok'), - closeOnConfirm: false, - showCancelButton: false, - }, () => window.location.reload())) - .catch(() => modal.open({ - type: 'error', - title: TAPi18n.__('Error'), - text: TAPi18n.__('Cloud_register_error'), - })) - .then(() => instance.state.set('loading', false)); - }, -}); - -Template.cloudRegisterManually.helpers({ - cloudLink() { - return Template.instance().cloudLink.get(); - }, - copyStep() { - return Template.instance().state.get('step') === CLOUD_STEPS.COPY; - }, - clientKey() { - return Template.instance().state.get('clientKey'); - }, - isLoading() { - return Template.instance().state.get('loading'); - }, - step() { - return Template.instance().state.get('step'); - }, - disabled() { - const { state } = Template.instance(); - - const shouldDisable = state.get('cloudKey').trim().length === 0 || state.get('loading'); - - return shouldDisable && 'disabled'; - }, -}); - -Template.cloudRegisterManually.onRendered(function() { - const clipboard = new Clipboard('.js-copy'); - clipboard.on('success', function() { - toastr.success(TAPi18n.__('Copied')); - }); - - const btn = this.find('.cloud-console-btn'); - // After_copy_the_text_go_to_cloud - this.cloudLink.set(TAPi18n.__('Cloud_click_here').replace(/(\[(.*)\]\(\))/ig, (_, __, text) => btn.outerHTML.replace('', `${ text }`))); -}); - -Template.cloudRegisterManually.onCreated(function() { - this.cloudLink = new ReactiveVar(); - this.state = new ReactiveDict({ - step: CLOUD_STEPS.COPY, - loading: false, - clientKey: '', - cloudKey: '', - error: '', - }); - - Meteor.call('cloud:getWorkspaceRegisterData', (error, result) => { - this.state.set('clientKey', result); - }); -}); diff --git a/app/cloud/client/admin/index.js b/app/cloud/client/admin/index.js deleted file mode 100644 index 92cb6032c24e..000000000000 --- a/app/cloud/client/admin/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import './cloud'; -import './callback'; diff --git a/app/cloud/client/index.js b/app/cloud/client/index.js deleted file mode 100644 index ce6ceecd3d5c..000000000000 --- a/app/cloud/client/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import './admin/callback'; -import './admin/cloud'; -import './admin/cloudRegisterManually'; - -import { BlazeLayout } from 'meteor/kadira:blaze-layout'; - -import { registerAdminRoute, registerAdminSidebarItem } from '../../../client/admin'; -import { hasAtLeastOnePermission } from '../../authorization'; - -registerAdminRoute('/cloud', { - name: 'cloud', - async action() { - await import('./admin'); - BlazeLayout.render('main', { center: 'cloud', old: true }); - }, -}); - -registerAdminRoute('/cloud/oauth-callback', { - name: 'cloud-oauth-callback', - async action() { - await import('./admin'); - BlazeLayout.render('main', { center: 'cloudCallback', old: true }); - }, -}); - -registerAdminSidebarItem({ - icon: 'cloud-plus', - href: 'cloud', - i18nLabel: 'Connectivity_Services', - permissionGranted() { - return hasAtLeastOnePermission(['manage-cloud']); - }, -}); diff --git a/app/integrations/client/getIntegration.js b/app/integrations/client/getIntegration.js deleted file mode 100644 index d80c8ee690e5..000000000000 --- a/app/integrations/client/getIntegration.js +++ /dev/null @@ -1,34 +0,0 @@ -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import toastr from 'toastr'; - -import { hasAllPermission } from '../../authorization/client'; -import { APIClient } from '../../utils/client'; - -export async function getIntegration(integrationId, uid) { - if (!integrationId) { - return; - } - - const reqParams = { - integrationId, - }; - - if (!hasAllPermission('manage-outgoing-integrations')) { - if (!hasAllPermission('manage-own-outgoing-integrations')) { - toastr.error(TAPi18n.__('No_integration_found')); - FlowRouter.go('admin-integrations'); - return; - } - reqParams.createdBy = uid; - } - - try { - const { integration } = await APIClient.v1.get('integrations.get', reqParams); - - return integration; - } catch (e) { - toastr.error(TAPi18n.__('Error')); - console.error(e); - } -} diff --git a/app/integrations/client/index.js b/app/integrations/client/index.js deleted file mode 100644 index f7c2445d187d..000000000000 --- a/app/integrations/client/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import '../lib/rocketchat'; -import './startup'; -import './route'; diff --git a/app/integrations/client/route.js b/app/integrations/client/route.js deleted file mode 100644 index 08a7eb444653..000000000000 --- a/app/integrations/client/route.js +++ /dev/null @@ -1,75 +0,0 @@ -import { BlazeLayout } from 'meteor/kadira:blaze-layout'; - -import { registerAdminRoute } from '../../../client/admin'; -import { t } from '../../utils'; - -const dynamic = () => import('./views'); - -registerAdminRoute('/integrations', { - name: 'admin-integrations', - async action() { - await dynamic(); - return BlazeLayout.render('main', { - center: 'integrations', - pageTitle: t('Integrations'), - }); - }, -}); - -registerAdminRoute('/integrations/new', { - name: 'admin-integrations-new', - async action() { - await dynamic(); - return BlazeLayout.render('main', { - center: 'integrationsNew', - pageTitle: t('Integration_New'), - }); - }, -}); - -registerAdminRoute('/integrations/incoming/:id?', { - name: 'admin-integrations-incoming', - async action(params) { - await dynamic(); - return BlazeLayout.render('main', { - center: 'pageSettingsContainer', - pageTitle: t('Integration_Incoming_WebHook'), - pageTemplate: 'integrationsIncoming', - params, - }); - }, -}); - -registerAdminRoute('/integrations/outgoing/:id?', { - name: 'admin-integrations-outgoing', - async action(params) { - await dynamic(); - return BlazeLayout.render('main', { - center: 'integrationsOutgoing', - pageTitle: t('Integration_Outgoing_WebHook'), - params, - }); - }, -}); - -registerAdminRoute('/integrations/outgoing/:id?/history', { - name: 'admin-integrations-outgoing-history', - async action(params) { - await dynamic(); - return BlazeLayout.render('main', { - center: 'integrationsOutgoingHistory', - pageTitle: t('Integration_Outgoing_WebHook_History'), - params, - }); - }, -}); - -registerAdminRoute('/integrations/additional/zapier', { - name: 'admin-integrations-additional-zapier', - async action() { - await dynamic(); - BlazeLayout.render('main', { - center: 'integrationsAdditionalZapier', - }); - }, -}); diff --git a/app/integrations/client/streamer.js b/app/integrations/client/streamer.js deleted file mode 100644 index 6bc2d6dc1327..000000000000 --- a/app/integrations/client/streamer.js +++ /dev/null @@ -1,3 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -export const integrationHistoryStreamer = new Meteor.Streamer('integrationHistory'); diff --git a/app/integrations/client/stylesheets/integrations.css b/app/integrations/client/stylesheets/integrations.css deleted file mode 100644 index 83ee9e64cfe6..000000000000 --- a/app/integrations/client/stylesheets/integrations.css +++ /dev/null @@ -1,75 +0,0 @@ -.admin-integrations-new-panel { - & .admin-integrations-new-item { - display: flex; - - padding: 20px 10px; - - cursor: pointer; - - color: #444444; - border-bottom: 1px solid #dddddd; - align-items: center; - - &:hover { - background-color: #fafafa; - } - - & > i { - color: #aaaaaa; - - font-size: 2rem; - } - - & .admin-integrations-new-item-body { - display: flex; - flex-direction: column; - - padding: 0 20px; - flex-grow: 1; - } - - & .admin-integrations-new-item-title { - font-size: 1.4rem; - font-weight: 500; - line-height: 2.1rem; - } - - & .admin-integrations-new-item-description { - color: #aaaaaa; - - font-size: 1rem; - line-height: 1.5rem; - } - } - - & > a:last-child > .admin-integrations-new-item { - border-bottom: none; - } -} - -.message-example { - & li { - list-style: none; - } -} - -.integrate-other-ways { - & p { - font-size: 1rem; - line-height: 1.5rem; - - & a { - color: #175cc4 !important; - } - } -} - -.content.zapier { - display: flex; - flex-direction: column; - align-items: center; - - #zapier-goes-here { - width: 95%; - } -} diff --git a/app/integrations/client/views/additional/zapier.html b/app/integrations/client/views/additional/zapier.html deleted file mode 100644 index d95f0ac50691..000000000000 --- a/app/integrations/client/views/additional/zapier.html +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/app/integrations/client/views/index.js b/app/integrations/client/views/index.js deleted file mode 100644 index f7c6282cbd35..000000000000 --- a/app/integrations/client/views/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import './integrations.html'; -import './integrations'; -import './integrationsNew.html'; -import './integrationsNew'; -import './integrationsIncoming.html'; -import './integrationsIncoming'; -import './integrationsOutgoing.html'; -import './integrationsOutgoing'; -import './integrationsOutgoingHistory.html'; -import './integrationsOutgoingHistory'; -import './additional/zapier.html'; diff --git a/app/integrations/client/views/integrations.html b/app/integrations/client/views/integrations.html deleted file mode 100644 index 0a39da5ae278..000000000000 --- a/app/integrations/client/views/integrations.html +++ /dev/null @@ -1,74 +0,0 @@ - diff --git a/app/integrations/client/views/integrations.js b/app/integrations/client/views/integrations.js deleted file mode 100644 index 0506b21e1697..000000000000 --- a/app/integrations/client/views/integrations.js +++ /dev/null @@ -1,65 +0,0 @@ -import { Template } from 'meteor/templating'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Tracker } from 'meteor/tracker'; -import moment from 'moment'; -import _ from 'underscore'; - -import { hasAtLeastOnePermission } from '../../../authorization'; -import { integrations } from '../../lib/rocketchat'; -import { SideNav } from '../../../ui-utils/client'; -import { APIClient } from '../../../utils/client'; - -const ITEMS_COUNT = 50; - -Template.integrations.helpers({ - hasPermission() { - return hasAtLeastOnePermission([ - 'manage-outgoing-integrations', - 'manage-own-outgoing-integrations', - 'manage-incoming-integrations', - 'manage-own-incoming-integrations', - ]); - }, - integrations() { - return Template.instance().integrations.get(); - }, - dateFormated(date) { - return moment(date).format('L LT'); - }, - eventTypeI18n(event) { - return TAPi18n.__(integrations.outgoingEvents[event].label); - }, -}); - -Template.integrations.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); - -Template.integrations.onCreated(async function() { - this.integrations = new ReactiveVar([]); - this.offset = new ReactiveVar(0); - this.total = new ReactiveVar(0); - - this.autorun(async () => { - const offset = this.offset.get(); - const { integrations, total } = await APIClient.v1.get(`integrations.list?sort={"type":1}&count=${ ITEMS_COUNT }&offset=${ offset }`); - this.total.set(total); - this.integrations.set(this.integrations.get().concat(integrations)); - }); -}); - -Template.integrations.events({ - 'scroll .content': _.throttle(function(e, instance) { - if (e.target.scrollTop >= (e.target.scrollHeight - e.target.clientHeight)) { - const integrations = instance.integrations.get(); - if (instance.total.get() <= integrations.length) { - return; - } - return instance.offset.set(instance.offset.get() + ITEMS_COUNT); - } - }, 200), -}); diff --git a/app/integrations/client/views/integrationsIncoming.html b/app/integrations/client/views/integrationsIncoming.html deleted file mode 100644 index 7a98d4ac9241..000000000000 --- a/app/integrations/client/views/integrationsIncoming.html +++ /dev/null @@ -1,138 +0,0 @@ - diff --git a/app/integrations/client/views/integrationsIncoming.js b/app/integrations/client/views/integrationsIncoming.js deleted file mode 100644 index 222205d64fa7..000000000000 --- a/app/integrations/client/views/integrationsIncoming.js +++ /dev/null @@ -1,251 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Tracker } from 'meteor/tracker'; -import hljs from 'highlight.js'; -import toastr from 'toastr'; - -import { exampleMsg, exampleSettings, exampleUser } from './messageExample'; -import { hasAtLeastOnePermission } from '../../../authorization'; -import { modal, SideNav } from '../../../ui-utils/client'; -import { t, handleError } from '../../../utils'; -import { getIntegration } from '../getIntegration'; - -Template.integrationsIncoming.onCreated(async function _incomingIntegrationsOnCreated() { - const params = Template.instance().data.params ? Template.instance().data.params() : undefined; - this.integration = new ReactiveVar({}); - this.record = new ReactiveVar({ - username: 'rocket.cat', - }); - if (params && params.id) { - const integration = await getIntegration(params.id, Meteor.userId()); - if (integration) { - this.integration.set(integration); - } - } -}); - -Template.integrationsIncoming.helpers({ - exampleMsg, - exampleUser, - exampleSettings, - hasPermission() { - return hasAtLeastOnePermission([ - 'manage-incoming-integrations', - 'manage-own-incoming-integrations', - ]); - }, - - canDelete() { - return this.params && this.params() && typeof this.params().id !== 'undefined'; - }, - - data() { - const data = Template.instance().integration.get(); - if (data) { - const completeToken = `${ data._id }/${ data.token }`; - data.url = Meteor.absoluteUrl(`hooks/${ completeToken }`); - data.completeToken = completeToken; - data.hasScriptError = data.scriptEnabled && data.scriptError; - Template.instance().record.set(data); - return data; - } - - return Template.instance().record.curValue; - }, - exampleJson() { - const record = Template.instance().record.get(); - const data = { - username: record.alias, - icon_emoji: record.emoji, - icon_url: record.avatar, - text: 'Example message', - attachments: [{ - title: 'Rocket.Chat', - title_link: 'https://rocket.chat', - text: 'Rocket.Chat, the best open source chat', - image_url: '/images/integration-attachment-example.png', - color: '#764FA5', - }], - }; - - const invalidData = [null, '']; - Object.keys(data).forEach((key) => { - if (invalidData.includes(data[key])) { - delete data[key]; - } - }); - - return hljs.highlight('json', JSON.stringify(data, null, 2)).value; - }, - - curl() { - const record = Template.instance().record.get(); - - if (!record.url) { - return; - } - - const data = { - username: record.alias, - icon_emoji: record.emoji, - icon_url: record.avatar, - text: 'Example message', - attachments: [{ - title: 'Rocket.Chat', - title_link: 'https://rocket.chat', - text: 'Rocket.Chat, the best open source chat', - image_url: '/images/integration-attachment-example.png', - color: '#764FA5', - }], - }; - - const invalidData = [null, '']; - Object.keys(data).forEach((key) => { - if (invalidData.includes(data[key])) { - delete data[key]; - } - }); - - return `curl -X POST -H 'Content-Type: application/json' --data '${ JSON.stringify(data) }' ${ record.url }`; - }, - - editorOptions() { - return { - lineNumbers: true, - mode: 'javascript', - gutters: [ - // 'CodeMirror-lint-markers' - 'CodeMirror-linenumbers', - 'CodeMirror-foldgutter', - ], - // lint: true, - foldGutter: true, - // lineWrapping: true, - matchBrackets: true, - autoCloseBrackets: true, - matchTags: true, - showTrailingSpace: true, - highlightSelectionMatches: true, - }; - }, -}); - -Template.integrationsIncoming.events({ - 'blur input': (e, t) => { - const value = t.record.curValue || {}; - - value.name = $('[name=name]').val().trim(); - value.alias = $('[name=alias]').val().trim(); - value.emoji = $('[name=emoji]').val().trim(); - value.avatar = $('[name=avatar]').val().trim(); - value.channel = $('[name=channel]').val().trim(); - value.username = $('[name=username]').val().trim(); - - t.record.set(value); - }, - - 'click .rc-header__section-button > .delete': () => { - const params = Template.instance().data.params(); - - modal.open({ - title: t('Are_you_sure'), - text: t('You_will_not_be_able_to_recover'), - type: 'warning', - showCancelButton: true, - confirmButtonColor: '#DD6B55', - confirmButtonText: t('Yes_delete_it'), - cancelButtonText: t('Cancel'), - closeOnConfirm: false, - html: false, - }, () => { - Meteor.call('deleteIncomingIntegration', params.id, (err) => { - if (err) { - return handleError(err); - } - modal.open({ - title: t('Deleted'), - text: t('Your_entry_has_been_deleted'), - type: 'success', - timer: 1000, - showConfirmButton: false, - }); - - FlowRouter.go('admin-integrations'); - }); - }); - }, - - 'click .button-fullscreen': () => { - const codeMirrorBox = $('.code-mirror-box'); - codeMirrorBox.addClass('code-mirror-box-fullscreen content-background-color'); - codeMirrorBox.find('.CodeMirror')[0].CodeMirror.refresh(); - }, - - 'click .button-restore': () => { - const codeMirrorBox = $('.code-mirror-box'); - codeMirrorBox.removeClass('code-mirror-box-fullscreen content-background-color'); - codeMirrorBox.find('.CodeMirror')[0].CodeMirror.refresh(); - }, - - 'click .rc-header__section-button > .save': () => { - const enabled = $('[name=enabled]:checked').val().trim(); - const name = $('[name=name]').val().trim(); - const alias = $('[name=alias]').val().trim(); - const emoji = $('[name=emoji]').val().trim(); - const avatar = $('[name=avatar]').val().trim(); - const channel = $('[name=channel]').val().trim(); - const username = $('[name=username]').val().trim(); - const scriptEnabled = $('[name=scriptEnabled]:checked').val().trim(); - const script = $('[name=script]').val().trim(); - - if (channel === '') { - return toastr.error(TAPi18n.__('The_channel_name_is_required')); - } - - if (username === '') { - return toastr.error(TAPi18n.__('The_username_is_required')); - } - - const integration = { - enabled: enabled === '1', - channel, - username, - alias: alias !== '' ? alias : undefined, - emoji: emoji !== '' ? emoji : undefined, - avatar: avatar !== '' ? avatar : undefined, - name: name !== '' ? name : undefined, - script: script !== '' ? script : undefined, - scriptEnabled: scriptEnabled === '1', - }; - - const params = Template.instance().data.params ? Template.instance().data.params() : undefined; - if (params && params.id) { - Meteor.call('updateIncomingIntegration', params.id, integration, (err) => { - if (err) { - return handleError(err); - } - - toastr.success(TAPi18n.__('Integration_updated')); - }); - } else { - Meteor.call('addIncomingIntegration', integration, (err, data) => { - if (err) { - return handleError(err); - } - - toastr.success(TAPi18n.__('Integration_added')); - FlowRouter.go('admin-integrations-incoming', { id: data._id }); - }); - } - }, -}); - -Template.integrationsIncoming.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/integrations/client/views/integrationsNew.html b/app/integrations/client/views/integrationsNew.html deleted file mode 100644 index 9c3ab5ee9ec3..000000000000 --- a/app/integrations/client/views/integrationsNew.html +++ /dev/null @@ -1,51 +0,0 @@ - diff --git a/app/integrations/client/views/integrationsNew.js b/app/integrations/client/views/integrationsNew.js deleted file mode 100644 index f5bd29c08e6f..000000000000 --- a/app/integrations/client/views/integrationsNew.js +++ /dev/null @@ -1,35 +0,0 @@ -import { Template } from 'meteor/templating'; -import { Tracker } from 'meteor/tracker'; - -import { hasAtLeastOnePermission } from '../../../authorization'; -import { SideNav } from '../../../ui-utils/client'; - -Template.integrationsNew.helpers({ - hasPermission() { - return hasAtLeastOnePermission([ - 'manage-outgoing-integrations', - 'manage-own-outgoing-integrations', - 'manage-incoming-integrations', - 'manage-own-incoming-integrations', - ]); - }, - canAddIncomingIntegration() { - return hasAtLeastOnePermission([ - 'manage-incoming-integrations', - 'manage-own-incoming-integrations', - ]); - }, - canAddOutgoingIntegration() { - return hasAtLeastOnePermission([ - 'manage-outgoing-integrations', - 'manage-own-outgoing-integrations', - ]); - }, -}); - -Template.integrationsNew.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/integrations/client/views/integrationsOutgoing.html b/app/integrations/client/views/integrationsOutgoing.html deleted file mode 100644 index d9dc03ae209e..000000000000 --- a/app/integrations/client/views/integrationsOutgoing.html +++ /dev/null @@ -1,241 +0,0 @@ - diff --git a/app/integrations/client/views/integrationsOutgoing.js b/app/integrations/client/views/integrationsOutgoing.js deleted file mode 100644 index dba874aca11b..000000000000 --- a/app/integrations/client/views/integrationsOutgoing.js +++ /dev/null @@ -1,353 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Random } from 'meteor/random'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Tracker } from 'meteor/tracker'; -import hljs from 'highlight.js'; -import toastr from 'toastr'; - -import { exampleMsg, exampleSettings, exampleUser } from './messageExample'; -import { hasAtLeastOnePermission } from '../../../authorization'; -import { modal, SideNav } from '../../../ui-utils'; -import { t, handleError } from '../../../utils/client'; -import { integrations } from '../../lib/rocketchat'; -import { getIntegration } from '../getIntegration'; - -Template.integrationsOutgoing.onCreated(async function _integrationsOutgoingOnCreated() { - const params = Template.instance().data.params ? Template.instance().data.params() : undefined; - this.record = new ReactiveVar({ - username: 'rocket.cat', - token: Random.id(24), - retryFailedCalls: true, - retryCount: 6, - retryDelay: 'powers-of-ten', - runOnEdits: true, - }); - - this.updateRecord = () => { - this.record.set({ - enabled: $('[name=enabled]:checked').val().trim() === '1', - event: $('[name=event]').val().trim(), - name: $('[name=name]').val().trim(), - alias: $('[name=alias]').val().trim(), - emoji: $('[name=emoji]').val().trim(), - avatar: $('[name=avatar]').val().trim(), - channel: $('[name=channel]').val() ? $('[name=channel]').val().trim() : undefined, - username: $('[name=username]').val().trim(), - triggerWords: $('[name=triggerWords]').val() ? $('[name=triggerWords]').val().trim() : undefined, - urls: $('[name=urls]').val().trim(), - token: $('[name=token]').val().trim(), - scriptEnabled: $('[name=scriptEnabled]:checked').val().trim() === '1', - script: $('[name=script]').val().trim(), - targetRoom: $('[name=targetRoom]').val() ? $('[name=targetRoom]').val().trim() : undefined, - triggerWordAnywhere: $('[name=triggerWordAnywhere]:checked').val().trim() === '1', - retryFailedCalls: $('[name=retryFailedCalls]:checked').val().trim() === '1', - retryCount: $('[name=retryCount]').val() ? $('[name=retryCount]').val().trim() : 6, - retryDelay: $('[name=retryDelay]').val() ? $('[name=retryDelay]').val().trim() : 'powers-of-ten', - runOnEdits: $('[name=runOnEdits]:checked').val().trim() === '1', - }); - }; - - const integration = await getIntegration(params.id, Meteor.userId()); - if (params.id && !integration) { - toastr.error(TAPi18n.__('No_integration_found')); - FlowRouter.go('admin-integrations'); - return; - } - - integration.hasScriptError = integration.scriptEnabled && integration.scriptError; - this.record.set(integration); -}); - -Template.integrationsOutgoing.helpers({ - exampleMsg, - exampleUser, - exampleSettings, - join(arr, sep) { - if (!arr || !arr.join) { - return arr; - } - - return arr.join(sep); - }, - - showHistoryButton() { - return this.params && this.params() && typeof this.params().id !== 'undefined'; - }, - - hasPermission() { - return hasAtLeastOnePermission([ - 'manage-outgoing-integrations', - 'manage-own-outgoing-integrations', - ]); - }, - - data() { - return Template.instance().record.get(); - }, - - canDelete() { - return this.params && this.params() && typeof this.params().id !== 'undefined'; - }, - - eventTypes() { - return Object.values(integrations.outgoingEvents); - }, - - hasTypeSelected() { - const record = Template.instance().record.get(); - - return typeof record.event === 'string' && record.event !== ''; - }, - - shouldDisplayChannel() { - const record = Template.instance().record.get(); - - return typeof record.event === 'string' && integrations.outgoingEvents[record.event].use.channel; - }, - - shouldDisplayTriggerWords() { - const record = Template.instance().record.get(); - - return typeof record.event === 'string' && integrations.outgoingEvents[record.event].use.triggerWords; - }, - - shouldDisplayTargetRoom() { - const record = Template.instance().record.get(); - - return typeof record.event === 'string' && integrations.outgoingEvents[record.event].use.targetRoom; - }, - - exampleJson() { - const record = Template.instance().record.get(); - const data = { - username: record.alias, - icon_emoji: record.emoji, - icon_url: record.avatar, - text: 'Response text', - attachments: [{ - title: 'Rocket.Chat', - title_link: 'https://rocket.chat', - text: 'Rocket.Chat, the best open source chat', - image_url: '/images/integration-attachment-example.png', - color: '#764FA5', - }], - }; - - const invalidData = [null, '']; - Object.keys(data).forEach((key) => { - if (invalidData.includes(data[key])) { - delete data[key]; - } - }); - - return hljs.highlight('json', JSON.stringify(data, null, 2)).value; - }, - - editorOptions() { - return { - lineNumbers: true, - mode: 'javascript', - gutters: [ - // "CodeMirror-lint-markers", - 'CodeMirror-linenumbers', - 'CodeMirror-foldgutter', - ], - // lint: true, - foldGutter: true, - // lineWrapping: true, - matchBrackets: true, - autoCloseBrackets: true, - matchTags: true, - showTrailingSpace: true, - highlightSelectionMatches: true, - }; - }, -}); - -Template.integrationsOutgoing.events({ - 'blur input': (e, t) => { - t.updateRecord(); - }, - - 'click input[type=radio]': (e, t) => { - t.updateRecord(); - }, - - 'change select[name=event]': (e, t) => { - const record = t.record.get(); - record.event = $('[name=event]').val().trim(); - - t.record.set(record); - }, - - 'click .rc-button.history': () => { - FlowRouter.go(`/admin/integrations/outgoing/${ FlowRouter.getParam('id') }/history`); - }, - - 'click .expand': (e) => { - $(e.currentTarget).closest('.section').removeClass('section-collapsed'); - $(e.currentTarget).closest('button').removeClass('expand').addClass('collapse').find('span').text(TAPi18n.__('Collapse')); - $('.CodeMirror').each((index, codeMirror) => codeMirror.CodeMirror.refresh()); - }, - - 'click .collapse': (e) => { - $(e.currentTarget).closest('.section').addClass('section-collapsed'); - $(e.currentTarget).closest('button').addClass('expand').removeClass('collapse').find('span').text(TAPi18n.__('Expand')); - }, - - 'click .rc-header__section-button > .delete': () => { - const params = Template.instance().data.params(); - - modal.open({ - title: t('Are_you_sure'), - text: t('You_will_not_be_able_to_recover'), - type: 'warning', - showCancelButton: true, - confirmButtonColor: '#DD6B55', - confirmButtonText: t('Yes_delete_it'), - cancelButtonText: t('Cancel'), - closeOnConfirm: false, - html: false, - }, () => { - Meteor.call('deleteOutgoingIntegration', params.id, (err) => { - if (err) { - handleError(err); - } else { - modal.open({ - title: t('Deleted'), - text: t('Your_entry_has_been_deleted'), - type: 'success', - timer: 1000, - showConfirmButton: false, - }); - - FlowRouter.go('admin-integrations'); - } - }); - }); - }, - - 'click .button-fullscreen': () => { - $('.code-mirror-box').addClass('code-mirror-box-fullscreen content-background-color'); - $('.CodeMirror')[0].CodeMirror.refresh(); - }, - - 'click .button-restore': () => { - $('.code-mirror-box').removeClass('code-mirror-box-fullscreen content-background-color'); - $('.CodeMirror')[0].CodeMirror.refresh(); - }, - - 'click .rc-header__section-button > .save': () => { - const event = $('[name=event]').val().trim(); - const enabled = $('[name=enabled]:checked').val().trim(); - const name = $('[name=name]').val().trim(); - const impersonateUser = $('[name=impersonateUser]:checked').val().trim(); - const alias = $('[name=alias]').val().trim(); - const emoji = $('[name=emoji]').val().trim(); - const avatar = $('[name=avatar]').val().trim(); - const username = $('[name=username]').val().trim(); - const token = $('[name=token]').val().trim(); - const scriptEnabled = $('[name=scriptEnabled]:checked').val().trim(); - const script = $('[name=script]').val().trim(); - const retryFailedCalls = $('[name=retryFailedCalls]:checked').val().trim(); - let urls = $('[name=urls]').val().trim(); - - if (username === '' && impersonateUser === '0') { - return toastr.error(TAPi18n.__('The_username_is_required')); - } - - urls = urls.split('\n').filter((url) => url.trim() !== ''); - if (urls.length === 0) { - return toastr.error(TAPi18n.__('You_should_inform_one_url_at_least')); - } - - let triggerWords; - let triggerWordAnywhere; - let runOnEdits; - if (integrations.outgoingEvents[event].use.triggerWords) { - triggerWords = $('[name=triggerWords]').val().trim(); - triggerWords = triggerWords.split(',').filter((word) => word.trim() !== ''); - - triggerWordAnywhere = $('[name=triggerWordAnywhere]:checked').val().trim(); - runOnEdits = $('[name=runOnEdits]:checked').val().trim(); - } - - let channel; - if (integrations.outgoingEvents[event].use.channel) { - channel = $('[name=channel]').val().trim(); - - if (!channel || channel.trim() === '') { - return toastr.error(TAPi18n.__('error-the-field-is-required', { field: TAPi18n.__('Channel') })); - } - } - - let targetRoom; - if (integrations.outgoingEvents[event].use.targetRoom) { - targetRoom = $('[name=targetRoom]').val().trim(); - - if (!targetRoom || targetRoom.trim() === '') { - return toastr.error(TAPi18n.__('error-the-field-is-required', { field: TAPi18n.__('TargetRoom') })); - } - } - - let retryCount; - let retryDelay; - if (retryFailedCalls === '1') { - retryCount = parseInt($('[name=retryCount]').val().trim()); - retryDelay = $('[name=retryDelay]').val().trim(); - } - - const integration = { - event: event !== '' ? event : undefined, - enabled: enabled === '1', - username, - channel: channel !== '' ? channel : undefined, - targetRoom: targetRoom !== '' ? targetRoom : undefined, - alias: alias !== '' ? alias : undefined, - emoji: emoji !== '' ? emoji : undefined, - avatar: avatar !== '' ? avatar : undefined, - name: name !== '' ? name : undefined, - triggerWords: triggerWords !== '' ? triggerWords : undefined, - urls: urls !== '' ? urls : undefined, - token: token !== '' ? token : undefined, - script: script !== '' ? script : undefined, - scriptEnabled: scriptEnabled === '1', - impersonateUser: impersonateUser === '1', - retryFailedCalls: retryFailedCalls === '1', - retryCount: retryCount || 6, - retryDelay: retryDelay || 'powers-of-ten', - triggerWordAnywhere: triggerWordAnywhere === '1', - runOnEdits: runOnEdits === '1', - }; - - const params = Template.instance().data.params ? Template.instance().data.params() : undefined; - if (params && params.id) { - Meteor.call('updateOutgoingIntegration', params.id, integration, (err) => { - if (err) { - return handleError(err); - } - - toastr.success(TAPi18n.__('Integration_updated')); - }); - } else { - Meteor.call('addOutgoingIntegration', integration, (err, data) => { - if (err) { - return handleError(err); - } - - toastr.success(TAPi18n.__('Integration_added')); - FlowRouter.go('admin-integrations-outgoing', { id: data._id }); - }); - } - }, -}); - -Template.integrationsOutgoing.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/integrations/client/views/integrationsOutgoingHistory.html b/app/integrations/client/views/integrationsOutgoingHistory.html deleted file mode 100644 index b453924e1f9d..000000000000 --- a/app/integrations/client/views/integrationsOutgoingHistory.html +++ /dev/null @@ -1,143 +0,0 @@ - diff --git a/app/integrations/client/views/integrationsOutgoingHistory.js b/app/integrations/client/views/integrationsOutgoingHistory.js deleted file mode 100644 index 66384848d6a4..000000000000 --- a/app/integrations/client/views/integrationsOutgoingHistory.js +++ /dev/null @@ -1,191 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Tracker } from 'meteor/tracker'; -import _ from 'underscore'; -import hljs from 'highlight.js'; -import moment from 'moment'; -import toastr from 'toastr'; - -import { handleError } from '../../../utils'; -import { hasAtLeastOnePermission } from '../../../authorization'; -import { integrations } from '../../lib/rocketchat'; -import { SideNav } from '../../../ui-utils/client'; -import { APIClient } from '../../../utils/client'; -import { getIntegration } from '../getIntegration'; -import { integrationHistoryStreamer } from '../streamer'; - -const HISTORY_COUNT = 25; - -Template.integrationsOutgoingHistory.onCreated(async function _integrationsOutgoingHistoryOnCreated() { - const params = Template.instance().data.params ? Template.instance().data.params() : undefined; - this.isLoading = new ReactiveVar(false); - this.history = new ReactiveVar([]); - this.offset = new ReactiveVar(0); - this.total = new ReactiveVar(0); - - if (params && params.id) { - integrationHistoryStreamer.on(params.id, ({ type, id, diff, data }) => { - const histories = this.history.get(); - - if (type === 'inserted') { - this.history.set([{ ...data }].concat(histories)); - return; - } - - if (type === 'updated') { - const history = histories.find(({ _id }) => _id === id); - Object.assign(history, diff); - this.history.set(histories); - return; - } - - if (type === 'removed') { - this.history.set([]); - } - }); - - const integration = await getIntegration(params.id, Meteor.userId()); - - if (!integration) { - toastr.error(TAPi18n.__('No_integration_found')); - return FlowRouter.go('admin-integrations'); - } - this.autorun(async () => { - this.isLoading.set(true); - const { history, total } = await APIClient.v1.get(`integrations.history?id=${ integration._id }&count=${ HISTORY_COUNT }&offset=${ this.offset.get() }`); - this.history.set(this.history.get().concat(history)); - this.total.set(total); - this.isLoading.set(false); - }); - } else { - toastr.error(TAPi18n.__('No_integration_found')); - FlowRouter.go('admin-integrations'); - } -}); - -Template.integrationsOutgoingHistory.helpers({ - hasPermission() { - return hasAtLeastOnePermission(['manage-outgoing-integrations', 'manage-own-outgoing-integrations']); - }, - - isLoading() { - return Template.instance().isLoading.get(); - }, - - histories() { - return Template.instance().history.get().sort((a, b) => { - if (+a._updatedAt < +b._updatedAt) { - return 1; - } - - if (+a._updatedAt > +b._updatedAt) { - return -1; - } - - return 0; - }); - }, - - hasProperty(history, property) { - return typeof history[property] !== 'undefined' || history[property] != null; - }, - - iconClass(history) { - if (typeof history.error !== 'undefined' && history.error) { - return 'icon-cancel-circled error-color'; - } if (history.finished) { - return 'icon-ok-circled success-color'; - } - return 'icon-help-circled'; - }, - - statusI18n(error) { - return typeof error !== 'undefined' && error ? TAPi18n.__('Failure') : TAPi18n.__('Success'); - }, - - formatDate(date) { - return moment(date).format('L LTS'); - }, - - formatDateDetail(date) { - return moment(date).format('L HH:mm:ss:SSSS'); - }, - - eventTypei18n(event) { - return TAPi18n.__(integrations.outgoingEvents[event].label); - }, - - jsonStringify(data) { - if (!data) { - return ''; - } if (typeof data === 'object') { - return hljs.highlight('json', JSON.stringify(data, null, 2)).value; - } - return hljs.highlight('json', data).value; - }, - - integrationId() { - return this.params && this.params() && this.params().id; - }, -}); - -Template.integrationsOutgoingHistory.events({ - 'click .expand': (e) => { - $(e.currentTarget).closest('.section').removeClass('section-collapsed'); - $(e.currentTarget).closest('button').removeClass('expand').addClass('collapse').find('span').text(TAPi18n.__('Collapse')); - $('.CodeMirror').each((index, codeMirror) => codeMirror.CodeMirror.refresh()); - }, - - 'click .collapse': (e) => { - $(e.currentTarget).closest('.section').addClass('section-collapsed'); - $(e.currentTarget).closest('button').addClass('expand').removeClass('collapse').find('span').text(TAPi18n.__('Expand')); - }, - - 'click .replay': (e, t) => { - if (!t || !t.data || !t.data.params || !t.data.params().id) { - return; - } - - const historyId = $(e.currentTarget).attr('data-history-id'); - - Meteor.call('replayOutgoingIntegration', { integrationId: t.data.params().id, historyId }, (e) => { - if (e) { - handleError(e); - } - }); - }, - - 'click .clear-history': (e, t) => { - if (!t || !t.data || !t.data.params || !t.data.params().id) { - return; - } - - Meteor.call('clearIntegrationHistory', t.data.params().id, (e) => { - if (e) { - handleError(e); - return; - } - - toastr.success(TAPi18n.__('Integration_History_Cleared')); - - t.history.set([]); - }); - }, - - 'scroll .content': _.throttle((e, instance) => { - const history = instance.history.get(); - if ((e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight) && instance.total.get() > history.length) { - instance.offset.set(instance.offset.get() + HISTORY_COUNT); - } - }, 200), -}); - -Template.integrationsOutgoingHistory.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/integrations/client/views/messageExample.js b/app/integrations/client/views/messageExample.js deleted file mode 100644 index 2e553dae32b6..000000000000 --- a/app/integrations/client/views/messageExample.js +++ /dev/null @@ -1,39 +0,0 @@ -import { Template } from 'meteor/templating'; -import { Random } from 'meteor/random'; - -export const exampleMsg = () => { - const record = Template.instance().record.get(); - return { - _id: Random.id(), - alias: record.alias, - emoji: record.emoji, - avatar: record.avatar, - msg: 'Example message', - bot: { - i: Random.id(), - }, - groupable: false, - attachments: [{ - title: 'Rocket.Chat', - title_link: 'https://rocket.chat', - text: 'Rocket.Chat, the best open source chat', - image_url: '/images/integration-attachment-example.png', - color: '#764FA5', - }], - ts: new Date(), - u: { - _id: Random.id(), - username: record.username, - }, - }; -}; - -export const exampleUser = () => ({ - u: { - _id: Random.id(), - }, -}); - -export const exampleSettings = () => ({ - settings: {}, -}); diff --git a/app/oauth2-server-config/client/admin/route.js b/app/oauth2-server-config/client/admin/route.js deleted file mode 100644 index c274dbaa6087..000000000000 --- a/app/oauth2-server-config/client/admin/route.js +++ /dev/null @@ -1,28 +0,0 @@ -import { BlazeLayout } from 'meteor/kadira:blaze-layout'; - -import { registerAdminRoute } from '../../../../client/admin'; -import { t } from '../../../utils'; - -registerAdminRoute('/oauth-apps', { - name: 'admin-oauth-apps', - async action() { - await import('./views'); - return BlazeLayout.render('main', { - center: 'oauthApps', - pageTitle: t('OAuth_Applications'), - }); - }, -}); - -registerAdminRoute('/oauth-app/:id?', { - name: 'admin-oauth-app', - async action(params) { - await import('./views'); - return BlazeLayout.render('main', { - center: 'pageSettingsContainer', - pageTitle: t('OAuth_Application'), - pageTemplate: 'oauthApp', - params, - }); - }, -}); diff --git a/app/oauth2-server-config/client/admin/views/index.js b/app/oauth2-server-config/client/admin/views/index.js deleted file mode 100644 index 071605a56b89..000000000000 --- a/app/oauth2-server-config/client/admin/views/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import './oauthApp.html'; -import './oauthApp'; -import './oauthApps.html'; -import './oauthApps'; diff --git a/app/oauth2-server-config/client/admin/views/oauthApp.html b/app/oauth2-server-config/client/admin/views/oauthApp.html deleted file mode 100644 index 360a4ff57c99..000000000000 --- a/app/oauth2-server-config/client/admin/views/oauthApp.html +++ /dev/null @@ -1,72 +0,0 @@ - diff --git a/app/oauth2-server-config/client/admin/views/oauthApp.js b/app/oauth2-server-config/client/admin/views/oauthApp.js deleted file mode 100644 index fa866ba86a81..000000000000 --- a/app/oauth2-server-config/client/admin/views/oauthApp.js +++ /dev/null @@ -1,120 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Tracker } from 'meteor/tracker'; -import toastr from 'toastr'; - -import { hasAllPermission } from '../../../../authorization'; -import { modal, SideNav } from '../../../../ui-utils/client'; -import { t, handleError } from '../../../../utils'; -import { APIClient } from '../../../../utils/client'; - -Template.oauthApp.onCreated(async function() { - const params = this.data.params(); - this.oauthApp = new ReactiveVar({}); - this.record = new ReactiveVar({ - active: true, - }); - if (params && params.id) { - const { oauthApp } = await APIClient.v1.get(`oauth-apps.get?appId=${ params.id }`); - this.oauthApp.set(oauthApp); - } -}); - -Template.oauthApp.helpers({ - hasPermission() { - return hasAllPermission('manage-oauth-apps'); - }, - data() { - const instance = Template.instance(); - if (typeof instance.data.params === 'function') { - const params = instance.data.params(); - if (params && params.id) { - const data = Template.instance().oauthApp.get(); - if (data) { - data.authorization_url = Meteor.absoluteUrl('oauth/authorize'); - data.access_token_url = Meteor.absoluteUrl('oauth/token'); - if (Array.isArray(data.redirectUri)) { - data.redirectUri = data.redirectUri.join('\n'); - } - - Template.instance().record.set(data); - return data; - } - } - } - return Template.instance().record.curValue; - }, -}); - -Template.oauthApp.events({ - 'click .submit > .delete'() { - const params = Template.instance().data.params(); - modal.open({ - title: t('Are_you_sure'), - text: t('You_will_not_be_able_to_recover'), - type: 'warning', - showCancelButton: true, - confirmButtonColor: '#DD6B55', - confirmButtonText: t('Yes_delete_it'), - cancelButtonText: t('Cancel'), - closeOnConfirm: false, - html: false, - }, function() { - Meteor.call('deleteOAuthApp', params.id, function() { - modal.open({ - title: t('Deleted'), - text: t('Your_entry_has_been_deleted'), - type: 'success', - timer: 1000, - showConfirmButton: false, - }); - FlowRouter.go('admin-oauth-apps'); - }); - }); - }, - 'click .submit > .save'() { - const instance = Template.instance(); - const name = $('[name=name]').val().trim(); - const active = $('[name=active]:checked').val().trim() === '1'; - const redirectUri = $('[name=redirectUri]').val().trim(); - if (name === '') { - return toastr.error(TAPi18n.__('The_application_name_is_required')); - } - if (redirectUri === '') { - return toastr.error(TAPi18n.__('The_redirectUri_is_required')); - } - const app = { - name, - active, - redirectUri, - }; - if (typeof instance.data.params === 'function') { - const params = instance.data.params(); - if (params && params.id) { - return Meteor.call('updateOAuthApp', params.id, app, function(err) { - if (err != null) { - return handleError(err); - } - toastr.success(TAPi18n.__('Application_updated')); - }); - } - } - Meteor.call('addOAuthApp', app, function(err, data) { - if (err != null) { - return handleError(err); - } - toastr.success(TAPi18n.__('Application_added')); - FlowRouter.go('admin-oauth-app', { id: data._id }); - }); - }, -}); - -Template.oauthApp.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/oauth2-server-config/client/admin/views/oauthApps.html b/app/oauth2-server-config/client/admin/views/oauthApps.html deleted file mode 100644 index 99a142127802..000000000000 --- a/app/oauth2-server-config/client/admin/views/oauthApps.html +++ /dev/null @@ -1,38 +0,0 @@ - diff --git a/app/oauth2-server-config/client/admin/views/oauthApps.js b/app/oauth2-server-config/client/admin/views/oauthApps.js deleted file mode 100644 index 595af845a769..000000000000 --- a/app/oauth2-server-config/client/admin/views/oauthApps.js +++ /dev/null @@ -1,33 +0,0 @@ -import { Template } from 'meteor/templating'; -import { Tracker } from 'meteor/tracker'; -import { ReactiveVar } from 'meteor/reactive-var'; -import moment from 'moment'; - -import { hasAllPermission } from '../../../../authorization'; -import { SideNav } from '../../../../ui-utils/client'; -import { APIClient } from '../../../../utils/client'; - -Template.oauthApps.onCreated(async function() { - this.oauthApps = new ReactiveVar([]); - const { oauthApps } = await APIClient.v1.get('oauth-apps.list'); - this.oauthApps.set(oauthApps); -}); - -Template.oauthApps.helpers({ - hasPermission() { - return hasAllPermission('manage-oauth-apps'); - }, - applications() { - return Template.instance().oauthApps.get(); - }, - dateFormated(date) { - return moment(date).format('L LT'); - }, -}); - -Template.oauthApps.onRendered(() => { - Tracker.afterFlush(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }); -}); diff --git a/app/oauth2-server-config/client/index.js b/app/oauth2-server-config/client/index.js index 917437a0b53a..5911484bf1c4 100644 --- a/app/oauth2-server-config/client/index.js +++ b/app/oauth2-server-config/client/index.js @@ -1,5 +1,4 @@ import './oauth/oauth2-client.html'; import './oauth/oauth2-client'; import './admin/startup'; -import './admin/route'; import './oauth/stylesheets/oauth2.css'; diff --git a/app/ui/client/components/GenericTable.js b/app/ui/client/components/GenericTable.js index 9d50a456aff5..c3a9d0cf5161 100644 --- a/app/ui/client/components/GenericTable.js +++ b/app/ui/client/components/GenericTable.js @@ -1,4 +1,4 @@ -import React, { useMemo, useState, useEffect, useCallback } from 'react'; +import React, { useMemo, useState, useEffect, useCallback, forwardRef } from 'react'; import { Box, Pagination, Skeleton, Table, Flex, Tile, Scrollable } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; @@ -35,15 +35,15 @@ const LoadingRow = ({ cols }) => )} ; -export function GenericTable({ +export const GenericTable = forwardRef(function GenericTable({ results, total, - renderRow, + renderRow: RenderRow, header, setParams = () => { }, params: paramsDefault = '', FilterComponent = () => null, -}) { +}, ref) { const t = useTranslation(); const [filter, setFilter] = useState(paramsDefault); @@ -65,40 +65,38 @@ export function GenericTable({ const itemsPerPageLabel = useCallback(() => t('Items_per_page:'), []); return <> - <> - - {results && !results.length - ? - {t('No_data_found')} - - : <> - - - - { header && - - {header} - - } - - {results - ? results.map(renderRow) - : } - -
-
-
- - - } - + + {results && !results.length + ? + {t('No_data_found')} + + : <> + + + + { header && + + {header} + + } + + {results + ? results.map((props, index) => ) + : } + +
+
+
+ + + } ; -} +}); diff --git a/app/utils/client/lib/handleError.js b/app/utils/client/lib/handleError.js index 6e2fb92bb2e9..92117a95e216 100644 --- a/app/utils/client/lib/handleError.js +++ b/app/utils/client/lib/handleError.js @@ -22,11 +22,11 @@ export const handleError = function(error, useToastr = true) { } const details = Object.entries(error.details || {}) .reduce((obj, [key, value]) => ({ ...obj, [key]: s.escapeHTML(value) }), {}); - const message = TAPi18n.__(error.error, details); + const message = TAPi18n.__(error.error || error.message, details); const title = details.errorTitle && TAPi18n.__(details.errorTitle); return toastr.error(message, title); } - return s.escapeHTML(TAPi18n.__(error.error, error.details)); + return s.escapeHTML(TAPi18n.__(error.error || error.message, error.details)); }; diff --git a/client/admin/cloud/CloudPage.js b/client/admin/cloud/CloudPage.js new file mode 100644 index 000000000000..e4e285da741a --- /dev/null +++ b/client/admin/cloud/CloudPage.js @@ -0,0 +1,146 @@ +import { Box, Button, ButtonGroup, Margins } from '@rocket.chat/fuselage'; +import { useMutableCallback, useSafely } from '@rocket.chat/fuselage-hooks'; +import React, { useState, useEffect } from 'react'; + +import Page from '../../components/basic/Page'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod } from '../../contexts/ServerContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import { useQueryStringParameter, useRoute, useRouteParameter } from '../../contexts/RouterContext'; +import WhatIsItSection from './WhatIsItSection'; +import ConnectToCloudSection from './ConnectToCloudSection'; +import TroubleshootingSection from './TroubleshootingSection'; +import WorkspaceRegistrationSection from './WorkspaceRegistrationSection'; +import WorkspaceLoginSection from './WorkspaceLoginSection'; +import ManualWorkspaceRegistrationModal from './ManualWorkspaceRegistrationModal'; +import { cloudConsoleUrl } from './constants'; + +function CloudPage() { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const cloudRoute = useRoute('cloud'); + + const page = useRouteParameter('page'); + + const errorCode = useQueryStringParameter('error_code'); + const code = useQueryStringParameter('code'); + const state = useQueryStringParameter('state'); + const token = useQueryStringParameter('token'); + + const finishOAuthAuthorization = useMethod('cloud:finishOAuthAuthorization'); + const checkRegisterStatus = useMethod('cloud:checkRegisterStatus'); + const connectWorkspace = useMethod('cloud:connectWorkspace'); + + useEffect(() => { + const acceptOAuthAuthorization = async () => { + if (page !== 'oauth-callback') { + return; + } + + if (errorCode) { + dispatchToastMessage({ + type: 'error', + title: t('Cloud_error_in_authenticating'), + message: t('Cloud_error_code', { errorCode }), + }); + cloudRoute.push(); + return; + } + + try { + await finishOAuthAuthorization(code, state); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + cloudRoute.push(); + } + }; + + acceptOAuthAuthorization(); + }, [errorCode, code, state]); + + const [registerStatus, setRegisterStatus] = useSafely(useState()); + const [modal, setModal] = useState(null); + + const fetchRegisterStatus = useMutableCallback(async () => { + try { + const registerStatus = await checkRegisterStatus(); + setRegisterStatus(registerStatus); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + }); + + useEffect(() => { + const acceptWorkspaceToken = async () => { + try { + if (token) { + const isConnected = await connectWorkspace(token); + + if (!isConnected) { + throw Error(t('An error occured connecting')); + } + + dispatchToastMessage({ type: 'success', message: t('Connected') }); + } + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + await fetchRegisterStatus(); + } + }; + + acceptWorkspaceToken(); + }, [token]); + + const handleManualWorkspaceRegistrationButtonClick = () => { + const handleModalClose = () => { + setModal(null); + fetchRegisterStatus(); + }; + setModal(); + }; + + const isConnectedToCloud = registerStatus?.connectToCloud; + const isWorkspaceRegistered = registerStatus?.workspaceRegistered; + + return + + + {!isWorkspaceRegistered && } + + + + + {modal} + + + + + {isConnectedToCloud && <> + {isWorkspaceRegistered + ? + : } + + + } + + {!isConnectedToCloud && } + + + + ; +} + +export default CloudPage; diff --git a/client/admin/cloud/CloudRoute.js b/client/admin/cloud/CloudRoute.js new file mode 100644 index 000000000000..53c71affae7f --- /dev/null +++ b/client/admin/cloud/CloudRoute.js @@ -0,0 +1,17 @@ +import React from 'react'; + +import { usePermission } from '../../contexts/AuthorizationContext'; +import NotAuthorizedPage from '../NotAuthorizedPage'; +import CloudPage from './CloudPage'; + +function CloudRoute() { + const canManageCloud = usePermission('manage-cloud'); + + if (!canManageCloud) { + return ; + } + + return ; +} + +export default CloudRoute; diff --git a/client/admin/cloud/ConnectToCloudSection.js b/client/admin/cloud/ConnectToCloudSection.js new file mode 100644 index 000000000000..2b1009d35ccc --- /dev/null +++ b/client/admin/cloud/ConnectToCloudSection.js @@ -0,0 +1,61 @@ +import { Box, Button, ButtonGroup, Throbber } from '@rocket.chat/fuselage'; +import { useSafely } from '@rocket.chat/fuselage-hooks'; +import React, { useState } from 'react'; + +import Subtitle from '../../components/basic/Subtitle'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod } from '../../contexts/ServerContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; + +function ConnectToCloudSection({ + onRegisterStatusChange, + ...props +}) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const [isConnecting, setConnecting] = useSafely(useState(false)); + + const registerWorkspace = useMethod('cloud:registerWorkspace'); + const syncWorkspace = useMethod('cloud:syncWorkspace'); + + const handleRegisterButtonClick = async () => { + setConnecting(true); + + try { + const isRegistered = await registerWorkspace(); + + if (!isRegistered) { + throw Error(t('An error occured')); + } + + // TODO: sync on register? + const isSynced = await syncWorkspace(); + + if (!isSynced) { + throw Error(t('An error occured syncing')); + } + + dispatchToastMessage({ type: 'success', message: t('Sync Complete') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + await (onRegisterStatusChange && onRegisterStatusChange()); + setConnecting(false); + } + }; + + return + {t('Cloud_registration_required')} + +

{t('Cloud_registration_required_description')}

+
+ + + +
; +} + +export default ConnectToCloudSection; diff --git a/client/admin/cloud/ManualWorkspaceRegistrationModal.js b/client/admin/cloud/ManualWorkspaceRegistrationModal.js new file mode 100644 index 000000000000..7952a3aa7053 --- /dev/null +++ b/client/admin/cloud/ManualWorkspaceRegistrationModal.js @@ -0,0 +1,183 @@ +import { Box, Button, ButtonGroup, Icon, Scrollable, Throbber } from '@rocket.chat/fuselage'; +import Clipboard from 'clipboard'; +import React, { useEffect, useState, useRef } from 'react'; + +import { Modal } from '../../components/basic/Modal'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod, useEndpoint } from '../../contexts/ServerContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import MarkdownText from '../../components/basic/MarkdownText'; +import { cloudConsoleUrl } from './constants'; + +function CopyStep({ onNextButtonClick }) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const [clientKey, setClientKey] = useState(''); + + const getWorkspaceRegisterData = useMethod('cloud:getWorkspaceRegisterData'); + + useEffect(() => { + const loadWorkspaceRegisterData = async () => { + const clientKey = await getWorkspaceRegisterData(); + setClientKey(clientKey); + }; + + loadWorkspaceRegisterData(); + }, []); + + const copyRef = useRef(); + + useEffect(function() { + const clipboard = new Clipboard(copyRef.current); + clipboard.on('success', () => { + dispatchToastMessage({ type: 'success', message: t('Copied') }); + }); + + return () => { + clipboard.destroy(); + }; + }, []); + + return <> + + +

{t('Cloud_register_offline_helper')}

+
+ + + + {clientKey} + + + + + +

+ {t('Cloud_click_here', { cloudConsoleUrl })} +

+
+
+ + + + + + ; +} + +function PasteStep({ onBackButtonClick, onFinish }) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const [isLoading, setLoading] = useState(false); + const [cloudKey, setCloudKey] = useState(''); + + const handleCloudKeyChange = (e) => { + setCloudKey(e.currentTarget.value); + }; + + const registerManually = useEndpoint('POST', 'cloud.manualRegister'); + + const handleFinishButtonClick = async () => { + setLoading(true); + + try { + await registerManually({}, { cloudBlob: cloudKey }); + dispatchToastMessage({ type: 'success', message: t('Cloud_register_success') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: t('Cloud_register_error') }); + } finally { + setLoading(false); + onFinish && onFinish(); + } + }; + + return <> + + +

{t('Cloud_register_offline_finish_helper')}

+
+ + + + + +
+ + + + + + + ; +} + +const Steps = { + COPY: 'copy', + PASTE: 'paste', +}; + +function ManualWorkspaceRegistrationModal({ onClose, props }) { + const t = useTranslation(); + + const [step, setStep] = useState(Steps.COPY); + + const handleNextButtonClick = () => { + setStep(Steps.PASTE); + }; + + const handleBackButtonClick = () => { + setStep(Steps.COPY); + }; + + return + + {t('Cloud_Register_manually')} + + + {(step === Steps.COPY && ) + || (step === Steps.PASTE && )} + ; +} + +export default ManualWorkspaceRegistrationModal; diff --git a/client/admin/cloud/TroubleshootingSection.js b/client/admin/cloud/TroubleshootingSection.js new file mode 100644 index 000000000000..4d1c8e7238d7 --- /dev/null +++ b/client/admin/cloud/TroubleshootingSection.js @@ -0,0 +1,63 @@ +import { Box, Button, ButtonGroup, Throbber } from '@rocket.chat/fuselage'; +import { useSafely } from '@rocket.chat/fuselage-hooks'; +import React, { useState } from 'react'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import Subtitle from '../../components/basic/Subtitle'; +import { useMethod } from '../../contexts/ServerContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import { statusPageUrl } from './constants'; + +function TroubleshootingSection({ + onRegisterStatusChange, + ...props +}) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const [isSyncing, setSyncing] = useSafely(useState(false)); + + const syncWorkspace = useMethod('cloud:syncWorkspace'); + + const handleSyncButtonClick = async () => { + setSyncing(true); + + try { + const isSynced = await syncWorkspace(); + + if (!isSynced) { + throw Error(t('An error occured syncing')); + } + + dispatchToastMessage({ type: 'success', message: t('Sync Complete') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + await (onRegisterStatusChange && onRegisterStatusChange()); + setSyncing(false); + } + }; + + return + {t('Cloud_troubleshooting')} + + +

{t('Cloud_workspace_support')}

+
+ + + + + + +

+ {t('Cloud_status_page_description')}:{' '} + {statusPageUrl} +

+
+
; +} + +export default TroubleshootingSection; diff --git a/client/admin/cloud/WhatIsItSection.js b/client/admin/cloud/WhatIsItSection.js new file mode 100644 index 000000000000..3bafb0e65f57 --- /dev/null +++ b/client/admin/cloud/WhatIsItSection.js @@ -0,0 +1,32 @@ +import { Box } from '@rocket.chat/fuselage'; +import React from 'react'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import Subtitle from '../../components/basic/Subtitle'; + +function WhatIsItSection(props) { + const t = useTranslation(); + + return + {t('Cloud_what_is_it')} + + +

{t('Cloud_what_is_it_description')}

+ +
+

{t('Cloud_what_is_it_services_like')}

+ +
    +
  • {t('Register_Server_Registered_Push_Notifications')}
  • +
  • {t('Register_Server_Registered_Livechat')}
  • +
  • {t('Register_Server_Registered_OAuth')}
  • +
  • {t('Register_Server_Registered_Marketplace')}
  • +
+ +

{t('Cloud_what_is_it_additional')}

+
+
+
; +} + +export default WhatIsItSection; diff --git a/client/admin/cloud/WorkspaceLoginSection.js b/client/admin/cloud/WorkspaceLoginSection.js new file mode 100644 index 000000000000..7e2bad6cb0dd --- /dev/null +++ b/client/admin/cloud/WorkspaceLoginSection.js @@ -0,0 +1,108 @@ +import { Box, Button, ButtonGroup } from '@rocket.chat/fuselage'; +import { useSafely } from '@rocket.chat/fuselage-hooks'; +import React, { useState, useEffect } from 'react'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod } from '../../contexts/ServerContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; + +function WorkspaceLoginSection({ + onRegisterStatusChange, + ...props +}) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const checkUserLoggedIn = useMethod('cloud:checkUserLoggedIn'); + const getOAuthAuthorizationUrl = useMethod('cloud:getOAuthAuthorizationUrl'); + const logout = useMethod('cloud:logout'); + const disconnectWorkspace = useMethod('cloud:disconnectWorkspace'); + + const [isLoggedIn, setLoggedIn] = useSafely(useState(false)); + const [isLoading, setLoading] = useSafely(useState(true)); + + const handleLoginButtonClick = async () => { + setLoading(true); + + try { + const url = await getOAuthAuthorizationUrl(); + window.location.href = url; + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + setLoading(false); + } + }; + + const handleLogoutButtonClick = async () => { + setLoading(true); + + try { + await logout(); + const isLoggedIn = await checkUserLoggedIn(); + setLoggedIn(isLoggedIn); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + setLoading(false); + } + }; + + const handleDisconnectButtonClick = async () => { + setLoading(true); + + try { + const success = await disconnectWorkspace(); + + if (!success) { + throw Error(t('An error occured disconnecting')); + } + + dispatchToastMessage({ type: 'success', message: t('Disconnected') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + await (onRegisterStatusChange && onRegisterStatusChange()); + setLoading(false); + } + }; + + useEffect(() => { + const checkLoginState = async () => { + setLoading(true); + + try { + const isLoggedIn = await checkUserLoggedIn(); + setLoggedIn(isLoggedIn); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + setLoading(false); + } + }; + + checkLoginState(); + }, []); + + return + +

{t('Cloud_workspace_connected')}

+
+ + + {isLoggedIn + ? + : } + + + +

{t('Cloud_workspace_disconnect')}

+
+ + + + +
; +} + +export default WorkspaceLoginSection; diff --git a/client/admin/cloud/WorkspaceRegistrationSection.js b/client/admin/cloud/WorkspaceRegistrationSection.js new file mode 100644 index 000000000000..8f2884afa63a --- /dev/null +++ b/client/admin/cloud/WorkspaceRegistrationSection.js @@ -0,0 +1,128 @@ +import { Box, Button, ButtonGroup, EmailInput, Field, Margins, TextInput } from '@rocket.chat/fuselage'; +import { useSafely, useUniqueId } from '@rocket.chat/fuselage-hooks'; +import React, { useState, useMemo } from 'react'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import { useMethod } from '../../contexts/ServerContext'; +import { supportEmailAddress } from './constants'; + +function WorkspaceRegistrationSection({ + email: initialEmail, + token: initialToken, + workspaceId, + uniqueId, + onRegisterStatusChange, + ...props +}) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const updateEmail = useMethod('cloud:updateEmail'); + const connectWorkspace = useMethod('cloud:connectWorkspace'); + + const [isProcessing, setProcessing] = useSafely(useState(false)); + const [email, setEmail] = useState(initialEmail); + const [token, setToken] = useState(initialToken); + + const supportMailtoUrl = useMemo(() => { + const subject = encodeURIComponent('Self Hosted Registration'); + const body = encodeURIComponent([ + `WorkspaceId: ${ workspaceId }`, + `Deployment Id: ${ uniqueId }`, + 'Issue: ', + ].join('\r\n')); + return `mailto:${ supportEmailAddress }?subject=${ subject }&body=${ body }`; + }, [workspaceId, uniqueId]); + + const handleEmailChange = ({ currentTarget: { value } }) => { + setEmail(value); + }; + + const handleTokenChange = ({ currentTarget: { value } }) => { + setToken(value); + }; + + const handleUpdateEmailButtonClick = async () => { + setProcessing(true); + + try { + await updateEmail(email, false); + dispatchToastMessage({ type: 'success', message: t('Saved') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + setProcessing(false); + } + }; + + const handleResendEmailButtonClick = async () => { + setProcessing(true); + + try { + await updateEmail(email, true); + dispatchToastMessage({ type: 'success', message: t('Requested') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + setProcessing(false); + } + }; + + const handleConnectButtonClick = async () => { + setProcessing(true); + + try { + const isConnected = await connectWorkspace(token); + + if (!isConnected) { + throw Error(t('An error occured connecting')); + } + + dispatchToastMessage({ type: 'success', message: t('Connected') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } finally { + await (onRegisterStatusChange && onRegisterStatusChange()); + setProcessing(false); + } + }; + + const emailInputId = useUniqueId(); + const tokenInputId = useUniqueId(); + + return + + + {t('Email')} + + + + {t('Cloud_address_to_send_registration_to')} + + + + + + + + + {t('Token')} + + + + {t('Cloud_manually_input_token')} + + + + + + + +

{t('Cloud_connect_support')}: {supportEmailAddress}

+
+
+
; +} + +export default WorkspaceRegistrationSection; diff --git a/client/admin/cloud/constants.js b/client/admin/cloud/constants.js new file mode 100644 index 000000000000..c5ed79a1477e --- /dev/null +++ b/client/admin/cloud/constants.js @@ -0,0 +1,3 @@ +export const cloudConsoleUrl = 'https://cloud.rocket.chat'; +export const supportEmailAddress = 'support@rocket.chat'; +export const statusPageUrl = 'https://status.rocket.chat'; diff --git a/client/admin/customSounds/EditSound.js b/client/admin/customSounds/EditSound.js new file mode 100644 index 000000000000..0496a617fb0e --- /dev/null +++ b/client/admin/customSounds/EditSound.js @@ -0,0 +1,202 @@ +import React, { useCallback, useState, useMemo, useEffect } from 'react'; +import { Box, Button, ButtonGroup, Margins, TextInput, Field, Icon, Skeleton, Throbber, InputBox } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod } from '../../contexts/ServerContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import { Modal } from '../../components/basic/Modal'; +import { useFileInput } from '../../hooks/useFileInput'; +import { useEndpointDataExperimental, ENDPOINT_STATES } from '../../hooks/useEndpointDataExperimental'; +import { validate, createSoundData } from './lib'; + +const DeleteWarningModal = ({ onDelete, onCancel, ...props }) => { + const t = useTranslation(); + return + + + {t('Are_you_sure')} + + + + {t('Custom_Sound_Status_Delete_Warning')} + + + + + + + + ; +}; + +const SuccessModal = ({ onClose, ...props }) => { + const t = useTranslation(); + return + + + {t('Deleted')} + + + + {t('Custom_Sound_Has_Been_Deleted')} + + + + + + + ; +}; + +export function EditSound({ _id, cache, ...props }) { + const t = useTranslation(); + const query = useMemo(() => ({ + query: JSON.stringify({ _id }), + }), [_id]); + + const { data, state, error } = useEndpointDataExperimental('custom-sounds.list', query); + + + if (state === ENDPOINT_STATES.LOADING) { + return + + + + + + + + + + + + ; + } + + if (error || !data || data.sounds.length < 1) { + return {t('Custom_User_Status_Error_Invalid_User_Status')}; + } + + return ; +} + +export function EditCustomSound({ close, onChange, data, ...props }) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const { _id, name: previousName } = data || {}; + const previousSound = data || {}; + + const [name, setName] = useState(''); + const [sound, setSound] = useState(); + const [modal, setModal] = useState(); + + useEffect(() => { + setName(previousName || ''); + setSound(previousSound || ''); + }, [previousName, previousSound, _id]); + + const deleteCustomSound = useMethod('deleteCustomSound'); + const uploadCustomSound = useMethod('uploadCustomSound'); + const insertOrUpdateSound = useMethod('insertOrUpdateSound'); + + const handleChangeFile = (soundFile) => { + setSound(soundFile); + }; + + const hasUnsavedChanges = useMemo(() => previousName !== name || previousSound !== sound, [name, sound]); + + const saveAction = async (sound) => { + const soundData = createSoundData(sound, name, { previousName, previousSound, _id }); + const validation = validate(soundData, sound); + if (validation.length === 0) { + let soundId; + try { + soundId = await insertOrUpdateSound(soundData); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + + soundData._id = soundId; + soundData.random = Math.round(Math.random() * 1000); + + if (sound && sound !== previousSound) { + dispatchToastMessage({ type: 'success', message: t('Uploading_file') }); + + const reader = new FileReader(); + reader.readAsBinaryString(sound); + reader.onloadend = () => { + try { + uploadCustomSound(reader.result, sound.type, soundData); + return dispatchToastMessage({ type: 'success', message: t('File_uploaded') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + }; + } + } + + validation.forEach((error) => dispatchToastMessage({ type: 'error', message: t('error-the-field-is-required', { field: t(error) }) })); + }; + + const handleSave = useCallback(async () => { + saveAction(sound); + onChange(); + }, [name, _id, sound]); + + const onDeleteConfirm = useCallback(async () => { + try { + await deleteCustomSound(_id); + setModal(() => { setModal(undefined); close(); onChange(); }}/>); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + onChange(); + } + }, [_id]); + + const openConfirmDelete = () => setModal(() => setModal(undefined)}/>); + + + const clickUpload = useFileInput(handleChangeFile, 'audio/mp3'); + + + return <> + + + + {t('Name')} + + setName(e.currentTarget.value)} placeholder={t('Name')} /> + + + + + {t('Sound_File_mp3')} + + + + {(sound && sound.name) || 'none'} + + + + + + + + + + + + + + + + + + + + + + { modal } + ; +} diff --git a/client/admin/customSounds/NewSound.js b/client/admin/customSounds/NewSound.js new file mode 100644 index 000000000000..b77671f1b07a --- /dev/null +++ b/client/admin/customSounds/NewSound.js @@ -0,0 +1,101 @@ +import React, { useState, useCallback } from 'react'; +import { Field, TextInput, Box, Icon, Margins, Button, ButtonGroup } from '@rocket.chat/fuselage'; + +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod } from '../../contexts/ServerContext'; +import { useFileInput } from '../../hooks/useFileInput'; +import { validate, createSoundData } from './lib'; + +export function NewSound({ goToNew, close, onChange, ...props }) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const [name, setName] = useState(''); + const [sound, setSound] = useState(); + + const uploadCustomSound = useMethod('uploadCustomSound'); + + const insertOrUpdateSound = useMethod('insertOrUpdateSound'); + + const handleChangeFile = (soundFile) => { + setSound(soundFile); + }; + + const clickUpload = useFileInput(handleChangeFile, 'audio/mp3'); + + const saveAction = async (name, soundFile) => { + const soundData = createSoundData(soundFile, name); + const validation = validate(soundData, sound); + if (validation.length === 0) { + let soundId; + try { + soundId = await insertOrUpdateSound(soundData); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + + soundData._id = soundId; + soundData.random = Math.round(Math.random() * 1000); + + if (soundId) { + dispatchToastMessage({ type: 'success', message: t('Uploading_file') }); + + const reader = new FileReader(); + reader.readAsBinaryString(soundFile); + reader.onloadend = () => { + try { + uploadCustomSound(reader.result, soundFile.type, soundData); + dispatchToastMessage({ type: 'success', message: t('File_uploaded') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + }; + } + return soundId; + } + validation.forEach((error) => { throw new Error({ type: 'error', message: t('error-the-field-is-required', { field: t(error) }) }); }); + }; + + const handleSave = useCallback(async () => { + try { + const result = await saveAction( + name, + sound, + ); + dispatchToastMessage({ type: 'success', message: t('Custom_Sound_Updated_Successfully') }); + goToNew(result)(); + onChange(); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + }, [name, sound]); + + return + + + {t('Name')} + + setName(e.currentTarget.value)} placeholder={t('Name')} /> + + + + {t('Sound_File_mp3')} + + + + {(sound && sound.name) || 'none'} + + + + + + + + + + + + + ; +} diff --git a/client/admin/integrations/IncomingWebhookForm.js b/client/admin/integrations/IncomingWebhookForm.js new file mode 100644 index 000000000000..f25ba8b304f0 --- /dev/null +++ b/client/admin/integrations/IncomingWebhookForm.js @@ -0,0 +1,165 @@ +import React, { useMemo } from 'react'; +import { Field, TextInput, Box, ToggleSwitch, Icon, TextAreaInput, FieldGroup, Margins } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import { useAbsoluteUrl } from '../../contexts/ServerContext'; +import { useHilightCode } from '../../hooks/useHilightCode'; +import { useExampleData } from './exampleIncomingData'; +import Page from '../../components/basic/Page'; + +export default function IncomingWebhookForm({ formValues, formHandlers, extraData = {}, append, ...props }) { + const t = useTranslation(); + + const hilightCode = useHilightCode(); + + const absoluteUrl = useAbsoluteUrl(); + + const { + enabled, + channel, + username, + name, + alias, + avatarUrl, + emoji, + scriptEnabled, + script, + } = formValues; + + const { + handleEnabled, + handleChannel, + handleUsername, + handleName, + handleAlias, + handleAvatarUrl, + handleEmoji, + handleScriptEnabled, + handleScript, + } = formHandlers; + + const url = absoluteUrl(`hooks/${ extraData._id }/${ extraData.token }`); + + const [exampleData, curlData] = useExampleData({ + aditionalFields: { + ...alias && { alias }, + ...emoji && { emoji }, + ...avatarUrl && { avatar: avatarUrl }, + }, + url, + }, [alias, emoji, avatarUrl]); + + const hilightedExampleJson = hilightCode('json', JSON.stringify(exampleData, null, 2)); + + return + + + {useMemo(() => + + {t('Enabled')} + + + , [enabled, handleEnabled])} + {useMemo(() => + {t('Name_optional')} + + + + {t('You_should_name_it_to_easily_manage_your_integrations')} + , [name, handleName])} + {useMemo(() => + {t('Post_to_Channel')} + + }/> + + {t('Messages_that_are_sent_to_the_Incoming_WebHook_will_be_posted_here')} + + , [channel, handleChannel])} + {useMemo(() => + {t('Post_as')} + + }/> + + {t('Choose_the_username_that_this_integration_will_post_as')} + {t('Should_exists_a_user_with_this_username')} + , [username, handleUsername])} + {useMemo(() => + {`${ t('Alias') } (${ t('optional') })`} + + }/> + + {t('Choose_the_alias_that_will_appear_before_the_username_in_messages')} + , [alias, handleAlias])} + {useMemo(() => + {`${ t('Avatar_URL') } (${ t('optional') })`} + + }/> + + {t('You_can_change_a_different_avatar_too')} + {t('Should_be_a_URL_of_an_image')} + , [avatarUrl, handleAvatarUrl])} + {useMemo(() => + {`${ t('Emoji') } (${ t('optional') })`} + + }/> + + {t('You_can_use_an_emoji_as_avatar')} + + , [emoji, handleEmoji])} + {useMemo(() => + + {t('Script_Enabled')} + + + , [scriptEnabled, handleScriptEnabled])} + {useMemo(() => + {t('Script')} + + }/> + + , [script, handleScript])} + {useMemo(() => !extraData._id && <> + {t('Webhook_URL')} + + } disabled/> + + {t('Send_your_JSON_payloads_to_this_URL')} + + + {t('Token')} + + } disabled/> + + , [extraData._id])} + {useMemo(() => extraData._id && <> + {t('Webhook_URL')} + + }/> + + {t('Send_your_JSON_payloads_to_this_URL')} + + + {t('Token')} + + }/> + + , [url, extraData._id, extraData.token])} + {useMemo(() => + {t('Example_payload')} + + +
+
+
+
, [hilightedExampleJson])} + {useMemo(() => extraData._id && + {t('Curl')} + + }/> + + , [curlData])} + { append } +
+
+
; +} diff --git a/client/admin/integrations/IntegrationsPage.js b/client/admin/integrations/IntegrationsPage.js new file mode 100644 index 000000000000..ec9dc1adb688 --- /dev/null +++ b/client/admin/integrations/IntegrationsPage.js @@ -0,0 +1,56 @@ +import { Button, ButtonGroup, Icon, Tabs } from '@rocket.chat/fuselage'; +import React, { useEffect, useCallback } from 'react'; + +import Page from '../../components/basic/Page'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useRoute, useRouteParameter } from '../../contexts/RouterContext'; +import IntegrationsTable from './IntegrationsTable'; +import NewZapier from './new/NewZapier'; +import NewBot from './new/NewBot'; + +function IntegrationsPage() { + const t = useTranslation(); + + const router = useRoute('admin-integrations'); + + const handleNewButtonClick = useCallback(() => { + router.push({ context: 'new', type: 'incoming' }); + }, []); + + const context = useRouteParameter('context'); + useEffect(() => { + if (!context) { + router.push({ context: 'webhook-incoming' }); + } + }, [context]); + + const showTable = !['zapier', 'bots'].includes(context); + + const goToIncoming = useCallback(() => router.push({ context: 'webhook-incoming' }), []); + const goToOutgoing = useCallback(() => router.push({ context: 'webhook-outgoing' }), []); + const goToZapier = useCallback(() => router.push({ context: 'zapier' }), []); + const goToBots = useCallback(() => router.push({ context: 'bots' }), []); + + return + + + + + + + {t('Incoming')} + {t('Outgoing')} + {t('Zapier')} + {t('Bots')} + + + {context === 'zapier' && } + {context === 'bots' && } + {showTable && } + + ; +} + +export default IntegrationsPage; diff --git a/client/admin/integrations/IntegrationsRoute.js b/client/admin/integrations/IntegrationsRoute.js new file mode 100644 index 000000000000..e1af75ed11e0 --- /dev/null +++ b/client/admin/integrations/IntegrationsRoute.js @@ -0,0 +1,40 @@ +import React from 'react'; + +import { useAtLeastOnePermission } from '../../contexts/AuthorizationContext'; +import { useRouteParameter } from '../../contexts/RouterContext'; +import NotAuthorizedPage from '../NotAuthorizedPage'; +import IntegrationsPage from './IntegrationsPage'; +import NewIntegrationsPage from './new/NewIntegrationsPage'; +import EditIntegrationsPage from './edit/EditIntegrationsPage'; +import OutgoingWebhookHistoryPage from './edit/OutgoingWebhookHistoryPage'; + +function IntegrationsRoute() { + const canViewIntegrationsPage = useAtLeastOnePermission([ + 'manage-incoming-integrations', + 'manage-outgoing-integrations', + 'manage-own-incoming-integrations', + 'manage-own-outgoing-integrations', + ]); + + const context = useRouteParameter('context'); + + if (!canViewIntegrationsPage) { + return ; + } + + if (context === 'new') { + return ; + } + + if (context === 'edit') { + return ; + } + + if (context === 'history') { + return ; + } + + return ; +} + +export default IntegrationsRoute; diff --git a/client/admin/integrations/IntegrationsTable.js b/client/admin/integrations/IntegrationsTable.js new file mode 100644 index 000000000000..582485154019 --- /dev/null +++ b/client/admin/integrations/IntegrationsTable.js @@ -0,0 +1,97 @@ +import { Box, Table, TextInput, Icon } from '@rocket.chat/fuselage'; +import { useDebouncedValue, useResizeObserver } from '@rocket.chat/fuselage-hooks'; +import React, { useMemo, useCallback, useState, useEffect } from 'react'; + +import { GenericTable, Th } from '../../../app/ui/client/components/GenericTable'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useRoute } from '../../contexts/RouterContext'; +import { useEndpointDataExperimental } from '../../hooks/useEndpointDataExperimental'; +import { useFormatDateAndTime } from '../../hooks/useFormatDateAndTime'; + +const style = { whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }; + +const FilterByTypeAndText = React.memo(({ setFilter, ...props }) => { + const t = useTranslation(); + + const [text, setText] = useState(''); + + const handleChange = useCallback((event) => setText(event.currentTarget.value), []); + + useEffect(() => { + setFilter({ text }); + }, [text]); + + return + } onChange={handleChange} value={text} /> + ; +}); + +const useQuery = (params, sort) => useMemo(() => ({ + query: JSON.stringify({ name: { $regex: params.text || '', $options: 'i' }, type: params.type }), + sort: JSON.stringify({ [sort[0]]: sort[1] === 'asc' ? 1 : -1 }), + ...params.itemsPerPage && { count: params.itemsPerPage }, + ...params.current && { offset: params.current }, +}), [JSON.stringify(params), JSON.stringify(sort)]); + +const useResizeInlineBreakpoint = (sizes = [], debounceDelay = 0) => { + const { ref, borderBoxSize } = useResizeObserver({ debounceDelay }); + const inlineSize = borderBoxSize ? borderBoxSize.inlineSize : 0; + sizes = useMemo(() => sizes.map((current) => (inlineSize ? inlineSize > current : true)), [inlineSize]); + return [ref, ...sizes]; +}; + +export function IntegrationsTable({ type }) { + const t = useTranslation(); + const formatDateAndTime = useFormatDateAndTime(); + const [ref, isBig] = useResizeInlineBreakpoint([700], 200); + + const [params, setParams] = useState({ text: '', current: 0, itemsPerPage: 25 }); + const [sort, setSort] = useState(['name', 'asc']); + + const debouncedText = useDebouncedValue(params.text, 500); + const debouncedSort = useDebouncedValue(sort, 500); + const query = useQuery({ ...params, text: debouncedText, type }, debouncedSort); + + const { data } = useEndpointDataExperimental('integrations.list', query); + + const router = useRoute('admin-integrations'); + + const onClick = (_id, type) => () => router.push({ + context: 'edit', + type: type === 'webhook-incoming' ? 'incoming' : 'outgoing', + id: _id, + }); + + const onHeaderClick = useCallback((id) => { + const [sortBy, sortDirection] = sort; + + if (sortBy === id) { + setSort([id, sortDirection === 'asc' ? 'desc' : 'asc']); + return; + } + setSort([id, 'asc']); + }, [sort]); + + const header = useMemo(() => [ + {t('Name')}, + {t('Post_to')}, + {t('Created_by')}, + isBig && {t('Created_at')}, + {t('Post_as')}, + ].filter(Boolean), [sort, isBig]); + + const renderRow = useCallback(({ name, _id, type, username, _createdAt, _createdBy: { username: createdBy }, channel }) => { + const handler = useMemo(() => onClick(_id, type), []); + return + {name} + {channel.join(', ')} + {createdBy} + {isBig && {formatDateAndTime(_createdAt)}} + {username} + ; + }, []); + + return ; +} + +export default IntegrationsTable; diff --git a/client/admin/integrations/OutgoiongWebhookForm.js b/client/admin/integrations/OutgoiongWebhookForm.js new file mode 100644 index 000000000000..2f6fe9fa4900 --- /dev/null +++ b/client/admin/integrations/OutgoiongWebhookForm.js @@ -0,0 +1,264 @@ +import { + Field, + TextInput, + Box, + ToggleSwitch, + Icon, + TextAreaInput, + FieldGroup, + Margins, + Select, + Accordion, +} from '@rocket.chat/fuselage'; +import React, { useMemo } from 'react'; + +import { useHilightCode } from '../../hooks/useHilightCode'; +import { useExampleData } from './exampleIncomingData'; +import { useTranslation } from '../../contexts/TranslationContext'; +import Page from '../../components/basic/Page'; +import { integrations as eventList } from '../../../app/integrations/lib/rocketchat'; + + +export default function OutgoingWebhookForm({ formValues, formHandlers, append, ...props }) { + const t = useTranslation(); + + const { + enabled, + impersonateUser, + event, + urls, + triggerWords, + targetRoom, + channel, + username, + name, + alias, + avatar: avatarUrl, + emoji, + token, + scriptEnabled, + script, + retryFailedCalls, + retryCount, + retryDelay, + triggerWordAnywhere, + } = formValues; + + const { + runOnEdits, + handleEvent, + handleEnabled, + handleName, + handleChannel, + handleTriggerWords, + handleTargetRoom, + handleUrls, + handleImpersonateUser, + handleUsername, + handleAlias, + handleAvatar, + handleEmoji, + handleToken, + handleScriptEnabled, + handleScript, + handleRetryFailedCalls, + handleRetryCount, + handleRetryDelay, + handleTriggerWordAnywhere, + handleRunOnEdits, + } = formHandlers; + + const retryDelayOptions = useMemo(() => [ + ['powers-of-ten', t('powers-of-ten')], + ['powers-of-two', t('powers-of-two')], + ['increments-of-two', t('increments-of-two')], + ], []); + + const { outgoingEvents } = eventList; + + const eventOptions = useMemo(() => Object.entries(outgoingEvents).map(([key, val]) => [key, t(val.label)]), []); + + const hilightCode = useHilightCode(); + + const showChannel = useMemo(() => outgoingEvents[event].use.channel, [event]); + const showTriggerWords = useMemo(() => outgoingEvents[event].use.triggerWords, [event]); + const showTargetRoom = useMemo(() => outgoingEvents[event].use.targetRoom, [event]); + + const [exampleData] = useExampleData({ + aditionalFields: { + ...alias && { alias }, + ...emoji && { emoji }, + ...avatarUrl && { avatar: avatarUrl }, + }, + url: null, + }, [alias, emoji, avatarUrl]); + + const hilightedExampleJson = hilightCode('json', JSON.stringify(exampleData, null, 2)); + + return + + + + { useMemo(() => + {t('Event_Trigger')} + + + + + , [retryDelay])} + { useMemo(() => event === 'sendMessage' && + + + {t('Integration_Word_Trigger_Placement')} + + + {t('Integration_Word_Trigger_Placement_Description')} + + + + {t('Integration_Word_Trigger_Placement')} + + + {t('Integration_Run_When_Message_Is_Edited_Description')} + + , [triggerWordAnywhere, runOnEdits])} + + + { append } + + + ; +} diff --git a/client/admin/integrations/edit/EditIncomingWebhook.js b/client/admin/integrations/edit/EditIncomingWebhook.js new file mode 100644 index 000000000000..2a6363d9f224 --- /dev/null +++ b/client/admin/integrations/edit/EditIncomingWebhook.js @@ -0,0 +1,105 @@ +import React, { useMemo, useState } from 'react'; +import { Field, Box, Headline, Skeleton, Margins, Button } from '@rocket.chat/fuselage'; + +import { SuccessModal, DeleteWarningModal } from './EditIntegrationsPage'; +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useEndpointDataExperimental, ENDPOINT_STATES } from '../../../hooks/useEndpointDataExperimental'; +import { useMethod } from '../../../contexts/ServerContext'; +import { useEndpointAction } from '../../../hooks/useEndpointAction'; +import { useRoute } from '../../../contexts/RouterContext'; +import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext'; +import { useForm } from '../../../hooks/useForm'; +import IncomingWebhookForm from '../IncomingWebhookForm'; + +export default function EditIncomingWebhookWithData({ integrationId, ...props }) { + const t = useTranslation(); + const [cache, setCache] = useState(); + + const { data, state, error } = useEndpointDataExperimental('integrations.get', useMemo(() => ({ integrationId }), [integrationId, cache])); + + const onChange = () => setCache(new Date()); + + if (state === ENDPOINT_STATES.LOADING) { + return + + + + + + + ; + } + + if (error) { + return {t('Oops_page_not_found')}; + } + + return ; +} + +const getInitialValue = (data) => { + const initialValue = { + enabled: data.enabled, + channel: data.channel.join(', ') ?? '', + username: data.username ?? '', + name: data.name ?? '', + alias: data.alias ?? '', + avatarUrl: data.avatarUrl ?? '', + emoji: data.emoji ?? '', + scriptEnabled: data.scriptEnabled, + script: data.script, + }; + return initialValue; +}; + +function EditIncomingWebhook({ data, onChange, ...props }) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const { values: formValues, handlers: formHandlers, reset } = useForm(getInitialValue(data)); + const [modal, setModal] = useState(); + + const deleteQuery = useMemo(() => ({ type: 'webhook-incoming', integrationId: data._id }), [data._id]); + const deleteIntegration = useEndpointAction('POST', 'integrations.remove', deleteQuery); + const saveIntegration = useMethod('updateIncomingIntegration'); + + const router = useRoute('admin-integrations'); + + const handleDeleteIntegration = () => { + const closeModal = () => setModal(); + const onDelete = async () => { + const result = await deleteIntegration(); + if (result.success) { setModal( { closeModal(); router.push({}); }}/>); } + }; + + setModal(); + }; + + const handleSave = async () => { + try { + await saveIntegration(data._id, { ...formValues }); + dispatchToastMessage({ type: 'success', message: t('Integration_updated') }); + onChange(); + } catch (e) { + dispatchToastMessage({ type: 'error', message: e }); + } + }; + + const actionButtons = useMemo(() => + + + + + + + + + + ); + + + return <> + + { modal } + ; +} diff --git a/client/admin/integrations/edit/EditIntegrationsPage.js b/client/admin/integrations/edit/EditIntegrationsPage.js new file mode 100644 index 000000000000..3ffdb8168c79 --- /dev/null +++ b/client/admin/integrations/edit/EditIntegrationsPage.js @@ -0,0 +1,82 @@ +import { Button, ButtonGroup, Icon } from '@rocket.chat/fuselage'; +import React, { useCallback } from 'react'; + +import Page from '../../../components/basic/Page'; +import EditIncomingWebhookWithData from './EditIncomingWebhook'; +import EditOutgoingWebhookWithData from './EditOutgoingWebhook'; +import { Modal } from '../../../components/basic/Modal'; +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useRouteParameter, useRoute } from '../../../contexts/RouterContext'; + +export const DeleteWarningModal = ({ onDelete, onCancel, ...props }) => { + const t = useTranslation(); + return + + + {t('Are_you_sure')} + + + + {t('Integration_Delete_Warning')} + + + + + + + + ; +}; + +export const SuccessModal = ({ onClose, ...props }) => { + const t = useTranslation(); + return + + + {t('Deleted')} + + + + {t('Your_entry_has_been_deleted')} + + + + + + + ; +}; + +export default function NewIntegrationsPage({ ...props }) { + const t = useTranslation(); + + const router = useRoute('admin-integrations'); + + const type = useRouteParameter('type'); + const integrationId = useRouteParameter('id'); + + const handleClickReturn = useCallback(() => { + router.push({ }); + }, []); + + const handleClickHistory = useCallback(() => { + router.push({ context: 'history', type: 'outgoing', id: integrationId }); + }, [integrationId]); + + return + + + + {type === 'outgoing' && } + + + + { + (type === 'outgoing' && ) + || (type === 'incoming' && ) + } + + ; +} diff --git a/client/admin/integrations/edit/EditOutgoingWebhook.js b/client/admin/integrations/edit/EditOutgoingWebhook.js new file mode 100644 index 000000000000..7c20820b2a82 --- /dev/null +++ b/client/admin/integrations/edit/EditOutgoingWebhook.js @@ -0,0 +1,134 @@ +import React, { useMemo, useState } from 'react'; +import { + Field, + Box, + Headline, + Skeleton, + Margins, + Button, +} from '@rocket.chat/fuselage'; + +import { SuccessModal, DeleteWarningModal } from './EditIntegrationsPage'; +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useEndpointDataExperimental, ENDPOINT_STATES } from '../../../hooks/useEndpointDataExperimental'; +import { useEndpointAction } from '../../../hooks/useEndpointAction'; +import { useRoute } from '../../../contexts/RouterContext'; +import { useMethod } from '../../../contexts/ServerContext'; +import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext'; +import OutgoingWebhookForm from '../OutgoiongWebhookForm'; +import { useForm } from '../../../hooks/useForm'; + +export default function EditOutgoingWebhookWithData({ integrationId, ...props }) { + const t = useTranslation(); + const [cache, setCache] = useState(); + + const { data, state, error } = useEndpointDataExperimental('integrations.get', useMemo(() => ({ integrationId }), [integrationId, cache])); + + const onChange = () => setCache(new Date()); + + if (state === ENDPOINT_STATES.LOADING) { + return + + + + + + + ; + } + + if (error) { + return {t('Oops_page_not_found')}; + } + + return ; +} + +const getInitialValue = (data) => { + const initialValue = { + enabled: data.enabled ?? true, + impersonateUser: data.impersonateUser, + event: data.event, + token: data.token, + urls: data.urls.join('\n') ?? '', + triggerWords: data.triggerWords?.join('; ') ?? '', + targetRoom: data.targetRoom ?? '', + channel: data.channel.join(', ') ?? '', + username: data.username ?? '', + name: data.name ?? '', + alias: data.alias ?? '', + avatarUrl: data.avatarUrl ?? '', + emoji: data.emoji ?? '', + scriptEnabled: data.scriptEnabled ?? false, + script: data.script ?? '', + retryFailedCalls: data.retryFailedCalls ?? true, + retryCount: data.retryCount ?? 5, + retryDelay: data.retryDelay ?? 'power-of-ten', + triggerrWordAnywhere: data.triggerrWordAnywhere ?? false, + runOnEdits: data.runOnEdits ?? true, + }; + return initialValue; +}; + +function EditOutgoingWebhook({ data, onChange, setSaveAction, ...props }) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const { handlers: formHandlers, values: formValues, reset } = useForm(getInitialValue(data)); + const [modal, setModal] = useState(); + + const saveIntegration = useMethod('updateOutgoingIntegration'); + + const router = useRoute('admin-integrations'); + + const deleteQuery = useMemo(() => ({ type: 'webhook-outgoing', integrationId: data._id }), [data._id]); + const deleteIntegration = useEndpointAction('POST', 'integrations.remove', deleteQuery); + + const handleDeleteIntegration = () => { + const closeModal = () => setModal(); + const onDelete = async () => { + const result = await deleteIntegration(); + if (result.success) { setModal( { closeModal(); router.push({}); }}/>); } + }; + + setModal(); + }; + + const { + urls, + triggerWords, + } = formValues; + + const handleSave = async () => { + try { + await saveIntegration(data._id, { + ...formValues, + triggerWords: triggerWords.split(';'), + urls: urls.split('\n'), + }); + + dispatchToastMessage({ type: 'success', message: t('Integration_updated') }); + onChange(); + } catch (e) { + dispatchToastMessage({ type: 'error', message: e }); + } + }; + + const actionButtons = useMemo(() => + + + + + + + + + + ); + + + return <> + + { modal } + ; +} diff --git a/client/admin/integrations/edit/OutgoingWebhookHistoryPage.js b/client/admin/integrations/edit/OutgoingWebhookHistoryPage.js new file mode 100644 index 000000000000..e931ade0b90d --- /dev/null +++ b/client/admin/integrations/edit/OutgoingWebhookHistoryPage.js @@ -0,0 +1,268 @@ +import { Button, ButtonGroup, Icon, Headline, Skeleton, Box, Accordion, Field, FieldGroup, Pagination } from '@rocket.chat/fuselage'; +import React, { useMemo, useCallback, useState, useEffect } from 'react'; + +import Page from '../../../components/basic/Page'; +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useHilightCode } from '../../../hooks/useHilightCode'; +import { integrations as eventList } from '../../../../app/integrations/lib/rocketchat'; +import { useMethod } from '../../../contexts/ServerContext'; +import { useEndpointDataExperimental, ENDPOINT_STATES } from '../../../hooks/useEndpointDataExperimental'; +import { useRoute, useRouteParameter } from '../../../contexts/RouterContext'; +import { useFormatDateAndTime } from '../../../hooks/useFormatDateAndTime'; +import { useToastMessageDispatch } from '../../../contexts/ToastMessagesContext'; + +function HistoryItem({ data, onChange, ...props }) { + const t = useTranslation(); + + const hilightCode = useHilightCode(); + + const replayOutgoingIntegration = useMethod('replayOutgoingIntegration'); + + const { + _id, + _createdAt, + _updatedAt, + httpResult, + event, + step, + httpCallData, + data: dataSentToTrigger, + prepareSentMessage, + processSentMessage, + url, + httpError, + errorStack, + error, + integration: { _id: integrationId }, + } = data; + + const handleClickReplay = useCallback((e) => { + e.stopPropagation(); + replayOutgoingIntegration({ integrationId, historyId: _id }); + onChange(); + }, [_id]); + + const formatDateAndTime = useFormatDateAndTime(); + + return + + {formatDateAndTime(_createdAt)} + + + + } + {...props} + > + + + {t('Status')} + + + {error ? t('Failure') : t('Success')} + + + + + {t('Integration_Outgoing_WebHook_History_Time_Triggered')} + + + {_createdAt} + + + + + {t('Integration_Outgoing_WebHook_History_Time_Ended_Or_Error')} + + + {_updatedAt} + + + + + {t('Event_Trigger')} + + + {t(eventList.outgoingEvents[event].label)} + + + + + {t('Integration_Outgoing_WebHook_History_Trigger_Step')} + + + {step} + + + + + {t('Integration_Outgoing_WebHook_History_Data_Passed_To_Trigger')} + + +
+
+
+
+ {prepareSentMessage && + {t('Integration_Outgoing_WebHook_History_Messages_Sent_From_Prepare_Script')} + + +
+
+
+
} + {processSentMessage && + {t('Integration_Outgoing_WebHook_History_Messages_Sent_From_Process_Script')} + + +
+
+
+
} + {url && + {t('URL')} + + + {url} + + + } + {httpCallData && + {t('Integration_Outgoing_WebHook_History_Data_Passed_To_URL')} + + +
+
+
+
} + {httpError && + {t('Integration_Outgoing_WebHook_History_Http_Response_Error')} + + +
+
+
+
} + {httpResult && + {t('Integration_Outgoing_WebHook_History_Http_Response')} + + +
+
+
+
} + {errorStack && + {t('Integration_Outgoing_WebHook_History_Error_Stacktrace')} + + +
+
+
+
} +
+
; +} + +function HistoryContent({ data, state, onChange, ...props }) { + const t = useTranslation(); + + const [loadedData, setLoadedData] = useState(); + useEffect(() => { + if (state === ENDPOINT_STATES.DONE) { setLoadedData(data); } + }, [state]); + + if (!loadedData || state === ENDPOINT_STATES.LOADING) { + return + + + + + + + ; + } + + if (loadedData.history.length < 1) { + return {t('Integration_Outgoing_WebHook_No_History')}; + } + + return <> + + {loadedData.history.map((current) => )} + + ; +} + +function OutgoingWebhookHistoryPage(props) { + const dispatchToastMessage = useToastMessageDispatch(); + const t = useTranslation(); + + const [cache, setCache] = useState(); + const [current, setCurrent] = useState(); + const [itemsPerPage, setItemsPerPage] = useState(); + const onChange = useCallback(() => { + setCache(new Date()); + }); + + const router = useRoute('admin-integrations'); + + const clearHistory = useMethod('clearIntegrationHistory'); + + const handleClearHistory = async () => { + try { + await clearHistory(); + dispatchToastMessage({ type: 'success', message: t('Integration_History_Cleared') }); + onChange(); + } catch (e) { + dispatchToastMessage({ type: 'error', message: e }); + } + }; + + const handleClickReturn = () => { + router.push({ }); + }; + + const id = useRouteParameter('id'); + + const query = useMemo(() => ({ + id, + cout: itemsPerPage, + offset: current, + }), [id, itemsPerPage, current, cache]); + + const { data, state } = useEndpointDataExperimental('integrations.history', query); + + const showingResultsLabel = useCallback(({ count, current, itemsPerPage }) => t('Showing results %s - %s of %s', current + 1, Math.min(current + itemsPerPage, count), count), []); + + return + + + + + + + + + + + ; +} + +export default OutgoingWebhookHistoryPage; diff --git a/client/admin/integrations/exampleIncomingData.js b/client/admin/integrations/exampleIncomingData.js new file mode 100644 index 000000000000..0226156f69fc --- /dev/null +++ b/client/admin/integrations/exampleIncomingData.js @@ -0,0 +1,20 @@ +import { useMemo } from 'react'; + +export function useExampleData({ aditionalFields, url }, dep) { + const exampleData = { + ...aditionalFields, + text: 'Example message', + attachments: [{ + title: 'Rocket.Chat', + title_link: 'https://rocket.chat', + text: 'Rocket.Chat, the best open source chat', + image_url: '/images/integration-attachment-example.png', + color: '#764FA5', + }], + }; + + return useMemo(() => [ + exampleData, + `curl -X POST -H 'Content-Type: application/json' --data '${ JSON.stringify(exampleData) }' ${ url }`, + ], dep); +} diff --git a/client/admin/integrations/new/NewBot.js b/client/admin/integrations/new/NewBot.js new file mode 100644 index 000000000000..54ff4615574e --- /dev/null +++ b/client/admin/integrations/new/NewBot.js @@ -0,0 +1,9 @@ +import React from 'react'; +import { Box } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../../contexts/TranslationContext'; + +export default function NewBot() { + const t = useTranslation(); + return ; +} diff --git a/client/admin/integrations/new/NewIncomingWebhook.js b/client/admin/integrations/new/NewIncomingWebhook.js new file mode 100644 index 000000000000..99cdbc628276 --- /dev/null +++ b/client/admin/integrations/new/NewIncomingWebhook.js @@ -0,0 +1,50 @@ +import React, { useMemo } from 'react'; +import { Field, Box, Margins, Button } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useRoute } from '../../../contexts/RouterContext'; +import { useEndpointAction } from '../../../hooks/useEndpointAction'; +import { useForm } from '../../../hooks/useForm'; +import IncomingWebhookForm from '../IncomingWebhookForm'; + +const initialState = { + enabled: false, + channel: '', + username: '', + name: '', + alias: '', + avatarUrl: '', + emoji: '', + scriptEnabled: false, + script: '', +}; + +export default function NewIncomingWebhook(props) { + const t = useTranslation(); + + const router = useRoute('admin-integrations'); + + const { values: formValues, handlers: formHandlers, reset } = useForm(initialState); + + const saveAction = useEndpointAction('POST', 'integrations.create', useMemo(() => ({ ...formValues, type: 'webhook-incoming' }), [JSON.stringify(formValues)]), t('Integration_added')); + + const handleSave = async () => { + const result = await saveAction(); + if (result.success) { + router.push({ context: 'edit', type: 'incoming', id: result.integration._id }); + } + }; + + const actionButtons = useMemo(() => + + + + + + + + + ); + + return ; +} diff --git a/client/admin/integrations/new/NewIntegrationsPage.js b/client/admin/integrations/new/NewIntegrationsPage.js new file mode 100644 index 000000000000..70dfc441127d --- /dev/null +++ b/client/admin/integrations/new/NewIntegrationsPage.js @@ -0,0 +1,58 @@ +import { Tabs, Button, ButtonGroup, Icon } from '@rocket.chat/fuselage'; +import React, { useCallback } from 'react'; + +import Page from '../../../components/basic/Page'; +import NewIncomingWebhook from './NewIncomingWebhook'; +import NewOutgoingWebhook from './NewOutgoingWebhook'; +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useRouteParameter, useRoute } from '../../../contexts/RouterContext'; + + +export default function NewIntegrationsPage({ ...props }) { + const t = useTranslation(); + + const router = useRoute('admin-integrations'); + + const handleClickTab = (type) => () => { + router.push({ context: 'new', type }); + }; + + const handleClickReturn = useCallback(() => { + router.push({ }); + }, []); + + const tab = useRouteParameter('type'); + + const handleIncomingTab = useCallback(handleClickTab('incoming'), []); + const handleOutgoingTab = useCallback(handleClickTab('outgoing'), []); + + return + + + + + + + + {t('Incoming')} + + + {t('Outgoing')} + + + + { + (tab === 'incoming' && ) + || (tab === 'outgoing' && ) + } + + ; +} diff --git a/client/admin/integrations/new/NewOutgoingWebhook.js b/client/admin/integrations/new/NewOutgoingWebhook.js new file mode 100644 index 000000000000..f211f07d5ba1 --- /dev/null +++ b/client/admin/integrations/new/NewOutgoingWebhook.js @@ -0,0 +1,68 @@ +import React, { useMemo, useCallback } from 'react'; +import { Field, Button } from '@rocket.chat/fuselage'; +import { useUniqueId } from '@rocket.chat/fuselage-hooks'; + +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useEndpointAction } from '../../../hooks/useEndpointAction'; +import { useRoute } from '../../../contexts/RouterContext'; +import { useForm } from '../../../hooks/useForm'; +import OutgoingWebhookForm from '../OutgoiongWebhookForm'; + +const defaultData = { + type: 'webhook-outgoing', + enabled: true, + impersonateUser: false, + event: 'sendMessage', + urls: '', + triggerWords: '', + targetRoom: '', + channel: '', + username: '', + name: '', + alias: '', + avatar: '', + emoji: '', + scriptEnabled: false, + script: '', + retryFailedCalls: true, + retryCount: 6, + retryDelay: 'powers-of-ten', + triggerWordAnywhere: false, + runOnEdits: true, +}; + +export default function NewOutgoingWebhook({ data = defaultData, onChange, setSaveAction, ...props }) { + const t = useTranslation(); + const router = useRoute('admin-integrations'); + + const { values: formValues, handlers: formHandlers } = useForm({ ...data, token: useUniqueId() }); + + const { + urls, + triggerWords, + } = formValues; + + const query = useMemo(() => ({ + ...formValues, + urls: urls.split('\n'), + triggerWords: triggerWords.split(';'), + }), [JSON.stringify(formValues)]); + + const saveIntegration = useEndpointAction('POST', 'integrations.create', query, t('Integration_added')); + + const handleSave = useCallback(async () => { + const result = await saveIntegration(); + if (result.success) { + router.push({ id: result.integration._id, context: 'edit', type: 'outgoing' }); + } + }, [saveIntegration, router]); + + const saveButton = useMemo(() => + + + + ); + + + return ; +} diff --git a/client/admin/integrations/new/NewZapier.js b/client/admin/integrations/new/NewZapier.js new file mode 100644 index 000000000000..a9f9e1513cfc --- /dev/null +++ b/client/admin/integrations/new/NewZapier.js @@ -0,0 +1,43 @@ +import React, { useEffect, useState } from 'react'; +import { Box, Skeleton, Margins } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../../contexts/TranslationContext'; + +const blogSpotStyleScriptImport = (src) => new Promise((resolve) => { + const script = document.createElement('script'); + script.type = 'text/javascript'; + document.body.appendChild(script); + + const resolveFunc = (event) => resolve(event.currentTarget); + + script.onreadystatechange = resolveFunc; + script.onload = resolveFunc; + script.src = src; +}); + +export default function NewZapier({ ...props }) { + const t = useTranslation(); + const [script, setScript] = useState(); + useEffect(() => { + const importZapier = async () => { + const scriptEl = await blogSpotStyleScriptImport('https://zapier.com/apps/embed/widget.js?services=rocketchat&html_id=zapier-goes-here'); + setScript(scriptEl); + }; + if (!script) { importZapier(); } + return () => script && script.parentNode.removeChild(script); + }, [script]); + + return <> + + {!script && + + + + + + + + } + + ; +} diff --git a/client/admin/oauthApps/OAuthAddApp.js b/client/admin/oauthApps/OAuthAddApp.js new file mode 100644 index 000000000000..a31a083288bd --- /dev/null +++ b/client/admin/oauthApps/OAuthAddApp.js @@ -0,0 +1,87 @@ +import React, { useCallback, useState } from 'react'; +import { + Button, + ButtonGroup, + TextInput, + Field, + TextAreaInput, + ToggleSwitch, + FieldGroup, +} from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod } from '../../contexts/ServerContext'; +import { useRoute } from '../../contexts/RouterContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import VerticalBar from '../../components/basic/VerticalBar'; + + +export default function OAuthAddApp(props) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const [newData, setNewData] = useState({ + name: '', + active: false, + redirectUri: '', + }); + + const saveApp = useMethod('addOAuthApp'); + + const router = useRoute('admin-oauth-apps'); + + const close = useCallback(() => router.push({}), [router]); + + const handleSave = useCallback(async () => { + try { + await saveApp( + newData, + ); + close(); + dispatchToastMessage({ type: 'success', message: t('Application_added') }); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + }, [JSON.stringify(newData)]); + + const handleChange = (field, getValue = (e) => e.currentTarget.value) => (e) => setNewData({ ...newData, [field]: getValue(e) }); + + const { + active, + name, + redirectUri, + } = newData; + + return + + + + {t('Active')} + !active)}/> + + + + {t('Application_Name')} + + + + {t('Give_the_application_a_name_This_will_be_seen_by_your_users')} + + + {t('Redirect_URI')} + + + + {t('After_OAuth2_authentication_users_will_be_redirected_to_this_URL')} + + + + + + + + + + + ; +} diff --git a/client/admin/oauthApps/OAuthAppsPage.js b/client/admin/oauthApps/OAuthAppsPage.js new file mode 100644 index 000000000000..a42e5b863675 --- /dev/null +++ b/client/admin/oauthApps/OAuthAppsPage.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { Button, Icon } from '@rocket.chat/fuselage'; + +import Page from '../../components/basic/Page'; +// import VerticalBar from '../../components/basic/VerticalBar'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useRouteParameter, useRoute } from '../../contexts/RouterContext'; +import OAuthAppsTable from './OAuthAppsTable'; +import OAuthEditAppWithData from './OAuthEditApp'; +import OAuthAddApp from './OAuthAddApp'; + +export function OAuthAppsPage() { + const t = useTranslation(); + + const router = useRoute('admin-oauth-apps'); + + const context = useRouteParameter('context'); + const id = useRouteParameter('id'); + + return + + + {context && } + {!context && } + + + {!context && } + {context === 'edit' && } + {context === 'new' && } + + + ; +} + +export default OAuthAppsPage; diff --git a/client/admin/oauthApps/OAuthAppsRoute.js b/client/admin/oauthApps/OAuthAppsRoute.js new file mode 100644 index 000000000000..8f163d0cb483 --- /dev/null +++ b/client/admin/oauthApps/OAuthAppsRoute.js @@ -0,0 +1,15 @@ +import React from 'react'; + +import { usePermission } from '../../contexts/AuthorizationContext'; +import NotAuthorizedPage from '../NotAuthorizedPage'; +import OAuthAppsPage from './OAuthAppsPage'; + +export default function MailerRoute() { + const canAccessOAuthApps = usePermission('manage-oauth-apps'); + + if (!canAccessOAuthApps) { + return ; + } + + return ; +} diff --git a/client/admin/oauthApps/OAuthAppsTable.js b/client/admin/oauthApps/OAuthAppsTable.js new file mode 100644 index 000000000000..91b1ec301b06 --- /dev/null +++ b/client/admin/oauthApps/OAuthAppsTable.js @@ -0,0 +1,40 @@ +import { Table } from '@rocket.chat/fuselage'; +import React, { useMemo, useCallback } from 'react'; + +import { GenericTable, Th } from '../../../app/ui/client/components/GenericTable'; +import { useTranslation } from '../../contexts/TranslationContext'; +import { useRoute } from '../../contexts/RouterContext'; +import { useEndpointDataExperimental } from '../../hooks/useEndpointDataExperimental'; +import { useFormatDateAndTime } from '../../hooks/useFormatDateAndTime'; + +export function OAuthAppsTable() { + const t = useTranslation(); + const formatDateAndTime = useFormatDateAndTime(); + + const { data } = useEndpointDataExperimental('oauth-apps.list', useMemo(() => ({}), [])); + + const router = useRoute('admin-oauth-apps'); + + const onClick = (_id) => () => router.push({ + context: 'edit', + id: _id, + }); + + const header = useMemo(() => [ + {t('Name')}, + {t('Created_by')}, + {t('Created_at')}, + ]); + + const renderRow = useCallback(({ _id, name, _createdAt, _createdBy: { username: createdBy } }) => + + {name} + {createdBy} + {formatDateAndTime(_createdAt)} + , + ); + + return ; +} + +export default OAuthAppsTable; diff --git a/client/admin/oauthApps/OAuthEditApp.js b/client/admin/oauthApps/OAuthEditApp.js new file mode 100644 index 000000000000..b525bbada583 --- /dev/null +++ b/client/admin/oauthApps/OAuthEditApp.js @@ -0,0 +1,222 @@ +import React, { useCallback, useState, useMemo } from 'react'; +import { + Box, + Button, + ButtonGroup, + TextInput, + Field, + Icon, + Skeleton, + Throbber, + InputBox, + TextAreaInput, + ToggleSwitch, + FieldGroup, +} from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../contexts/TranslationContext'; +import { useMethod, useAbsoluteUrl } from '../../contexts/ServerContext'; +import { useRoute } from '../../contexts/RouterContext'; +import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext'; +import { Modal } from '../../components/basic/Modal'; +import { useEndpointDataExperimental, ENDPOINT_STATES } from '../../hooks/useEndpointDataExperimental'; +import VerticalBar from '../../components/basic/VerticalBar'; + +const DeleteWarningModal = ({ onDelete, onCancel, ...props }) => { + const t = useTranslation(); + return + + + {t('Are_you_sure')} + + + + {t('Application_delete_warning')} + + + + + + + + ; +}; + +const SuccessModal = ({ onClose, ...props }) => { + const t = useTranslation(); + return + + + {t('Deleted')} + + + + {t('Your_entry_has_been_deleted')} + + + + + + + ; +}; + +export default function EditOauthAppWithData({ _id, ...props }) { + const t = useTranslation(); + + const [cache, setCache] = useState(); + + const onChange = useCallback(() => { + setCache(new Date()); + }, []); + + const query = useMemo(() => ({ + appId: _id, + }), [_id, cache]); + + const { data, state, error } = useEndpointDataExperimental('oauth-apps.get', query); + + if (state === ENDPOINT_STATES.LOADING) { + return + + + + + + + + + + + + ; + } + + if (error || !data || !_id) { + return {t('error-application-not-found')}; + } + + return ; +} + +function EditOauthApp({ onChange, data, ...props }) { + const t = useTranslation(); + const dispatchToastMessage = useToastMessageDispatch(); + + const [newData, setNewData] = useState({ + name: data.name, + active: data.active, + redirectUri: Array.isArray(data.redirectUri) ? data.redirectUri.join('\n') : data.redirectUri, + }); + const [modal, setModal] = useState(); + + const router = useRoute('admin-oauth-apps'); + + const close = useCallback(() => router.push({}), [router]); + + const absoluteUrl = useAbsoluteUrl(); + const authUrl = useMemo(() => absoluteUrl('oauth/authorize')); + const tokenUrl = useMemo(() => absoluteUrl('oauth/token')); + + const saveApp = useMethod('updateOAuthApp'); + const deleteApp = useMethod('deleteOAuthApp'); + + const handleSave = useCallback(async () => { + try { + await saveApp( + data._id, + newData, + ); + dispatchToastMessage({ type: 'success', message: t('Application_updated') }); + onChange(); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + }, [JSON.stringify(newData)]); + + const onDeleteConfirm = useCallback(async () => { + try { + await deleteApp(data._id); + setModal(() => { setModal(); close(); }}/>); + } catch (error) { + dispatchToastMessage({ type: 'error', message: error }); + } + }, [data._id]); + + const openConfirmDelete = () => setModal(() => setModal(undefined)}/>); + + const handleChange = (field, getValue = (e) => e.currentTarget.value) => (e) => setNewData({ ...newData, [field]: getValue(e) }); + + const { + active, + name, + redirectUri, + } = newData; + + return <> + + + + + {t('Active')} + !active)}/> + + + + {t('Application_Name')} + + + + {t('Give_the_application_a_name_This_will_be_seen_by_your_users')} + + + {t('Redirect_URI')} + + + + {t('After_OAuth2_authentication_users_will_be_redirected_to_this_URL')} + + + {t('Client_ID')} + + + + + + {t('Client_Secret')} + + + + + + {t('Authorization_URL')} + + + + + + {t('Access_Token_URL')} + + + + + + + + + + + + + + + + + + + + + + { modal } + ; +} diff --git a/client/admin/rooms/EditRoom.js b/client/admin/rooms/EditRoom.js index d60ca438a58d..f77b06334afb 100644 --- a/client/admin/rooms/EditRoom.js +++ b/client/admin/rooms/EditRoom.js @@ -1,5 +1,5 @@ import React, { useCallback, useState, useMemo } from 'react'; -import { Box, Headline, Button, Margins, TextInput, Skeleton, Field, ToggleSwitch, Divider, Icon, Callout } from '@rocket.chat/fuselage'; +import { Box, Button, Margins, TextInput, Skeleton, Field, ToggleSwitch, Divider, Icon, Callout } from '@rocket.chat/fuselage'; import { useTranslation } from '../../contexts/TranslationContext'; import { useEndpointDataExperimental, ENDPOINT_STATES } from '../../hooks/useEndpointDataExperimental'; @@ -22,11 +22,11 @@ function EditRoomWithData({ rid }) { if (state === ENDPOINT_STATES.LOADING) { return - + - + - + ; } diff --git a/client/admin/rooms/edit/EditRoom.js b/client/admin/rooms/edit/EditRoom.js new file mode 100644 index 000000000000..7638bebcc00c --- /dev/null +++ b/client/admin/rooms/edit/EditRoom.js @@ -0,0 +1,194 @@ +import React, { useCallback, useState, useMemo } from 'react'; +import { Box, Headline, Button, Margins, TextInput, Skeleton, Field, ToggleSwitch, Divider, Icon, Callout } from '@rocket.chat/fuselage'; + +import { useTranslation } from '../../../contexts/TranslationContext'; +import { useEndpointDataExperimental, ENDPOINT_STATES } from '../../../hooks/useEndpointDataExperimental'; +import { roomTypes } from '../../../../app/utils/client'; +import { useMethod } from '../../../contexts/ServerContext'; +import { usePermission } from '../../../contexts/AuthorizationContext'; +import NotAuthorizedPage from '../../NotAuthorizedPage'; +import { useEndpointAction } from '../../../hooks/useEndpointAction'; +import Page from '../../../components/basic/Page'; + +export function EditRoomContextBar({ rid }) { + const canViewRoomAdministration = usePermission('view-room-administration'); + return canViewRoomAdministration ? : ; +} + +function EditRoomWithData({ rid }) { + const [cache, setState] = useState(); + + const { data = {}, state, error } = useEndpointDataExperimental('rooms.adminRooms.getRoom', useMemo(() => ({ rid }), [rid, cache])); + + if (state === ENDPOINT_STATES.LOADING) { + return + + + + + + + ; + } + + if (state === ENDPOINT_STATES.ERROR) { + return error.message; + } + + return setState(new Date())}/>; +} + +function EditRoom({ room, onChange }) { + const t = useTranslation(); + + const [deleted, setDeleted] = useState(false); + const [newData, setNewData] = useState({}); + const [changeArchivation, setChangeArchivation] = useState(false); + + const canDelete = usePermission(`delete-${ room.t }`); + + const hasUnsavedChanges = useMemo(() => Object.values(newData).filter((current) => current === null).length < Object.keys(newData).length, [JSON.stringify(newData)]); + const saveQuery = useMemo(() => ({ rid: room._id, ...Object.fromEntries(Object.entries(newData).filter(([, value]) => value !== null)) }), [room._id, JSON.stringify(newData)]); + + const archiveSelector = room.archived ? 'unarchive' : 'archive'; + const archiveMessage = archiveSelector === 'archive' ? 'Room_has_been_archived' : 'Room_has_been_archived'; + const archiveQuery = useMemo(() => ({ rid: room._id, action: room.archived ? 'unarchive' : 'archive' }), [room.rid, changeArchivation]); + + const saveAction = useEndpointAction('POST', 'rooms.saveRoomSettings', saveQuery, t('Room_updated_successfully')); + const archiveAction = useEndpointAction('POST', 'rooms.changeArchivationState', archiveQuery, t(archiveMessage)); + + const updateType = (type) => () => (type === 'p' ? 'c' : 'p'); + const areEqual = (a, b) => a === b || !(a || b); + + const handleChange = (field, currentValue, getValue = (e) => e.currentTarget.value) => (e) => setNewData({ ...newData, [field]: areEqual(getValue(e), currentValue) ? null : getValue(e) }); + const handleSave = async () => { + await Promise.all([hasUnsavedChanges && saveAction(), changeArchivation && archiveAction()].filter(Boolean)); + onChange('update'); + }; + + const deleteRoom = useMethod('eraseRoom'); + + const handleDelete = useCallback(async () => { + await deleteRoom(room._id); + setDeleted(true); + }, [room]); + + const roomName = room.t === 'd' ? room.usernames.join(' x ') : roomTypes.getRoomName(room.t, { type: room.t, ...room }); + const roomType = newData.roomType ?? room.t; + const readOnly = newData.readOnly ?? !!room.ro; + const isArchived = changeArchivation ? !room.archived : !!room.archived; + const isDefault = newData.default ?? !!room.default; + const isFavorite = newData.favorite ?? !!room.favorite; + const isFeatured = newData.featured ?? !!room.featured; + + return + + + {deleted && } + + + {t('Name')} + + + + + { room.t !== 'd' && <> + + {t('Owner')} + + {room.u?.username} + + + + {t('Topic')} + + + + + + + + + {t('Public')} + {t('All_users_in_the_channel_can_write_new_messages')} + + + + + + {t('Private')} + {t('Just_invited_people_can_access_this_channel')} + + + + + + + + + + {t('Collaborative')} + {t('All_users_in_the_channel_can_write_new_messages')} + + + !readOnly)}/> + + + {t('Read_only')} + {t('Only_authorized_users_can_write_new_messages')} + + + + + + + + + {t('Archived')} + setChangeArchivation(!changeArchivation)}/> + + + + + + + {t('Default')} + !isDefault)}/> + + + + + + + {t('Favorite')} + !isFavorite)}/> + + + + + + + {t('Featured')} + !isFeatured)}/> + + + + + + + + + + + + + + } + + + + + + + ; +} diff --git a/client/admin/routes.js b/client/admin/routes.js index 4df152660524..6ede81d1ef1d 100644 --- a/client/admin/routes.js +++ b/client/admin/routes.js @@ -72,6 +72,16 @@ registerAdminRoute('/mailer', { lazyRouteComponent: () => import('./mailer/MailerRoute'), }); +registerAdminRoute('/oauth-apps/:context?/:id?', { + name: 'admin-oauth-apps', + lazyRouteComponent: () => import('./oauthApps/OAuthAppsRoute'), +}); + +registerAdminRoute('/integrations/:context?/:type?/:id?', { + name: 'admin-integrations', + lazyRouteComponent: () => import('./integrations/IntegrationsRoute'), +}); + registerAdminRoute('/custom-user-status/:context?/:id?', { name: 'custom-user-status', lazyRouteComponent: () => import('./customUserStatus/CustomUserStatusRoute'), @@ -97,6 +107,11 @@ registerAdminRoute('/invites', { lazyRouteComponent: () => import('./invites/InvitesRoute'), }); +registerAdminRoute('/cloud/:page?', { + name: 'cloud', + lazyRouteComponent: () => import('./cloud/CloudRoute'), +}); + registerAdminRoute('/view-logs', { name: 'admin-view-logs', lazyRouteComponent: () => import('./viewLogs/ViewLogsRoute'), diff --git a/client/admin/sidebarItems.js b/client/admin/sidebarItems.js index a76b96d08dda..c5112049b571 100644 --- a/client/admin/sidebarItems.js +++ b/client/admin/sidebarItems.js @@ -42,6 +42,13 @@ registerAdminSidebarItem({ permissionGranted: () => hasPermission('create-invite-links'), }); +registerAdminSidebarItem({ + icon: 'cloud-plus', + href: 'cloud', + i18nLabel: 'Connectivity_Services', + permissionGranted: () => hasPermission('manage-cloud'), +}); + registerAdminSidebarItem({ href: 'admin-view-logs', i18nLabel: 'View_Logs', diff --git a/client/admin/users/EditUser.js b/client/admin/users/EditUser.js index a7b287f234ac..1feb1eb82c34 100644 --- a/client/admin/users/EditUser.js +++ b/client/admin/users/EditUser.js @@ -1,5 +1,5 @@ import React, { useMemo, useState } from 'react'; -import { Field, TextInput, Box, Headline, Skeleton, ToggleSwitch, Icon, TextAreaInput, MultiSelectFiltered, Margins, Button } from '@rocket.chat/fuselage'; +import { Field, TextInput, Box, Skeleton, ToggleSwitch, Icon, TextAreaInput, MultiSelectFiltered, Margins, Button } from '@rocket.chat/fuselage'; import { useTranslation } from '../../contexts/TranslationContext'; import { useEndpointData } from '../../hooks/useEndpointData'; @@ -18,11 +18,11 @@ export function EditUserWithData({ userId, ...props }) { if (state === ENDPOINT_STATES.LOADING) { return - + - + - + ; } diff --git a/client/admin/users/InviteUsers.js b/client/admin/users/InviteUsers.js index 5804f498c863..d47db76f7ff0 100644 --- a/client/admin/users/InviteUsers.js +++ b/client/admin/users/InviteUsers.js @@ -1,5 +1,5 @@ import React, { useCallback, useState } from 'react'; -import { Box, Headline, Button, Icon, TextAreaInput } from '@rocket.chat/fuselage'; +import { Box, Button, Icon, TextAreaInput } from '@rocket.chat/fuselage'; import { useTranslation } from '../../contexts/TranslationContext'; import { useMethod } from '../../contexts/ServerContext'; @@ -24,7 +24,7 @@ export function InviteUsers({ data, ...props }) { }); }; return - {t('Send_invitation_email')} + {t('Send_invitation_email')} {t('Send_invitation_email_info')} setText(e.currentTarget.value)}/>