diff --git a/.storybook/.babelrc b/.storybook/.babelrc index 6e8b075e8c4ea27433ca8298627fe3dce6775918..3f856fec45fb179713902581c38f0757e9d8e56f 100644 --- a/.storybook/.babelrc +++ b/.storybook/.babelrc @@ -5,9 +5,14 @@ { "shippedProposals": true, "useBuiltIns": "usage", - "corejs": "3" + "corejs": "3", + "modules": "commonjs", } ], - "@babel/preset-react" + "@babel/preset-react", + "@babel/preset-flow" + ], + "plugins": [ + "@babel/plugin-proposal-class-properties" ] -} \ No newline at end of file +} diff --git a/.storybook/addons.js b/.storybook/addons.js index 6aed412d04afb1e1ae1d5c1a9f9bd08904cef636..9d64a3d0a8f3342da85a92d311fd2f7f151ae9e3 100644 --- a/.storybook/addons.js +++ b/.storybook/addons.js @@ -1,2 +1,4 @@ import '@storybook/addon-actions/register'; +import '@storybook/addon-knobs/register'; import '@storybook/addon-links/register'; +import '@storybook/addon-viewport/register'; diff --git a/.storybook/config.js b/.storybook/config.js index 984a7b25e285c92f248ef94c1bf80622e42261e0..5de80993cf9fe96c1d27725ca6eff098d0f307c2 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -1,3 +1,49 @@ -import { configure } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { withKnobs }from '@storybook/addon-knobs'; +import { MINIMAL_VIEWPORTS, INITIAL_VIEWPORTS } from '@storybook/addon-viewport/dist/defaults'; +import { addDecorator, addParameters, configure } from '@storybook/react'; +import React from 'react'; + +import { ConnectionStatusProvider } from '../client/components/providers/ConnectionStatusProvider.mock'; +import { TranslationProvider } from '../client/components/providers/TranslationProvider.mock'; + +addParameters({ + viewport: { + viewports: { + ...MINIMAL_VIEWPORTS, + ...INITIAL_VIEWPORTS, + }, + defaultViewport: 'responsive', + }, +}) + +addDecorator(function RocketChatDecorator(fn) { + const linkElement = document.getElementById('theme-styles') || document.createElement('link'); + if (linkElement.id !== 'theme-styles') { + require('../app/theme/client/main.css'); + require('../app/theme/client/vendor/fontello/css/fontello.css'); + require('../client/RocketChat.font.css'); + linkElement.setAttribute('id', 'theme-styles'); + linkElement.setAttribute('rel', 'stylesheet'); + linkElement.setAttribute('href', 'https://open.rocket.chat/theme.css'); + document.head.appendChild(linkElement); + } + + return <ConnectionStatusProvider connected status='connected' reconnect={action('reconnect')}> + <TranslationProvider> + <style>{` + body { + background-color: white; + } + `}</style> + <div dangerouslySetInnerHTML={{ __html: require('!!raw-loader!../private/public/icons.svg').default }} /> + <div className='global-font-family color-primary-font-color'> + {fn()} + </div> + </TranslationProvider> + </ConnectionStatusProvider>; +}); + +addDecorator(withKnobs); configure(require.context('../client', true, /\.stories\.js$/), module); diff --git a/.storybook/empty.js b/.storybook/empty.js new file mode 100644 index 0000000000000000000000000000000000000000..ff8b4c56321a3362fc00224b01800f62466f9a1f --- /dev/null +++ b/.storybook/empty.js @@ -0,0 +1 @@ +export default {}; diff --git a/.storybook/helpers.js b/.storybook/helpers.js index 00ad512dc47bba6305253ab4c2acc77bcca42bde..63e4e038a4445eecfe278990a19dde5ec44ae341 100644 --- a/.storybook/helpers.js +++ b/.storybook/helpers.js @@ -1,44 +1 @@ -import { action } from '@storybook/addon-actions'; -import '@rocket.chat/icons/dist/font/RocketChat.minimal.css'; -import React from 'react'; - -import '../app/theme/client/main.css'; -import { ConnectionStatusProvider } from '../client/components/providers/ConnectionStatusProvider.mock'; -import { TranslationProvider } from '../client/components/providers/TranslationProvider.mock'; - -export const rocketChatWrapper = (fn) => - <ConnectionStatusProvider connected status='connected' reconnect={action('reconnect')}> - <TranslationProvider> - <style>{` - body { - background-color: white; - } - - .global-font-family { - 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; - } - - .color-primary-font-color { - color: #444; - } - `}</style> - <div dangerouslySetInnerHTML={{__html: require('!!raw-loader!../private/public/icons.svg').default}} /> - <div className='global-font-family color-primary-font-color'> - {fn()} - </div> - </TranslationProvider> -</ConnectionStatusProvider>; +export const dummyDate = new Date(2015, 4, 19); diff --git a/.storybook/meteor.js b/.storybook/meteor.js new file mode 100644 index 0000000000000000000000000000000000000000..13f507c7ef32a9ee9f7237c6d094a10aabd25dc3 --- /dev/null +++ b/.storybook/meteor.js @@ -0,0 +1,74 @@ +export const Meteor = { + isClient: true, + isServer: false, + _localStorage: window.localStorage, + absoluteUrl: () => {}, + userId: () => {}, + Streamer: () => {}, + startup: () => {}, + methods: () => {}, + call: () => {}, +}; + +Meteor.absoluteUrl.defaultOptions = {}; + +export const Tracker = { + autorun: () => ({ + stop: () => {}, + }), + nonreactive: (fn) => fn(), + Dependency: () => {}, +}; + +export const Accounts = {}; + +export const Mongo = { + Collection: () => ({ + find: () => ({ + observe: () => {}, + fetch: () => [], + }) + }), +}; + +export const ReactiveVar = () => ({ + get: () => {}, + set: () => {}, +}); + +export const ReactiveDict = () => ({ + get: () => {}, + set: () => {}, + all: () => {}, +}); + +export const Template = () => ({ + onCreated: () => {}, + onRendered: () => {}, + onDestroyed: () => {}, + helpers: () => {}, + events: () => {}, +}); + +Template.registerHelper = () => {}; +Template.__checkName = () => {}; + +export const Blaze = { + Template, + registerHelper: () => {}, +}; + +window.Blaze = Blaze; + +export const check = () => {}; + +export const FlowRouter = { + route: () => {} +}; + +export const BlazeLayout = {}; + +export const Session = { + get: () => {}, + set: () => {}, +}; diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index b9ededccd61c9b3f2d6059868c0e5d12e5bed3a4..b9d6efb821d66c9c929bd1f9d89f15913acd46c6 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -1,14 +1,11 @@ 'use strict'; -module.exports = async ({ config, mode }) => { - const cssRule = config.module.rules.find(({ test }) => test.test('index.css')); - cssRule.use[1].options.url = (url, resourcePath) => { - if (/^(\.\/)?images\//.test(url)) { - return false; - } +const path = require('path'); + +const webpack = require('webpack'); - return true; - }; +module.exports = async ({ config }) => { + const cssRule = config.module.rules.find(({ test }) => test.test('index.css')); cssRule.use[2].options.plugins = [ require('postcss-custom-properties')({ preserve: true }), @@ -16,7 +13,36 @@ module.exports = async ({ config, mode }) => { require('postcss-selector-not')(), require('postcss-nested')(), require('autoprefixer')(), + require('postcss-url')({ url: ({ absolutePath, relativePath, url }) => { + const absoluteDir = absolutePath.slice(0, -relativePath.length); + const relativeDir = path.relative(absoluteDir, path.resolve(__dirname, '../public')); + const newPath = path.join(relativeDir, url); + return newPath; + } }), ]; - return config; + config.module.rules.push({ + test: /\.info$/, + type: 'json', + }); + + config.module.rules.push({ + test: /\.html$/, + use: '@settlin/spacebars-loader', + }); + + config.plugins.push(new webpack.NormalModuleReplacementPlugin( + /^meteor/, + require.resolve('./meteor.js'), + )); + + config.plugins.push(new webpack.NormalModuleReplacementPlugin( + /\.\/server\/index.js/, + require.resolve('./empty.js'), + )); + + config.mode = 'development'; + config.optimization.usedExports = true; + + return config; }; diff --git a/app/apps/client/admin/views.js b/app/apps/client/admin/views.js new file mode 100644 index 0000000000000000000000000000000000000000..83f4f0a0e69e52afc82051c7c006e026ccbecfa9 --- /dev/null +++ b/app/apps/client/admin/views.js @@ -0,0 +1,11 @@ +import './modalTemplates/iframeModal.html'; +import './modalTemplates/iframeModal'; +import './marketplace'; +import './apps'; +import './appInstall.html'; +import './appInstall'; +import './appLogs.html'; +import './appLogs'; +import './appManage'; +import './appWhatIsIt.html'; +import './appWhatIsIt'; diff --git a/app/apps/client/index.js b/app/apps/client/index.js index 887964154a900ee0bd72386f401662688e592b5b..a89134a70f5480e64084e78b1c06f086a5cd0a5c 100644 --- a/app/apps/client/index.js +++ b/app/apps/client/index.js @@ -1,14 +1,3 @@ -import './admin/modalTemplates/iframeModal.html'; -import './admin/modalTemplates/iframeModal'; -import './admin/marketplace'; -import './admin/apps'; -import './admin/appInstall.html'; -import './admin/appInstall'; -import './admin/appLogs.html'; -import './admin/appLogs'; -import './admin/appManage'; -import './admin/appWhatIsIt.html'; -import './admin/appWhatIsIt'; import './routes'; export { Apps } from './orchestrator'; diff --git a/app/apps/client/routes.js b/app/apps/client/routes.js index 1a44f4d74bffeb03d803a5fe21388d33b1b6b7ec..914137e5f72fcb00fadb3f1a9c581b0ed0d9c18d 100644 --- a/app/apps/client/routes.js +++ b/app/apps/client/routes.js @@ -7,6 +7,7 @@ FlowRouter.route('/admin/apps/what-is-it', { name: 'apps-what-is-it', action: async () => { // TODO: render loading indicator + await import('./admin/views'); if (await Apps.isEnabled()) { FlowRouter.go('apps'); } else { @@ -18,6 +19,7 @@ FlowRouter.route('/admin/apps/what-is-it', { const createAppsRouteAction = (centerTemplate) => async () => { // TODO: render loading indicator if (await Apps.isEnabled()) { + await import('./admin/views'); BlazeLayout.render('main', { center: centerTemplate, old: true }); // TODO remove old } else { FlowRouter.go('apps-what-is-it'); diff --git a/app/authorization/client/index.js b/app/authorization/client/index.js index 709df4e2f38c80cef8d3a187afd16624148ae797..7ff5353f1f7956ae534b5be4c78ae8ab5713494b 100644 --- a/app/authorization/client/index.js +++ b/app/authorization/client/index.js @@ -4,10 +4,6 @@ import './usersNameChanged'; import './requiresPermission.html'; import './route'; import './startup'; -import './views/permissions.html'; -import './views/permissions'; -import './views/permissionsRole.html'; -import './views/permissionsRole'; export { hasAllPermission, diff --git a/app/authorization/client/route.js b/app/authorization/client/route.js index 5d54d53c8888d264620582a4ab602eb168badf6f..2415242d6eb9e59803640712a3628f8a94dc0dbf 100644 --- a/app/authorization/client/route.js +++ b/app/authorization/client/route.js @@ -5,7 +5,8 @@ import { t } from '../../utils/client'; FlowRouter.route('/admin/permissions', { name: 'admin-permissions', - action(/* params*/) { + async action(/* params*/) { + await import('./views'); return BlazeLayout.render('main', { center: 'permissions', pageTitle: t('Permissions'), @@ -15,7 +16,8 @@ FlowRouter.route('/admin/permissions', { FlowRouter.route('/admin/permissions/:name?/edit', { name: 'admin-permissions-edit', - action(/* params*/) { + async action(/* params*/) { + await import('./views'); return BlazeLayout.render('main', { center: 'pageContainer', pageTitle: t('Role_Editing'), @@ -26,7 +28,8 @@ FlowRouter.route('/admin/permissions/:name?/edit', { FlowRouter.route('/admin/permissions/new', { name: 'admin-permissions-new', - action(/* params*/) { + async action(/* params*/) { + await import('./views'); return BlazeLayout.render('main', { center: 'pageContainer', pageTitle: t('Role_Editing'), diff --git a/app/authorization/client/views/index.js b/app/authorization/client/views/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ba54dffa5c020615b38e1f33577649bceb6a574f --- /dev/null +++ b/app/authorization/client/views/index.js @@ -0,0 +1,4 @@ +import './permissions.html'; +import './permissions'; +import './permissionsRole.html'; +import './permissionsRole'; diff --git a/app/callbacks/lib/callbacks.js b/app/callbacks/lib/callbacks.js index 193b6be06ed6f4a9e48125c8ccd9603470ef9700..efc44c0ee59dc53e090be090e0fbd74f9741ac6b 100644 --- a/app/callbacks/lib/callbacks.js +++ b/app/callbacks/lib/callbacks.js @@ -56,7 +56,7 @@ const createCallbackTimed = (hook, callbacks) => const create = (hook, cbs) => (timed ? createCallbackTimed(hook, cbs) : createCallback(hook, cbs)); const combinedCallbacks = new Map(); -this.combinedCallbacks = combinedCallbacks; + /* * Callback priorities */ diff --git a/app/cloud/client/admin/index.js b/app/cloud/client/admin/index.js new file mode 100644 index 0000000000000000000000000000000000000000..92cb6032c24ef91a09c3b4d2c36fb08eda0fd537 --- /dev/null +++ b/app/cloud/client/admin/index.js @@ -0,0 +1,2 @@ +import './cloud'; +import './callback'; diff --git a/app/cloud/client/index.js b/app/cloud/client/index.js index d0241a21c12e2e2ebc417510703e054d312d26a0..c757fa04a0b11bdb434368ee3128c542cb2ab354 100644 --- a/app/cloud/client/index.js +++ b/app/cloud/client/index.js @@ -1,6 +1,3 @@ -import './admin/callback'; -import './admin/cloud'; - import { BlazeLayout } from 'meteor/kadira:blaze-layout'; import { FlowRouter } from 'meteor/kadira:flow-router'; @@ -9,14 +6,16 @@ import { hasAtLeastOnePermission } from '../../authorization'; FlowRouter.route('/admin/cloud', { name: 'cloud-config', - action() { + async action() { + await import('./admin'); BlazeLayout.render('main', { center: 'cloud', old: true }); }, }); FlowRouter.route('/admin/cloud/oauth-callback', { name: 'cloud-oauth-callback', - action() { + async action() { + await import('./admin'); BlazeLayout.render('main', { center: 'cloudCallback', old: true }); }, }); diff --git a/app/custom-sounds/client/admin/route.js b/app/custom-sounds/client/admin/route.js index cf12f9949f6a84878776e5fe1cbdf0e8bc971ec9..5aebea1934f887430bc98a4cc5442b870afa46b6 100644 --- a/app/custom-sounds/client/admin/route.js +++ b/app/custom-sounds/client/admin/route.js @@ -7,7 +7,8 @@ FlowRouter.route('/admin/custom-sounds', { subscriptions(/* params, queryParams*/) { this.register('customSounds', Meteor.subscribe('customSounds')); }, - action(/* params*/) { + async action(/* params*/) { + await import('./views'); BlazeLayout.render('main', { center: 'adminSounds' }); }, }); diff --git a/app/custom-sounds/client/admin/views.js b/app/custom-sounds/client/admin/views.js new file mode 100644 index 0000000000000000000000000000000000000000..3a2397b2bdaa6c48443c4b0e75f44a963df53777 --- /dev/null +++ b/app/custom-sounds/client/admin/views.js @@ -0,0 +1,8 @@ +import './adminSoundEdit.html'; +import './adminSoundInfo.html'; +import './adminSounds.html'; +import './adminSounds'; +import './soundEdit.html'; +import './soundEdit'; +import './soundInfo.html'; +import './soundInfo'; diff --git a/app/custom-sounds/client/index.js b/app/custom-sounds/client/index.js index ca11995874f103131f15e6c74ced19c9e88bc2b9..918e3247240ca92bdde71a733de4768b3678c359 100644 --- a/app/custom-sounds/client/index.js +++ b/app/custom-sounds/client/index.js @@ -1,13 +1,5 @@ import './notifications/deleteCustomSound'; import './notifications/updateCustomSound'; -import './admin/adminSoundEdit.html'; -import './admin/adminSoundInfo.html'; -import './admin/adminSounds.html'; -import './admin/adminSounds'; -import './admin/soundEdit.html'; -import './admin/soundEdit'; -import './admin/soundInfo.html'; -import './admin/soundInfo'; import './admin/route'; import './admin/startup'; diff --git a/app/emoji-custom/client/admin/route.js b/app/emoji-custom/client/admin/route.js index 1b20c5a0abe2f3ac45fded4b934c188d8f674751..169ff2bb637a215815ce65c150dd522fd4f1dc7d 100644 --- a/app/emoji-custom/client/admin/route.js +++ b/app/emoji-custom/client/admin/route.js @@ -3,7 +3,8 @@ import { BlazeLayout } from 'meteor/kadira:blaze-layout'; FlowRouter.route('/admin/emoji-custom', { name: 'emoji-custom', - action(/* params*/) { + async action(/* params*/) { + await import('./views'); BlazeLayout.render('main', { center: 'adminEmoji' }); }, }); diff --git a/app/emoji-custom/client/admin/views.js b/app/emoji-custom/client/admin/views.js new file mode 100644 index 0000000000000000000000000000000000000000..9c058a4610eb345286faaeaa8fab9071a21abc09 --- /dev/null +++ b/app/emoji-custom/client/admin/views.js @@ -0,0 +1,9 @@ +import './adminEmoji.html'; +import './adminEmoji'; +import './adminEmojiEdit.html'; +import './adminEmojiInfo.html'; +import './emojiEdit.html'; +import './emojiEdit'; +import './emojiInfo.html'; +import './emojiInfo'; +import './emojiPreview.html'; diff --git a/app/emoji-custom/client/index.js b/app/emoji-custom/client/index.js index 06b3776947690c3fd85a76e0504d2650cae20b43..8b6f4fc9c0fc1b8831cb618dadb1bb181b46ac1c 100644 --- a/app/emoji-custom/client/index.js +++ b/app/emoji-custom/client/index.js @@ -2,13 +2,4 @@ import './lib/emojiCustom'; import './notifications/deleteEmojiCustom'; import './notifications/updateEmojiCustom'; import './admin/startup'; -import './admin/adminEmoji.html'; -import './admin/adminEmoji'; -import './admin/adminEmojiEdit.html'; -import './admin/adminEmojiInfo.html'; -import './admin/emojiEdit.html'; -import './admin/emojiEdit'; -import './admin/emojiInfo.html'; -import './admin/emojiInfo'; -import './admin/emojiPreview.html'; import './admin/route'; diff --git a/app/importer/client/admin/views.js b/app/importer/client/admin/views.js new file mode 100644 index 0000000000000000000000000000000000000000..5e6c2fc3ed0e483a3ff449714286d1f827d0f538 --- /dev/null +++ b/app/importer/client/admin/views.js @@ -0,0 +1,8 @@ +import './adminImport.html'; +import './adminImport'; +import './adminImportHistory.html'; +import './adminImportHistory'; +import './adminImportPrepare.html'; +import './adminImportPrepare'; +import './adminImportProgress.html'; +import './adminImportProgress'; diff --git a/app/importer/client/index.js b/app/importer/client/index.js index ff06c8ee496b17e5feac1d518b5db25ca1af5c1d..68c66ec4b4eabdc4c8a42e5255abbc056766bc2b 100644 --- a/app/importer/client/index.js +++ b/app/importer/client/index.js @@ -1,15 +1,43 @@ +import { FlowRouter } from 'meteor/kadira:flow-router'; +import { BlazeLayout } from 'meteor/kadira:blaze-layout'; + import { ImporterWebsocketReceiver } from './ImporterWebsocketReceiver'; import { Importers } from '../lib/Importers'; import { ImporterInfo } from '../lib/ImporterInfo'; import { ProgressStep } from '../lib/ImporterProgressStep'; -import './admin/adminImport.html'; -import './admin/adminImport'; -import './admin/adminImportHistory.html'; -import './admin/adminImportHistory'; -import './admin/adminImportPrepare.html'; -import './admin/adminImportPrepare'; -import './admin/adminImportProgress.html'; -import './admin/adminImportProgress'; + + +FlowRouter.route('/admin/import', { + name: 'admin-import', + async action() { + await import('./admin/views'); + BlazeLayout.render('main', { center: 'adminImport' }); + }, +}); + +FlowRouter.route('/admin/import/history', { + name: 'admin-import-history', + async action() { + await import('./admin/views'); + BlazeLayout.render('main', { center: 'adminImportHistory' }); + }, +}); + +FlowRouter.route('/admin/import/prepare/:importer', { + name: 'admin-import-prepare', + async action() { + await import('./admin/views'); + BlazeLayout.render('main', { center: 'adminImportPrepare' }); + }, +}); + +FlowRouter.route('/admin/import/progress/:importer', { + name: 'admin-import-progress', + async action() { + await import('./admin/views'); + BlazeLayout.render('main', { center: 'adminImportProgress' }); + }, +}); export { Importers, diff --git a/app/integrations/client/index.js b/app/integrations/client/index.js index 2da38377a2f02f601627f467dac20c4cae439300..87ac557c71d989d75ccdd840543732a73df3efd6 100644 --- a/app/integrations/client/index.js +++ b/app/integrations/client/index.js @@ -2,14 +2,3 @@ import '../lib/rocketchat'; import './collections'; import './startup'; import './route'; -import './views/integrations.html'; -import './views/integrations'; -import './views/integrationsNew.html'; -import './views/integrationsNew'; -import './views/integrationsIncoming.html'; -import './views/integrationsIncoming'; -import './views/integrationsOutgoing.html'; -import './views/integrationsOutgoing'; -import './views/integrationsOutgoingHistory.html'; -import './views/integrationsOutgoingHistory'; -import './views/additional/zapier.html'; diff --git a/app/integrations/client/route.js b/app/integrations/client/route.js index 944188db98cd4cad3a02860bef4f75bab77fb7a7..d9b85202579a8d72c926c04ca1a68f2ee824dc4d 100644 --- a/app/integrations/client/route.js +++ b/app/integrations/client/route.js @@ -4,12 +4,17 @@ import { BlazeLayout } from 'meteor/kadira:blaze-layout'; import { t } from '../../utils'; +const dynamic = () => { + import('./views'); +}; + FlowRouter.route('/admin/integrations', { name: 'admin-integrations', subscriptions() { this.register('integrations', Meteor.subscribe('integrations')); }, - action() { + async action() { + await dynamic(); return BlazeLayout.render('main', { center: 'integrations', pageTitle: t('Integrations'), @@ -22,7 +27,8 @@ FlowRouter.route('/admin/integrations/new', { subscriptions() { this.register('integrations', Meteor.subscribe('integrations')); }, - action() { + async action() { + await dynamic(); return BlazeLayout.render('main', { center: 'integrationsNew', pageTitle: t('Integration_New'), @@ -35,7 +41,8 @@ FlowRouter.route('/admin/integrations/incoming/:id?', { subscriptions() { this.register('integrations', Meteor.subscribe('integrations')); }, - action(params) { + async action(params) { + await dynamic(); return BlazeLayout.render('main', { center: 'pageSettingsContainer', pageTitle: t('Integration_Incoming_WebHook'), @@ -47,7 +54,8 @@ FlowRouter.route('/admin/integrations/incoming/:id?', { FlowRouter.route('/admin/integrations/outgoing/:id?', { name: 'admin-integrations-outgoing', - action(params) { + async action(params) { + await dynamic(); return BlazeLayout.render('main', { center: 'integrationsOutgoing', pageTitle: t('Integration_Outgoing_WebHook'), @@ -58,7 +66,8 @@ FlowRouter.route('/admin/integrations/outgoing/:id?', { FlowRouter.route('/admin/integrations/outgoing/:id?/history', { name: 'admin-integrations-outgoing-history', - action(params) { + async action(params) { + await dynamic(); return BlazeLayout.render('main', { center: 'integrationsOutgoingHistory', pageTitle: t('Integration_Outgoing_WebHook_History'), @@ -69,7 +78,8 @@ FlowRouter.route('/admin/integrations/outgoing/:id?/history', { FlowRouter.route('/admin/integrations/additional/zapier', { name: 'admin-integrations-additional-zapier', - action() { + async action() { + await dynamic(); BlazeLayout.render('main', { center: 'integrationsAdditionalZapier', }); diff --git a/app/integrations/client/views/index.js b/app/integrations/client/views/index.js new file mode 100644 index 0000000000000000000000000000000000000000..f7c6282cbd3538ca7746070f7cad628133428d47 --- /dev/null +++ b/app/integrations/client/views/index.js @@ -0,0 +1,11 @@ +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/logger/client/index.js b/app/logger/client/index.js index 1cdc33f64edfd81d684b5bb4416da782a065d2f4..689a3ac95d83db440427c5076fa2c21ad2b3c2ae 100644 --- a/app/logger/client/index.js +++ b/app/logger/client/index.js @@ -1,3 +1,2 @@ import './logger'; import './viewLogs'; -import './views/viewLogs'; diff --git a/app/logger/client/viewLogs.js b/app/logger/client/viewLogs.js index 112a947fc70b67e99058ce55fc5fde9118a2fa60..9c488140b920799345bf4ae62a538caa0bc9cffb 100644 --- a/app/logger/client/viewLogs.js +++ b/app/logger/client/viewLogs.js @@ -22,7 +22,8 @@ Meteor.startup(function() { FlowRouter.route('/admin/view-logs', { name: 'admin-view-logs', - action() { + async action() { + await import('./views/viewLogs'); return BlazeLayout.render('main', { center: 'pageSettingsContainer', pageTitle: t('View_Logs'), diff --git a/app/mail-messages/client/index.js b/app/mail-messages/client/index.js index 75419b8457309430f6af5d28863ab90db913551c..09634cf5172b24a8e3b611728a6dd6cf70eec9b1 100644 --- a/app/mail-messages/client/index.js +++ b/app/mail-messages/client/index.js @@ -1,6 +1,2 @@ import './startup'; import './router'; -import './views/mailer.html'; -import './views/mailer'; -import './views/mailerUnsubscribe.html'; -import './views/mailerUnsubscribe'; diff --git a/app/mail-messages/client/router.js b/app/mail-messages/client/router.js index 9e706f11be74ef826b01856fb832c9f568a1f951..fd738b632d8bde6ae4f78e813ac8c5eae2d409d1 100644 --- a/app/mail-messages/client/router.js +++ b/app/mail-messages/client/router.js @@ -4,7 +4,8 @@ import { BlazeLayout } from 'meteor/kadira:blaze-layout'; FlowRouter.route('/admin/mailer', { name: 'admin-mailer', - action() { + async action() { + await import('./views'); return BlazeLayout.render('main', { center: 'mailer', }); @@ -13,7 +14,8 @@ FlowRouter.route('/admin/mailer', { FlowRouter.route('/mailer/unsubscribe/:_id/:createdAt', { name: 'mailer-unsubscribe', - action(params) { + async action(params) { + await import('./views'); Meteor.call('Mailer:unsubscribe', params._id, params.createdAt); return BlazeLayout.render('mailerUnsubscribe'); }, diff --git a/app/mail-messages/client/views/index.js b/app/mail-messages/client/views/index.js new file mode 100644 index 0000000000000000000000000000000000000000..55bb6a5d7a7772c92fc108d87857d6a3de3b9e17 --- /dev/null +++ b/app/mail-messages/client/views/index.js @@ -0,0 +1,4 @@ +import './mailer.html'; +import './mailer'; +import './mailerUnsubscribe.html'; +import './mailerUnsubscribe'; diff --git a/app/oauth2-server-config/client/admin/route.js b/app/oauth2-server-config/client/admin/route.js index df568f2bca603c62f58f201bc757f144ed0e5d0a..340f403b935140821fae845bbe24dc6221860297 100644 --- a/app/oauth2-server-config/client/admin/route.js +++ b/app/oauth2-server-config/client/admin/route.js @@ -5,7 +5,8 @@ import { t } from '../../../utils'; FlowRouter.route('/admin/oauth-apps', { name: 'admin-oauth-apps', - action() { + async action() { + await import('./views'); return BlazeLayout.render('main', { center: 'oauthApps', pageTitle: t('OAuth_Applications'), @@ -15,7 +16,8 @@ FlowRouter.route('/admin/oauth-apps', { FlowRouter.route('/admin/oauth-app/:id?', { name: 'admin-oauth-app', - action(params) { + async action(params) { + await import('./views'); return BlazeLayout.render('main', { center: 'pageSettingsContainer', pageTitle: t('OAuth_Application'), diff --git a/app/oauth2-server-config/client/admin/views/index.js b/app/oauth2-server-config/client/admin/views/index.js new file mode 100644 index 0000000000000000000000000000000000000000..071605a56b89c37ce20723d7f3cac749408268c3 --- /dev/null +++ b/app/oauth2-server-config/client/admin/views/index.js @@ -0,0 +1,4 @@ +import './oauthApp.html'; +import './oauthApp'; +import './oauthApps.html'; +import './oauthApps'; diff --git a/app/oauth2-server-config/client/index.js b/app/oauth2-server-config/client/index.js index 27d8d4052ce88ce44c485411ee4ef3f0666bb354..1c579a2712b01b852111666f3a94a379e2cd1dbc 100644 --- a/app/oauth2-server-config/client/index.js +++ b/app/oauth2-server-config/client/index.js @@ -2,7 +2,3 @@ import './oauth/oauth2-client.html'; import './oauth/oauth2-client'; import './admin/startup'; import './admin/route'; -import './admin/views/oauthApp.html'; -import './admin/views/oauthApp'; -import './admin/views/oauthApps.html'; -import './admin/views/oauthApps'; diff --git a/app/theme/client/imports/general/base_old.css b/app/theme/client/imports/general/base_old.css index 71374c4145f96465f7a2c62cfcffb160c01b6b9f..183a7e9f732bdb1c9276153abbda2fe66b98300e 100644 --- a/app/theme/client/imports/general/base_old.css +++ b/app/theme/client/imports/general/base_old.css @@ -383,7 +383,7 @@ /* input & form styles */ -.rc-old input:focus { +.rc-old :not(.rcx-input-control):focus { outline: none; box-shadow: 0 0 0; } @@ -4196,20 +4196,6 @@ rc-old select, } } - & a.meteor { - position: fixed; - right: 30px; - bottom: 20px; - - width: 100px; - height: 50px; - - text-indent: -9999em; - - background: url(images/meteor.png) no-repeat center center; - background-size: 100% auto; - } - & .share { min-height: 40px; diff --git a/app/theme/client/vendor/fontello/css/fontello.css b/app/theme/client/vendor/fontello/css/fontello.css index 0caceef9127f7d89d165ead214b75e0562c6a307..47c2859f0c774542268b0d7e06c4792ce5af86b0 100755 --- a/app/theme/client/vendor/fontello/css/fontello.css +++ b/app/theme/client/vendor/fontello/css/fontello.css @@ -1,60 +1,50 @@ @font-face { font-family: 'fontello'; - src: url('../font/fontello.eot?9377982'); - src: url('../font/fontello.eot?9377982#iefix') format('embedded-opentype'), - url('../font/fontello.woff2?9377982') format('woff2'), - url('../font/fontello.woff?9377982') format('woff'), - url('../font/fontello.ttf?9377982') format('truetype'), - url('../font/fontello.svg?9377982#fontello') format('svg'); + src: url('/font/fontello.eot'); + src: url('/font/fontello.eot#iefix') format('embedded-opentype'), + url('/font/fontello.woff2') format('woff2'), + url('/font/fontello.woff') format('woff'), + url('/font/fontello.ttf') format('truetype'), + url('/font/fontello.svg#fontello') format('svg'); font-weight: normal; font-style: normal; } -/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ -/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ -/* -@media screen and (-webkit-min-device-pixel-ratio:0) { - @font-face { - font-family: 'fontello'; - src: url('../font/fontello.svg?9377982#fontello') format('svg'); - } -} -*/ - + [class^="icon-"]:before, [class*=" icon-"]:before { font-family: "fontello"; font-style: normal; font-weight: normal; speak: none; - + display: inline-block; text-decoration: inherit; width: 1em; margin-right: .2em; text-align: center; /* opacity: .8; */ - + /* For safety - reset parent styles, that can break glyph codes*/ font-variant: normal; text-transform: none; - + /* fix buttons height, for twitter bootstrap */ line-height: 1em; - + /* Animation center compensation - margins should be symmetric */ /* remove if not needed */ margin-left: .2em; - + /* you can be more comfortable with increased icons size */ /* font-size: 120%; */ - + /* Font smoothing. That was taken from TWBS */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - + /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } - + .icon-parking:before { content: '\21'; } /* '!' */ .icon-bedroom:before { content: '\22'; } /* '"' */ .icon-elevator:before { content: '\23'; } /* '#' */ @@ -540,4 +530,4 @@ .icon-markdown:before { content: '\e98c'; } /* '' */ .icon-no-newline:before { content: '\e98d'; } /* 'î¦' */ .icon-tools:before { content: '\e98e'; } /* '' */ -.icon-tape:before { content: '\e98f'; } /* 'î¦' */ \ No newline at end of file +.icon-tape:before { content: '\e98f'; } /* 'î¦' */ diff --git a/app/ui-admin/client/SettingsCachedCollection.js b/app/ui-admin/client/SettingsCachedCollection.js index edfbb64c69fb3c54440b299fd637e932d52ff1c8..6637eee28940e9559ad7a903b032db0887308c8c 100644 --- a/app/ui-admin/client/SettingsCachedCollection.js +++ b/app/ui-admin/client/SettingsCachedCollection.js @@ -6,7 +6,6 @@ export class PrivateSettingsCachedCollection extends CachedCollection { super({ name: 'private-settings', eventType: 'onLogged', - useCache: false, }); } diff --git a/app/ui-admin/client/index.js b/app/ui-admin/client/index.js index 2a0a65da65cba4798ae5483d516dc0b09194da24..8f4ee8618186845dbbbc20a90b18160843c06ced 100644 --- a/app/ui-admin/client/index.js +++ b/app/ui-admin/client/index.js @@ -1,18 +1,9 @@ import './admin.html'; import './adminFlex.html'; -import './rooms/adminRooms.html'; -import './rooms/adminRoomInfo.html'; -import './rooms/adminRoomInfo'; -import './rooms/channelSettingsDefault.html'; -import './rooms/channelSettingsDefault'; -import './users/adminInviteUser.html'; -import './users/adminUserChannels.html'; -import './users/adminUserEdit.html'; -import './users/adminUserInfo.html'; -import './users/adminUsers.html'; import './admin'; import './adminFlex'; -import './rooms/adminRooms'; -import './users/adminInviteUser'; -import './users/adminUserChannels'; -import './users/adminUsers'; +import './routes'; + + +// import './users/adminUserChannels'; +// import './users/adminUserChannels.html'; diff --git a/app/ui-admin/client/rooms/views.js b/app/ui-admin/client/rooms/views.js new file mode 100644 index 0000000000000000000000000000000000000000..cfd9eee52505e5ace807a7486fb54c73cddef995 --- /dev/null +++ b/app/ui-admin/client/rooms/views.js @@ -0,0 +1,6 @@ +import './adminRooms.html'; +import './adminRoomInfo.html'; +import './adminRoomInfo'; +import './channelSettingsDefault.html'; +import './channelSettingsDefault'; +import './adminRooms'; diff --git a/app/ui-admin/client/routes.js b/app/ui-admin/client/routes.js new file mode 100644 index 0000000000000000000000000000000000000000..cf87a26258f5dd8eff8d3f5cab83b18791e09937 --- /dev/null +++ b/app/ui-admin/client/routes.js @@ -0,0 +1,19 @@ +import { FlowRouter } from 'meteor/kadira:flow-router'; +import { BlazeLayout } from 'meteor/kadira:blaze-layout'; + +FlowRouter.route('/admin/users', { + name: 'admin-users', + async action() { + await import('./users/views'); + BlazeLayout.render('main', { center: 'adminUsers' }); + }, +}); + + +FlowRouter.route('/admin/rooms', { + name: 'admin-rooms', + async action() { + await import('./rooms/views'); + BlazeLayout.render('main', { center: 'adminRooms' }); + }, +}); diff --git a/app/ui-admin/client/users/adminUserChannels.html b/app/ui-admin/client/users/adminUserChannels.html deleted file mode 100644 index a1b85e7fc76f378634c5b952aadd090588199be2..0000000000000000000000000000000000000000 --- a/app/ui-admin/client/users/adminUserChannels.html +++ /dev/null @@ -1,9 +0,0 @@ -<template name="adminUserChannels"> - {{#unless hasPermission 'view-full-other-user-info'}} - <p>{{_ "You_are_not_authorized_to_view_this_page"}}</p> - {{else}} - <div class="user-info-channel"> - <h3><a href="{{route}}"><i class="icon-{{type}}"></i> {{name}}</a></h3> - </div> - {{/unless}} -</template> \ No newline at end of file diff --git a/app/ui-admin/client/users/adminUserChannels.js b/app/ui-admin/client/users/adminUserChannels.js deleted file mode 100644 index 3eeacc50e7a33096b54459712fbba992e820c71e..0000000000000000000000000000000000000000 --- a/app/ui-admin/client/users/adminUserChannels.js +++ /dev/null @@ -1,29 +0,0 @@ -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { Template } from 'meteor/templating'; - -Template.adminUserChannels.helpers({ - type() { - if (this.t === 'd') { - return 'at'; - } if (this.t === 'p') { - return 'lock'; - } - return 'hash'; - }, - route() { - switch (this.t) { - case 'd': - return FlowRouter.path('direct', { - username: this.name, - }); - case 'p': - return FlowRouter.path('group', { - name: this.name, - }); - case 'c': - return FlowRouter.path('channel', { - name: this.name, - }); - } - }, -}); diff --git a/app/ui-admin/client/users/views.js b/app/ui-admin/client/users/views.js new file mode 100644 index 0000000000000000000000000000000000000000..da3c6d5414b18652062e073bdeeb9d42f057d4e9 --- /dev/null +++ b/app/ui-admin/client/users/views.js @@ -0,0 +1,6 @@ +import './adminInviteUser.html'; +import './adminUserEdit.html'; +import './adminUserInfo.html'; +import './adminUsers.html'; +import './adminInviteUser'; +import './adminUsers'; diff --git a/app/ui-cached-collection/client/models/CachedCollection.js b/app/ui-cached-collection/client/models/CachedCollection.js index 9dfa24856c020874177b39b5368a70a1ec230974..ea305ba81c00f765f6936f4a9dcbe7ee45edbe67 100644 --- a/app/ui-cached-collection/client/models/CachedCollection.js +++ b/app/ui-cached-collection/client/models/CachedCollection.js @@ -131,7 +131,6 @@ export class CachedCollection extends EventEmitter { userRelated = true, listenChangesForLoggedUsersOnly = false, useSync = true, - useCache = true, version = 8, maxCacheTime = 60 * 60 * 24 * 30, onSyncData = (/* action, record */) => {}, @@ -146,7 +145,6 @@ export class CachedCollection extends EventEmitter { this.eventName = eventName || `${ name }-changed`; this.eventType = eventType; this.useSync = useSync; - this.useCache = useCache; this.listenChangesForLoggedUsersOnly = listenChangesForLoggedUsersOnly; this.version = version; this.userRelated = userRelated; diff --git a/app/user-status/client/admin/route.js b/app/user-status/client/admin/route.js index d5c8c6be1e21a7e2daefd48a15233433b1481a35..fec4bab8d92c1c40a16eb4b68bd6de19f0569962 100644 --- a/app/user-status/client/admin/route.js +++ b/app/user-status/client/admin/route.js @@ -3,7 +3,8 @@ import { BlazeLayout } from 'meteor/kadira:blaze-layout'; FlowRouter.route('/admin/user-status-custom', { name: 'user-status-custom', - action(/* params */) { + async action(/* params */) { + await import('./views'); BlazeLayout.render('main', { center: 'adminUserStatus' }); }, }); diff --git a/app/user-status/client/admin/views.js b/app/user-status/client/admin/views.js new file mode 100644 index 0000000000000000000000000000000000000000..f7a4098c9b9d9f2cc203044e14aad6f412bee3fb --- /dev/null +++ b/app/user-status/client/admin/views.js @@ -0,0 +1,9 @@ +import './adminUserStatus.html'; +import './adminUserStatus'; +import './adminUserStatusEdit.html'; +import './adminUserStatusInfo.html'; +import './userStatusEdit.html'; +import './userStatusEdit'; +import './userStatusInfo.html'; +import './userStatusInfo'; +import './userStatusPreview.html'; diff --git a/app/user-status/client/index.js b/app/user-status/client/index.js index cd0736a72021e9f27874c1b8bc9b8cb688e96b7a..84c2a9c7579d1eca33ce61e4fd4576be305911f7 100644 --- a/app/user-status/client/index.js +++ b/app/user-status/client/index.js @@ -1,12 +1,3 @@ -import './admin/adminUserStatus.html'; -import './admin/adminUserStatus'; -import './admin/adminUserStatusEdit.html'; -import './admin/adminUserStatusInfo.html'; -import './admin/userStatusEdit.html'; -import './admin/userStatusEdit'; -import './admin/userStatusInfo.html'; -import './admin/userStatusInfo'; -import './admin/userStatusPreview.html'; import './admin/route'; import './admin/startup'; diff --git a/client/RocketChat.font.css b/client/RocketChat.font.css deleted file mode 100644 index 7b9074ad89b9c7279d7d92898ef12a7927c67558..0000000000000000000000000000000000000000 --- a/client/RocketChat.font.css +++ /dev/null @@ -1,14 +0,0 @@ -@font-face { - font-family: 'RocketChat'; - font-weight: 400; - font-style: normal; - font-display: auto; - - src: url('/fonts/RocketChat.eot'); - src: - url('/fonts/RocketChat.eot?#iefix') format('embedded-opentype'), - url('/fonts/RocketChat.woff2') format('woff2'), - url('/fonts/RocketChat.woff') format('woff'), - url('/fonts/RocketChat.ttf') format('truetype'), - url('/fonts/RocketChat.svg#RocketChat') format('svg'); -} diff --git a/client/components/admin/hooks.js b/client/components/admin/hooks.js new file mode 100644 index 0000000000000000000000000000000000000000..da2ac3b93ef7a8b143459797dfe5f84c69ab3668 --- /dev/null +++ b/client/components/admin/hooks.js @@ -0,0 +1,10 @@ +import { useEffect } from 'react'; + +import { SideNav } from '../../../app/ui-utils/client'; + +export const useAdminSideNav = () => { + useEffect(() => { + SideNav.setFlex('adminFlex'); + SideNav.openFlex(); + }, []); +}; diff --git a/client/components/admin/info/BuildEnvironmentSection.js b/client/components/admin/info/BuildEnvironmentSection.js index 22163c75ec2e76c17d6381e3f3211b2d13e67d8d..140ac47b98aa98d7f28983afe26a7bcdf5a1e7ff 100644 --- a/client/components/admin/info/BuildEnvironmentSection.js +++ b/client/components/admin/info/BuildEnvironmentSection.js @@ -1,8 +1,7 @@ import React from 'react'; -import { useTranslation } from '../../contexts/TranslationContext'; -import { InformationList } from './InformationList'; -import { InformationEntry } from './InformationEntry'; +import { useTranslation } from '../../providers/TranslationProvider'; +import { DescriptionList } from './DescriptionList'; import { formatDate } from './formatters'; export function BuildEnvironmentSection({ info }) { @@ -11,12 +10,12 @@ export function BuildEnvironmentSection({ info }) { return <> <h3>{t('Build_Environment')}</h3> - <InformationList> - <InformationEntry label={t('OS_Platform')}>{build.platform}</InformationEntry> - <InformationEntry label={t('OS_Arch')}>{build.arch}</InformationEntry> - <InformationEntry label={t('OS_Release')}>{build.osRelease}</InformationEntry> - <InformationEntry label={t('Node_version')}>{build.nodeVersion}</InformationEntry> - <InformationEntry label={t('Date')}>{formatDate(build.date)}</InformationEntry> - </InformationList> + <DescriptionList> + <DescriptionList.Entry label={t('OS_Platform')}>{build.platform}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Arch')}>{build.arch}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Release')}>{build.osRelease}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Node_version')}>{build.nodeVersion}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Date')}>{formatDate(build.date)}</DescriptionList.Entry> + </DescriptionList> </>; } diff --git a/client/components/admin/info/BuildEnvironmentSection.stories.js b/client/components/admin/info/BuildEnvironmentSection.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..b825ffd1751fab652c1db076ef626b46e45df891 --- /dev/null +++ b/client/components/admin/info/BuildEnvironmentSection.stories.js @@ -0,0 +1,24 @@ +import React from 'react'; + +import { dummyDate } from '../../../../.storybook/helpers'; +import { BuildEnvironmentSection } from './BuildEnvironmentSection'; + +export default { + title: 'admin/info/BuildEnvironmentSection', + component: BuildEnvironmentSection, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + ], +}; + +const info = { + compile: { + platform: 'info.compile.platform', + arch: 'info.compile.arch', + osRelease: 'info.compile.osRelease', + nodeVersion: 'info.compile.nodeVersion', + date: dummyDate, + }, +}; + +export const _default = () => <BuildEnvironmentSection info={info} />; diff --git a/client/components/admin/info/CommitSection.js b/client/components/admin/info/CommitSection.js index f814bc5c7037716e871f114952dc311476043e68..1617c422c63ee3a19ecf0f9e2b64f2320b6c336b 100644 --- a/client/components/admin/info/CommitSection.js +++ b/client/components/admin/info/CommitSection.js @@ -1,8 +1,7 @@ import React from 'react'; -import { useTranslation } from '../../contexts/TranslationContext'; -import { InformationList } from './InformationList'; -import { InformationEntry } from './InformationEntry'; +import { useTranslation } from '../../providers/TranslationProvider'; +import { DescriptionList } from './DescriptionList'; export function CommitSection({ info }) { const t = useTranslation(); @@ -10,13 +9,13 @@ export function CommitSection({ info }) { return <> <h3>{t('Commit')}</h3> - <InformationList> - <InformationEntry label={t('Hash')}>{commit.hash}</InformationEntry> - <InformationEntry label={t('Date')}>{commit.date}</InformationEntry> - <InformationEntry label={t('Branch')}>{commit.branch}</InformationEntry> - <InformationEntry label={t('Tag')}>{commit.tag}</InformationEntry> - <InformationEntry label={t('Author')}>{commit.author}</InformationEntry> - <InformationEntry label={t('Subject')}>{commit.subject}</InformationEntry> - </InformationList> + <DescriptionList> + <DescriptionList.Entry label={t('Hash')}>{commit.hash}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Date')}>{commit.date}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Branch')}>{commit.branch}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Tag')}>{commit.tag}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Author')}>{commit.author}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Subject')}>{commit.subject}</DescriptionList.Entry> + </DescriptionList> </>; } diff --git a/client/components/admin/info/CommitSection.stories.js b/client/components/admin/info/CommitSection.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..80f1d1133fc01f67b3d128d32a6b2000367dddba --- /dev/null +++ b/client/components/admin/info/CommitSection.stories.js @@ -0,0 +1,24 @@ +import React from 'react'; + +import { CommitSection } from './CommitSection'; + +export default { + title: 'admin/info/CommitSection', + component: CommitSection, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + ], +}; + +const info = { + commit: { + hash: 'info.commit.hash', + date: 'info.commit.date', + branch: 'info.commit.branch', + tag: 'info.commit.tag', + author: 'info.commit.author', + subject: 'info.commit.subject', + }, +}; + +export const _default = () => <CommitSection info={info} />; diff --git a/client/components/admin/info/DescriptionList.js b/client/components/admin/info/DescriptionList.js new file mode 100644 index 0000000000000000000000000000000000000000..af12fe4d34122038a4be378ebb6b70299c7e4855 --- /dev/null +++ b/client/components/admin/info/DescriptionList.js @@ -0,0 +1,16 @@ +import React from 'react'; + +export const DescriptionList = ({ children }) => + <table className='statistics-table secondary-background-color'> + <tbody> + {children} + </tbody> + </table>; + +const Entry = ({ children, label }) => + <tr className='admin-table-row'> + <th className='content-background-color border-component-color'>{label}</th> + <td className='border-component-color'>{children}</td> + </tr>; + +DescriptionList.Entry = Entry; diff --git a/client/components/admin/info/DescriptionList.stories.js b/client/components/admin/info/DescriptionList.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..0db82d0d5e365ab5512a1b08713d719dcf5aa019 --- /dev/null +++ b/client/components/admin/info/DescriptionList.stories.js @@ -0,0 +1,20 @@ +import React from 'react'; + +import { DescriptionList } from './DescriptionList'; + +export default { + title: 'admin/info/DescriptionList', + component: DescriptionList, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + (fn) => <section className='page-container page-list'> + <div className='content'> + {fn()} + </div> + </section>, + ], +}; + +export const _default = () => <DescriptionList> + <DescriptionList.Entry label='Key'>Value</DescriptionList.Entry> +</DescriptionList>; diff --git a/client/components/admin/info/InformationEntry.js b/client/components/admin/info/InformationEntry.js deleted file mode 100644 index bb90111ed1d4d782e4cee0770787b5b7fa8320c7..0000000000000000000000000000000000000000 --- a/client/components/admin/info/InformationEntry.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export const InformationEntry = ({ children, label }) => - <tr className='admin-table-row'> - <th className='content-background-color border-component-color'>{label}</th> - <td className='border-component-color'>{children}</td> - </tr>; diff --git a/client/components/admin/info/InformationList.js b/client/components/admin/info/InformationList.js deleted file mode 100644 index 7cbc85048acd0f69ed118519f29ca2325c252a68..0000000000000000000000000000000000000000 --- a/client/components/admin/info/InformationList.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; - -export const InformationList = ({ children }) => - <table className='statistics-table secondary-background-color'> - <tbody> - {children} - </tbody> - </table>; diff --git a/client/components/admin/info/InformationPage.js b/client/components/admin/info/InformationPage.js index cdcc1280651130b14ce5e2250f612eb6974ccd45..cd564cc2ecb6cb74f17a5178d759cbf0dedd57c1 100644 --- a/client/components/admin/info/InformationPage.js +++ b/client/components/admin/info/InformationPage.js @@ -1,15 +1,10 @@ import { Button, Icon } from '@rocket.chat/fuselage'; -import React, { useEffect, useState } from 'react'; +import React from 'react'; -import { call } from '../../../../app/ui-utils/client/lib/callMethod'; -import { useViewStatisticsPermission } from '../../../hooks/usePermissions'; -import { useReactiveValue } from '../../../hooks/useReactiveValue'; -import { Info } from '../../../../app/utils'; -import { SideNav } from '../../../../app/ui-utils/client/lib/SideNav'; -import { Header } from '../../header/Header'; import { Link } from '../../basic/Link'; import { ErrorAlert } from '../../basic/ErrorAlert'; -import { useTranslation } from '../../contexts/TranslationContext'; +import { Header } from '../../header/Header'; +import { useTranslation } from '../../providers/TranslationProvider'; import { RocketChatSection } from './RocketChatSection'; import { CommitSection } from './CommitSection'; import { RuntimeEnvironmentSection } from './RuntimeEnvironmentSection'; @@ -17,95 +12,30 @@ import { BuildEnvironmentSection } from './BuildEnvironmentSection'; import { UsageSection } from './UsageSection'; import { InstancesSection } from './InstancesSection'; -const useStatistics = (canViewStatistics) => { - const [isLoading, setLoading] = useState(true); - const [statistics, setStatistics] = useState({}); - const [instances, setInstances] = useState([]); - const [fetchStatistics, setFetchStatistics] = useState(() => () => ({})); - - useEffect(() => { - let didCancel = false; - - const fetchStatistics = async () => { - if (!canViewStatistics) { - setStatistics(null); - setInstances(null); - return; - } - - setLoading(true); - - try { - const [statistics, instances] = await Promise.all([ - call('getStatistics'), - call('instances/get'), - ]); - - if (didCancel) { - return; - } - - setStatistics(statistics); - setInstances(instances); - } finally { - setLoading(false); - } - }; - - setFetchStatistics(() => fetchStatistics); - - fetchStatistics(); - - return () => { - didCancel = true; - }; - }, [canViewStatistics]); - - return { - isLoading, - statistics, - instances, - fetchStatistics, - }; -}; - -export function InformationPage() { - const canViewStatistics = useViewStatisticsPermission(); - - const { - isLoading, - statistics, - instances, - fetchStatistics, - } = useStatistics(canViewStatistics); - - const info = useReactiveValue(() => Info, []); - +export function InformationPage({ + canViewStatistics, + isLoading, + info, + statistics, + instances, + onClickRefreshButton, +}) { const t = useTranslation(); - const handleRefreshClick = () => { - if (isLoading) { - return; - } - - fetchStatistics(); - }; - - useEffect(() => { - SideNav.setFlex('adminFlex'); - SideNav.openFlex(); - }, []); + if (!info) { + return null; + } const alertOplogForMultipleInstances = statistics && statistics.instanceCount > 1 && !statistics.oplogEnabled; - return <section className='page-container page-list Admin__InformationPage'> + return <section className='page-container'> <Header rawSectionName={t('Info')} hideHelp> {canViewStatistics - && <div className='rc-header__block rc-header__block-action'> - <Button primary type='button' onClick={handleRefreshClick}> - <Icon iconName='reload' /> {t('Refresh')} + && <Header.ActionBlock> + <Button disabled={isLoading} primary type='button' onClick={onClickRefreshButton}> + <Icon name='reload' /> {t('Refresh')} </Button> - </div>} + </Header.ActionBlock>} </Header> <div className='content'> @@ -121,11 +51,11 @@ export function InformationPage() { </p> </ErrorAlert>} - <RocketChatSection info={info} statistics={statistics} isLoading={isLoading} /> + {canViewStatistics && <RocketChatSection info={info} statistics={statistics} isLoading={isLoading} />} <CommitSection info={info} /> - <RuntimeEnvironmentSection statistics={statistics} isLoading={isLoading} /> + {canViewStatistics && <RuntimeEnvironmentSection statistics={statistics} isLoading={isLoading} />} <BuildEnvironmentSection info={info} /> - <UsageSection statistics={statistics} isLoading={isLoading} /> + {canViewStatistics && <UsageSection statistics={statistics} isLoading={isLoading} />} <InstancesSection instances={instances} /> </div> </section>; diff --git a/client/components/admin/info/InformationPage.stories.js b/client/components/admin/info/InformationPage.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..e85c6b9957dd433fb62061aad819ca729fc6335d --- /dev/null +++ b/client/components/admin/info/InformationPage.stories.js @@ -0,0 +1,151 @@ +import { action } from '@storybook/addon-actions'; +import { boolean, object } from '@storybook/addon-knobs/react'; +import React from 'react'; + +import { dummyDate } from '../../../../.storybook/helpers'; +import { InformationPage } from './InformationPage'; + +export default { + title: 'admin/info/InformationPage', + component: InformationPage, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + ], +}; + +const info = { + marketplaceApiVersion: 'info.marketplaceApiVersion', + commit: { + hash: 'info.commit.hash', + date: 'info.commit.date', + branch: 'info.commit.branch', + tag: 'info.commit.tag', + author: 'info.commit.author', + subject: 'info.commit.subject', + }, + compile: { + platform: 'info.compile.platform', + arch: 'info.compile.arch', + osRelease: 'info.compile.osRelease', + nodeVersion: 'info.compile.nodeVersion', + date: dummyDate, + }, +}; + +const statistics = { + version: 'statistics.version', + migration: { + version: 'statistics.migration.version', + lockedAt: dummyDate, + }, + installedAt: dummyDate, + process: { + nodeVersion: 'statistics.process.nodeVersion', + uptime: 10 * 24 * 60 * 60, + pid: 'statistics.process.pid', + }, + uniqueId: 'statistics.uniqueId', + instanceCount: 1, + oplogEnabled: true, + os: { + type: 'statistics.os.type', + platform: 'statistics.os.platform', + arch: 'statistics.os.arch', + release: 'statistics.os.release', + uptime: 10 * 24 * 60 * 60, + loadavg: [1.1, 1.5, 1.15], + totalmem: 1024, + freemem: 1024, + cpus: [{}], + }, + mongoVersion: 'statistics.mongoVersion', + mongoStorageEngine: 'statistics.mongoStorageEngine', + totalUsers: 'statistics.totalUsers', + nonActiveUsers: 'nonActiveUsers', + activeUsers: 'statistics.activeUsers', + totalConnectedUsers: 'statistics.totalConnectedUsers', + onlineUsers: 'statistics.onlineUsers', + awayUsers: 'statistics.awayUsers', + offlineUsers: 'statistics.offlineUsers', + totalRooms: 'statistics.totalRooms', + totalChannels: 'statistics.totalChannels', + totalPrivateGroups: 'statistics.totalPrivateGroups', + totalDirect: 'statistics.totalDirect', + totalLivechat: 'statistics.totalLivechat', + totalDiscussions: 'statistics.totalDiscussions', + totalThreads: 'statistics.totalThreads', + totalMessages: 'statistics.totalMessages', + totalChannelMessages: 'statistics.totalChannelMessages', + totalPrivateGroupMessages: 'statistics.totalPrivateGroupMessages', + totalDirectMessages: 'statistics.totalDirectMessages', + totalLivechatMessages: 'statistics.totalLivechatMessages', + uploadsTotal: 'statistics.uploadsTotal', + uploadsTotalSize: 1024, + integrations: { + totalIntegrations: 'statistics.integrations.totalIntegrations', + totalIncoming: 'statistics.integrations.totalIncoming', + totalIncomingActive: 'statistics.integrations.totalIncomingActive', + totalOutgoing: 'statistics.integrations.totalOutgoing', + totalOutgoingActive: 'statistics.integrations.totalOutgoingActive', + totalWithScriptEnabled: 'statistics.integrations.totalWithScriptEnabled', + }, +}; + +const instances = [ + { + address: 'instances[].address', + broadcastAuth: 'instances[].broadcastAuth', + currentStatus: { + connected: 'instances[].currentStatus.connected', + retryCount: 'instances[].currentStatus.retryCount', + status: 'instances[].currentStatus.status', + }, + instanceRecord: { + _id: 'instances[].instanceRecord._id', + pid: 'instances[].instanceRecord.pid', + _createdAt: dummyDate, + _updatedAt: dummyDate, + }, + }, +]; + +export const _default = () => + <InformationPage + canViewStatistics={boolean('canViewStatistics', true)} + isLoading={boolean('isLoading', false)} + info={object('info', info)} + statistics={object('statistics', statistics)} + instances={object('instances', instances)} + onClickRefreshButton={action('clickRefreshButton')} + />; + +export const withoutCanViewStatisticsPermission = () => + <InformationPage + info={info} + onClickRefreshButton={action('clickRefreshButton')} + />; + +export const loading = () => + <InformationPage + canViewStatistics + isLoading + info={info} + onClickRefreshButton={action('clickRefreshButton')} + />; + +export const withStatistics = () => + <InformationPage + canViewStatistics + info={info} + statistics={statistics} + onClickRefreshButton={action('clickRefreshButton')} + />; + +export const withOneInstance = () => + <InformationPage + canViewStatistics + info={info} + statistics={statistics} + instances={instances} + onClickRefreshButton={action('clickRefreshButton')} + />; diff --git a/client/components/admin/info/InformationRoute.js b/client/components/admin/info/InformationRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..4442c7e61dba1619e4b22a2e96456b432cd0dcec --- /dev/null +++ b/client/components/admin/info/InformationRoute.js @@ -0,0 +1,77 @@ +import React, { useState, useEffect } from 'react'; + +import { useMethod } from '../../../hooks/useMethod'; +import { useViewStatisticsPermission } from '../../../hooks/usePermissions'; +import { useRocketChatInformation } from '../../../hooks/useRocketChatInformation'; +import { useAdminSideNav } from '../hooks'; +import { InformationPage } from './InformationPage'; + +export function InformationRoute() { + useAdminSideNav(); + + const canViewStatistics = useViewStatisticsPermission(); + + const [isLoading, setLoading] = useState(true); + const [statistics, setStatistics] = useState({}); + const [instances, setInstances] = useState([]); + const [fetchStatistics, setFetchStatistics] = useState(() => () => ({})); + const getStatistics = useMethod('getStatistics'); + const getInstances = useMethod('instances/get'); + + useEffect(() => { + let didCancel = false; + + const fetchStatistics = async () => { + if (!canViewStatistics) { + setStatistics(null); + setInstances(null); + return; + } + + setLoading(true); + + try { + const [statistics, instances] = await Promise.all([ + getStatistics(), + getInstances(), + ]); + + if (didCancel) { + return; + } + + setStatistics(statistics); + setInstances(instances); + } finally { + setLoading(false); + } + }; + + setFetchStatistics(() => fetchStatistics); + + fetchStatistics(); + + return () => { + didCancel = true; + }; + }, [canViewStatistics]); + + const info = useRocketChatInformation(); + + const handleClickRefreshButton = () => { + if (isLoading) { + return; + } + + fetchStatistics(); + }; + + return <InformationPage + canViewStatistics={canViewStatistics} + isLoading={isLoading} + info={info} + statistics={statistics} + instances={instances} + onClickRefreshButton={handleClickRefreshButton} + />; +} diff --git a/client/components/admin/info/InstancesSection.js b/client/components/admin/info/InstancesSection.js index 855d2c9520b2b4b79fe8f0a0998d91a1d43d1c5a..087f1d0b39d80c6f6f5e1794f8bc88a9f8e27309 100644 --- a/client/components/admin/info/InstancesSection.js +++ b/client/components/admin/info/InstancesSection.js @@ -1,9 +1,8 @@ import React from 'react'; +import { useTranslation } from '../../providers/TranslationProvider'; +import { DescriptionList } from './DescriptionList'; import { formatDate } from './formatters'; -import { useTranslation } from '../../contexts/TranslationContext'; -import { InformationList } from './InformationList'; -import { InformationEntry } from './InformationEntry'; export function InstancesSection({ instances }) { const t = useTranslation(); @@ -15,17 +14,17 @@ export function InstancesSection({ instances }) { return <> <h3>{t('Broadcast_Connected_Instances')}</h3> {instances.map(({ address, broadcastAuth, currentStatus, instanceRecord }, i) => - <InformationList key={i}> - <InformationEntry label={t('Address')}>{address}</InformationEntry> - <InformationEntry label={t('Auth')}>{broadcastAuth ? 'true' : 'false'}</InformationEntry> - <InformationEntry label={<>{t('Current_Status')} > {t('Connected')}</>}>{currentStatus.connected ? 'true' : 'false'}</InformationEntry> - <InformationEntry label={<>{t('Current_Status')} > {t('Retry_Count')}</>}>{currentStatus.retryCount}</InformationEntry> - <InformationEntry label={<>{t('Current_Status')} > {t('Status')}</>}>{currentStatus.status}</InformationEntry> - <InformationEntry label={<>{t('Instance_Record')} > {t('ID')}</>}>{instanceRecord._id}</InformationEntry> - <InformationEntry label={<>{t('Instance_Record')} > {t('PID')}</>}>{instanceRecord.pid}</InformationEntry> - <InformationEntry label={<>{t('Instance_Record')} > {t('Created_at')}</>}>{formatDate(instanceRecord._createdAt)}</InformationEntry> - <InformationEntry label={<>{t('Instance_Record')} > {t('Updated_at')}</>}>{formatDate(instanceRecord._updatedAt)}</InformationEntry> - </InformationList> + <DescriptionList key={i}> + <DescriptionList.Entry label={t('Address')}>{address}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Auth')}>{broadcastAuth ? 'true' : 'false'}</DescriptionList.Entry> + <DescriptionList.Entry label={<>{t('Current_Status')} > {t('Connected')}</>}>{currentStatus.connected ? 'true' : 'false'}</DescriptionList.Entry> + <DescriptionList.Entry label={<>{t('Current_Status')} > {t('Retry_Count')}</>}>{currentStatus.retryCount}</DescriptionList.Entry> + <DescriptionList.Entry label={<>{t('Current_Status')} > {t('Status')}</>}>{currentStatus.status}</DescriptionList.Entry> + <DescriptionList.Entry label={<>{t('Instance_Record')} > {t('ID')}</>}>{instanceRecord._id}</DescriptionList.Entry> + <DescriptionList.Entry label={<>{t('Instance_Record')} > {t('PID')}</>}>{instanceRecord.pid}</DescriptionList.Entry> + <DescriptionList.Entry label={<>{t('Instance_Record')} > {t('Created_at')}</>}>{formatDate(instanceRecord._createdAt)}</DescriptionList.Entry> + <DescriptionList.Entry label={<>{t('Instance_Record')} > {t('Updated_at')}</>}>{formatDate(instanceRecord._updatedAt)}</DescriptionList.Entry> + </DescriptionList> )} </>; } diff --git a/client/components/admin/info/InstancesSection.stories.js b/client/components/admin/info/InstancesSection.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..8f0f8729765fa764ba6c063cf6277fc8e07738d3 --- /dev/null +++ b/client/components/admin/info/InstancesSection.stories.js @@ -0,0 +1,32 @@ +import React from 'react'; + +import { dummyDate } from '../../../../.storybook/helpers'; +import { InstancesSection } from './InstancesSection'; + +export default { + title: 'admin/info/InstancesSection', + component: InstancesSection, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + ], +}; + +const instances = [ + { + address: 'instances[].address', + broadcastAuth: 'instances[].broadcastAuth', + currentStatus: { + connected: 'instances[].currentStatus.connected', + retryCount: 'instances[].currentStatus.retryCount', + status: 'instances[].currentStatus.status', + }, + instanceRecord: { + _id: 'instances[].instanceRecord._id', + pid: 'instances[].instanceRecord.pid', + _createdAt: dummyDate, + _updatedAt: dummyDate, + }, + }, +]; + +export const _default = () => <InstancesSection instances={instances} />; diff --git a/client/components/admin/info/RocketChatSection.js b/client/components/admin/info/RocketChatSection.js index 7c10d79f66f3f34e534cb2ceb670e56b4add842d..1b380054f253da65bb6a9c00c1f777842cf375ac 100644 --- a/client/components/admin/info/RocketChatSection.js +++ b/client/components/admin/info/RocketChatSection.js @@ -1,34 +1,29 @@ +import { Text } from '@rocket.chat/fuselage'; import React from 'react'; -import { useTranslation } from '../../contexts/TranslationContext'; -import { SkeletonText } from './SkeletonText'; +import { useTranslation } from '../../providers/TranslationProvider'; import { formatDate, formatHumanReadableTime } from './formatters'; -import { InformationList } from './InformationList'; -import { InformationEntry } from './InformationEntry'; +import { DescriptionList } from './DescriptionList'; export function RocketChatSection({ info, statistics, isLoading }) { - const s = (fn) => (isLoading ? <SkeletonText /> : fn()); + const s = (fn) => (isLoading ? <Text.Skeleton animated width={'1/2'} /> : fn()); const t = useTranslation(); - const appsEngineVersion = info.marketplaceApiVersion; - - if (!statistics) { - return null; - } + const appsEngineVersion = info && info.marketplaceApiVersion; return <> <h3>{t('Rocket.Chat')}</h3> - <InformationList> - <InformationEntry label={t('Version')}>{s(() => statistics.version)}</InformationEntry> - {appsEngineVersion && <InformationEntry label={t('Apps_Engine_Version')}>{appsEngineVersion}</InformationEntry>} - <InformationEntry label={t('DB_Migration')}>{s(() => statistics.migration.version)}</InformationEntry> - <InformationEntry label={t('DB_Migration_Date')}>{s(() => formatDate(statistics.migration.lockedAt))}</InformationEntry> - <InformationEntry label={t('Installed_at')}>{s(() => formatDate(statistics.installedAt))}</InformationEntry> - <InformationEntry label={t('Uptime')}>{s(() => formatHumanReadableTime(statistics.process.uptime, t))}</InformationEntry> - <InformationEntry label={t('Deployment_ID')}>{s(() => statistics.uniqueId)}</InformationEntry> - <InformationEntry label={t('PID')}>{s(() => statistics.process.pid)}</InformationEntry> - <InformationEntry label={t('Running_Instances')}>{s(() => statistics.instanceCount)}</InformationEntry> - <InformationEntry label={t('OpLog')}>{s(() => (statistics.oplogEnabled ? t('Enabled') : t('Disabled')))}</InformationEntry> - </InformationList> + <DescriptionList> + <DescriptionList.Entry label={t('Version')}>{s(() => statistics.version)}</DescriptionList.Entry> + {appsEngineVersion && <DescriptionList.Entry label={t('Apps_Engine_Version')}>{appsEngineVersion}</DescriptionList.Entry>} + <DescriptionList.Entry label={t('DB_Migration')}>{s(() => statistics.migration.version)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('DB_Migration_Date')}>{s(() => formatDate(statistics.migration.lockedAt))}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Installed_at')}>{s(() => formatDate(statistics.installedAt))}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Uptime')}>{s(() => formatHumanReadableTime(statistics.process.uptime, t))}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Deployment_ID')}>{s(() => statistics.uniqueId)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('PID')}>{s(() => statistics.process.pid)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Running_Instances')}>{s(() => statistics.instanceCount)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OpLog')}>{s(() => (statistics.oplogEnabled ? t('Enabled') : t('Disabled')))}</DescriptionList.Entry> + </DescriptionList> </>; } diff --git a/client/components/admin/info/RocketChatSection.stories.js b/client/components/admin/info/RocketChatSection.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..e859eee72b5a583716bfa84f172c2b4156c259ca --- /dev/null +++ b/client/components/admin/info/RocketChatSection.stories.js @@ -0,0 +1,36 @@ +import React from 'react'; + +import { dummyDate } from '../../../../.storybook/helpers'; +import { RocketChatSection } from './RocketChatSection'; + +export default { + title: 'admin/info/RocketChatSection', + component: RocketChatSection, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + ], +}; + +const info = { + marketplaceApiVersion: 'info.marketplaceApiVersion', +}; + +const statistics = { + version: 'statistics.version', + migration: { + version: 'statistics.migration.version', + lockedAt: dummyDate, + }, + installedAt: dummyDate, + process: { + uptime: 10 * 24 * 60 * 60, + pid: 'statistics.process.pid', + }, + uniqueId: 'statistics.uniqueId', + instanceCount: 1, + oplogEnabled: true, +}; + +export const _default = () => <RocketChatSection info={info} statistics={statistics} />; + +export const loading = () => <RocketChatSection info={{}} statistics={{}} isLoading />; diff --git a/client/components/admin/info/RuntimeEnvironmentSection.js b/client/components/admin/info/RuntimeEnvironmentSection.js index 01c2a9ff78ea8f73561fd6e1c32ee6512e5c1983..f5a3a3ce928bdeb786c9729aa6eb895d4b9cfb7c 100644 --- a/client/components/admin/info/RuntimeEnvironmentSection.js +++ b/client/components/admin/info/RuntimeEnvironmentSection.js @@ -1,34 +1,29 @@ +import { Text } from '@rocket.chat/fuselage'; import React from 'react'; -import { useTranslation } from '../../contexts/TranslationContext'; -import { SkeletonText } from './SkeletonText'; +import { useTranslation } from '../../providers/TranslationProvider'; +import { DescriptionList } from './DescriptionList'; import { formatMemorySize, formatHumanReadableTime, formatCPULoad } from './formatters'; -import { InformationList } from './InformationList'; -import { InformationEntry } from './InformationEntry'; export function RuntimeEnvironmentSection({ statistics, isLoading }) { - const s = (fn) => (isLoading ? <SkeletonText /> : fn()); + const s = (fn) => (isLoading ? <Text.Skeleton animated width={'1/2'} /> : fn()); const t = useTranslation(); - if (!statistics) { - return null; - } - return <> <h3>{t('Runtime_Environment')}</h3> - <InformationList> - <InformationEntry label={t('OS_Type')}>{s(() => statistics.os.type)}</InformationEntry> - <InformationEntry label={t('OS_Platform')}>{s(() => statistics.os.platform)}</InformationEntry> - <InformationEntry label={t('OS_Arch')}>{s(() => statistics.os.arch)}</InformationEntry> - <InformationEntry label={t('OS_Release')}>{s(() => statistics.os.release)}</InformationEntry> - <InformationEntry label={t('Node_version')}>{s(() => statistics.process.nodeVersion)}</InformationEntry> - <InformationEntry label={t('Mongo_version')}>{s(() => statistics.mongoVersion)}</InformationEntry> - <InformationEntry label={t('Mongo_storageEngine')}>{s(() => statistics.mongoStorageEngine)}</InformationEntry> - <InformationEntry label={t('OS_Uptime')}>{s(() => formatHumanReadableTime(statistics.os.uptime, t))}</InformationEntry> - <InformationEntry label={t('OS_Loadavg')}>{s(() => formatCPULoad(statistics.os.loadavg))}</InformationEntry> - <InformationEntry label={t('OS_Totalmem')}>{s(() => formatMemorySize(statistics.os.totalmem))}</InformationEntry> - <InformationEntry label={t('OS_Freemem')}>{s(() => formatMemorySize(statistics.os.freemem))}</InformationEntry> - <InformationEntry label={t('OS_Cpus')}>{s(() => statistics.os.cpus.length)}</InformationEntry> - </InformationList> + <DescriptionList> + <DescriptionList.Entry label={t('OS_Type')}>{s(() => statistics.os.type)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Platform')}>{s(() => statistics.os.platform)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Arch')}>{s(() => statistics.os.arch)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Release')}>{s(() => statistics.os.release)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Node_version')}>{s(() => statistics.process.nodeVersion)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Mongo_version')}>{s(() => statistics.mongoVersion)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Mongo_storageEngine')}>{s(() => statistics.mongoStorageEngine)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Uptime')}>{s(() => formatHumanReadableTime(statistics.os.uptime, t))}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Loadavg')}>{s(() => formatCPULoad(statistics.os.loadavg))}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Totalmem')}>{s(() => formatMemorySize(statistics.os.totalmem))}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Freemem')}>{s(() => formatMemorySize(statistics.os.freemem))}</DescriptionList.Entry> + <DescriptionList.Entry label={t('OS_Cpus')}>{s(() => statistics.os.cpus.length)}</DescriptionList.Entry> + </DescriptionList> </>; } diff --git a/client/components/admin/info/RuntimeEnvironmentSection.stories.js b/client/components/admin/info/RuntimeEnvironmentSection.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..3270bbfe081496566150b41d2c0a47d6fdb642ab --- /dev/null +++ b/client/components/admin/info/RuntimeEnvironmentSection.stories.js @@ -0,0 +1,34 @@ +import React from 'react'; + +import { RuntimeEnvironmentSection } from './RuntimeEnvironmentSection'; + +export default { + title: 'admin/info/RuntimeEnvironmentSection', + component: RuntimeEnvironmentSection, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + ], +}; + +const statistics = { + os: { + type: 'statistics.os.type', + platform: 'statistics.os.platform', + arch: 'statistics.os.arch', + release: 'statistics.os.release', + uptime: 10 * 24 * 60 * 60, + loadavg: [1.1, 1.5, 1.15], + totalmem: 1024, + freemem: 1024, + cpus: [{}], + }, + process: { + nodeVersion: 'statistics.process.nodeVersion', + }, + mongoVersion: 'statistics.mongoVersion', + mongoStorageEngine: 'statistics.mongoStorageEngine', +}; + +export const _default = () => <RuntimeEnvironmentSection statistics={statistics} />; + +export const loading = () => <RuntimeEnvironmentSection statistics={{}} isLoading />; diff --git a/client/components/admin/info/SkeletonText.css b/client/components/admin/info/SkeletonText.css deleted file mode 100644 index baac1e70e96760d6fbd9adb4a6322cd00760985f..0000000000000000000000000000000000000000 --- a/client/components/admin/info/SkeletonText.css +++ /dev/null @@ -1,28 +0,0 @@ -.Admin__InformationPage__SkeletonText { - display: inline-flex; - - min-width: 10em; - height: 1em; - - animation: Admin__InformationPage__SkeletonText__animation 1s linear 1s infinite running; - - opacity: 0.25; - background: - linear-gradient( - to right, - transparent, - currentColor 50%, - transparent 100% - ); - background-size: 100vw 100vh; -} - -@keyframes Admin__InformationPage__SkeletonText__animation { - 0% { - background-position: 0 0; - } - - 100% { - background-position: 100vw 0; - } -} diff --git a/client/components/admin/info/SkeletonText.js b/client/components/admin/info/SkeletonText.js deleted file mode 100644 index 3c5cdcb1df79c2875779f79a67377cd15168e34f..0000000000000000000000000000000000000000 --- a/client/components/admin/info/SkeletonText.js +++ /dev/null @@ -1,9 +0,0 @@ -import React, { useMemo } from 'react'; -import './SkeletonText.css'; - - -export function SkeletonText() { - const width = useMemo(() => `${ Math.random() * 10 + 10 }em`, []); - - return <span className='Admin__InformationPage__SkeletonText' style={{ width }} />; -} diff --git a/client/components/admin/info/UsageSection.js b/client/components/admin/info/UsageSection.js index 64b76ea0d358a3c943bfd1a22a22244d9c2ec42f..171ef59d9486cbc15476d14d021800a94467f87e 100644 --- a/client/components/admin/info/UsageSection.js +++ b/client/components/admin/info/UsageSection.js @@ -1,53 +1,48 @@ +import { Text } from '@rocket.chat/fuselage'; import React from 'react'; -import { useTranslation } from '../../contexts/TranslationContext'; -import { SkeletonText } from './SkeletonText'; +import { useTranslation } from '../../providers/TranslationProvider'; +import { DescriptionList } from './DescriptionList'; import { formatMemorySize } from './formatters'; -import { InformationList } from './InformationList'; -import { InformationEntry } from './InformationEntry'; export function UsageSection({ statistics, isLoading }) { - const s = (fn) => (isLoading ? <SkeletonText /> : fn()); + const s = (fn) => (isLoading ? <Text.Skeleton animated width={'1/2'} /> : fn()); const t = useTranslation(); - if (!statistics) { - return null; - } - return <> <h3>{t('Usage')}</h3> - <InformationList> - <InformationEntry label={t('Stats_Total_Users')}>{s(() => statistics.totalUsers)}</InformationEntry> - <InformationEntry label={t('Stats_Active_Users')}>{s(() => statistics.activeUsers)}</InformationEntry> - <InformationEntry label={t('Stats_Non_Active_Users')}>{s(() => statistics.nonActiveUsers)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Connected_Users')}>{s(() => statistics.totalConnectedUsers)}</InformationEntry> - <InformationEntry label={t('Stats_Online_Users')}>{s(() => statistics.onlineUsers)}</InformationEntry> - <InformationEntry label={t('Stats_Away_Users')}>{s(() => statistics.awayUsers)}</InformationEntry> - <InformationEntry label={t('Stats_Offline_Users')}>{s(() => statistics.offlineUsers)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Rooms')}>{s(() => statistics.totalRooms)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Channels')}>{s(() => statistics.totalChannels)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Private_Groups')}>{s(() => statistics.totalPrivateGroups)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Direct_Messages')}>{s(() => statistics.totalDirect)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Livechat_Rooms')}>{s(() => statistics.totalLivechat)}</InformationEntry> - <InformationEntry label={t('Total_Discussions')}>{s(() => statistics.totalDiscussions)}</InformationEntry> - <InformationEntry label={t('Total_Threads')}>{s(() => statistics.totalThreads)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Messages')}>{s(() => statistics.totalMessages)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Messages_Channel')}>{s(() => statistics.totalChannelMessages)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Messages_PrivateGroup')}>{s(() => statistics.totalPrivateGroupMessages)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Messages_Direct')}>{s(() => statistics.totalDirectMessages)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Messages_Livechat')}>{s(() => statistics.totalLivechatMessages)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Uploads')}>{s(() => statistics.uploadsTotal)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Uploads_Size')}>{s(() => formatMemorySize(statistics.uploadsTotalSize))}</InformationEntry> - {statistics.apps && <> - <InformationEntry label={t('Stats_Total_Installed_Apps')}>{statistics.apps.totalInstalled}</InformationEntry> - <InformationEntry label={t('Stats_Total_Active_Apps')}>{statistics.apps.totalActive}</InformationEntry> + <DescriptionList> + <DescriptionList.Entry label={t('Stats_Total_Users')}>{s(() => statistics.totalUsers)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Active_Users')}>{s(() => statistics.activeUsers)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Non_Active_Users')}>{s(() => statistics.nonActiveUsers)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Connected_Users')}>{s(() => statistics.totalConnectedUsers)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Online_Users')}>{s(() => statistics.onlineUsers)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Away_Users')}>{s(() => statistics.awayUsers)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Offline_Users')}>{s(() => statistics.offlineUsers)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Rooms')}>{s(() => statistics.totalRooms)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Channels')}>{s(() => statistics.totalChannels)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Private_Groups')}>{s(() => statistics.totalPrivateGroups)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Direct_Messages')}>{s(() => statistics.totalDirect)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Livechat_Rooms')}>{s(() => statistics.totalLivechat)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Total_Discussions')}>{s(() => statistics.totalDiscussions)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Total_Threads')}>{s(() => statistics.totalThreads)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Messages')}>{s(() => statistics.totalMessages)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Messages_Channel')}>{s(() => statistics.totalChannelMessages)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Messages_PrivateGroup')}>{s(() => statistics.totalPrivateGroupMessages)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Messages_Direct')}>{s(() => statistics.totalDirectMessages)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Messages_Livechat')}>{s(() => statistics.totalLivechatMessages)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Uploads')}>{s(() => statistics.uploadsTotal)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Uploads_Size')}>{s(() => formatMemorySize(statistics.uploadsTotalSize))}</DescriptionList.Entry> + {statistics && statistics.apps && <> + <DescriptionList.Entry label={t('Stats_Total_Installed_Apps')}>{statistics.apps.totalInstalled}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Active_Apps')}>{statistics.apps.totalActive}</DescriptionList.Entry> </>} - <InformationEntry label={t('Stats_Total_Integrations')}>{s(() => statistics.integrations.totalIntegrations)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Incoming_Integrations')}>{s(() => statistics.integrations.totalIncoming)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Active_Incoming_Integrations')}>{s(() => statistics.integrations.totalIncomingActive)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Outgoing_Integrations')}>{s(() => statistics.integrations.totalOutgoing)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Active_Outgoing_Integrations')}>{s(() => statistics.integrations.totalOutgoingActive)}</InformationEntry> - <InformationEntry label={t('Stats_Total_Integrations_With_Script_Enabled')}>{s(() => statistics.integrations.totalWithScriptEnabled)}</InformationEntry> - </InformationList> + <DescriptionList.Entry label={t('Stats_Total_Integrations')}>{s(() => statistics.integrations.totalIntegrations)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Incoming_Integrations')}>{s(() => statistics.integrations.totalIncoming)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Active_Incoming_Integrations')}>{s(() => statistics.integrations.totalIncomingActive)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Outgoing_Integrations')}>{s(() => statistics.integrations.totalOutgoing)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Active_Outgoing_Integrations')}>{s(() => statistics.integrations.totalOutgoingActive)}</DescriptionList.Entry> + <DescriptionList.Entry label={t('Stats_Total_Integrations_With_Script_Enabled')}>{s(() => statistics.integrations.totalWithScriptEnabled)}</DescriptionList.Entry> + </DescriptionList> </>; } diff --git a/client/components/admin/info/UsageSection.stories.js b/client/components/admin/info/UsageSection.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..81653490717440c8319c00c681ce6e88f9236272 --- /dev/null +++ b/client/components/admin/info/UsageSection.stories.js @@ -0,0 +1,54 @@ +import React from 'react'; + +import { UsageSection } from './UsageSection'; + +export default { + title: 'admin/info/UsageSection', + component: UsageSection, + decorators: [ + (fn) => <div className='rc-old'>{fn()}</div>, + ], +}; + +const statistics = { + totalUsers: 'statistics.totalUsers', + nonActiveUsers: 'nonActiveUsers', + activeUsers: 'statistics.activeUsers', + totalConnectedUsers: 'statistics.totalConnectedUsers', + onlineUsers: 'statistics.onlineUsers', + awayUsers: 'statistics.awayUsers', + offlineUsers: 'statistics.offlineUsers', + totalRooms: 'statistics.totalRooms', + totalChannels: 'statistics.totalChannels', + totalPrivateGroups: 'statistics.totalPrivateGroups', + totalDirect: 'statistics.totalDirect', + totalLivechat: 'statistics.totalLivechat', + totalDiscussions: 'statistics.totalDiscussions', + totalThreads: 'statistics.totalThreads', + totalMessages: 'statistics.totalMessages', + totalChannelMessages: 'statistics.totalChannelMessages', + totalPrivateGroupMessages: 'statistics.totalPrivateGroupMessages', + totalDirectMessages: 'statistics.totalDirectMessages', + totalLivechatMessages: 'statistics.totalLivechatMessages', + uploadsTotal: 'statistics.uploadsTotal', + uploadsTotalSize: 1024, + integrations: { + totalIntegrations: 'statistics.integrations.totalIntegrations', + totalIncoming: 'statistics.integrations.totalIncoming', + totalIncomingActive: 'statistics.integrations.totalIncomingActive', + totalOutgoing: 'statistics.integrations.totalOutgoing', + totalOutgoingActive: 'statistics.integrations.totalOutgoingActive', + totalWithScriptEnabled: 'statistics.integrations.totalWithScriptEnabled', + }, +}; + +const apps = { + totalInstalled: 'statistics.apps.totalInstalled', + totalActive: 'statistics.apps.totalActive', +}; + +export const _default = () => <UsageSection statistics={statistics} />; + +export const withApps = () => <UsageSection statistics={{ ...statistics, apps }} />; + +export const loading = () => <UsageSection statistics={{}} isLoading />; diff --git a/client/components/admin/settings/GroupPage.js b/client/components/admin/settings/GroupPage.js new file mode 100644 index 0000000000000000000000000000000000000000..9840b97e75b848b217f7cc3404c38ba08a55d9c9 --- /dev/null +++ b/client/components/admin/settings/GroupPage.js @@ -0,0 +1,92 @@ +import { Accordion, Button, Paragraph, Text } from '@rocket.chat/fuselage'; +import React from 'react'; +import styled from 'styled-components'; + +import { Header } from '../../header/Header'; +import { useTranslation } from '../../providers/TranslationProvider'; +import { Section } from './Section'; + +const Wrapper = styled.div` + margin: 0 auto; + width: 100%; + max-width: 590px; +`; + +export function GroupPage({ children, group, headerButtons }) { + const t = useTranslation(); + + const handleSubmit = (event) => { + event.preventDefault(); + group.save(); + }; + + const handleCancelClick = (event) => { + event.preventDefault(); + group.cancel(); + }; + + const handleSaveClick = (event) => { + event.preventDefault(); + group.save(); + }; + + if (!group) { + return <section className='page-container page-static page-settings'> + <Header /> + <div className='content' /> + </section>; + } + + return <form action='#' className='page-container' method='post' onSubmit={handleSubmit}> + <Header rawSectionName={t(group.i18nLabel)}> + <Header.ButtonSection> + {group.changed && <Button danger primary type='reset' onClick={handleCancelClick}>{t('Cancel')}</Button>} + <Button + children={t('Save_changes')} + className='save' + disabled={!group.changed} + primary + type='submit' + onClick={handleSaveClick} + /> + {headerButtons} + </Header.ButtonSection> + </Header> + + <div className='content'> + <Wrapper> + {t.has(group.i18nDescription) && <Paragraph hintColor>{t(group.i18nDescription)}</Paragraph>} + + <Accordion className='page-settings'> + {children} + </Accordion> + </Wrapper> + </div> + </form>; +} + +GroupPage.Skeleton = function Skeleton() { + const t = useTranslation(); + + return <div className='page-container'> + <Header rawSectionName={<div style={{ width: '20rem' }}><Text.Skeleton animated headline /></div>}> + <Header.ButtonSection> + <Button + children={t('Save_changes')} + disabled + primary + /> + </Header.ButtonSection> + </Header> + + <div className='content'> + <Wrapper> + <Paragraph.Skeleton animated /> + + <Accordion className='page-settings'> + <Section.Skeleton /> + </Accordion> + </Wrapper> + </div> + </div>; +}; diff --git a/client/components/admin/settings/GroupSelector.js b/client/components/admin/settings/GroupSelector.js new file mode 100644 index 0000000000000000000000000000000000000000..a07d54709e640806a7669f10d46c8493a454af5f --- /dev/null +++ b/client/components/admin/settings/GroupSelector.js @@ -0,0 +1,23 @@ +import React, { useMemo } from 'react'; + +import { AssetsGroupPage } from './groups/AssetsGroupPage'; +import { OAuthGroupPage } from './groups/OAuthGroupPage'; +import { GenericGroupPage } from './groups/GenericGroupPage'; +import { GroupPage } from './GroupPage'; +import { useGroup } from './SettingsState'; + +export function GroupSelector({ groupId }) { + const group = useGroup(groupId); + + const children = useMemo(() => { + if (!group) { + return <GroupPage.Skeleton />; + } + + return (group._id === 'Assets' && <AssetsGroupPage group={group} />) + || (group._id === 'OAuth' && <OAuthGroupPage group={group} />) + || <GenericGroupPage group={group} />; + }, [group]); + + return children; +} diff --git a/client/components/admin/settings/NotAuthorizedPage.js b/client/components/admin/settings/NotAuthorizedPage.js new file mode 100644 index 0000000000000000000000000000000000000000..f65ffd19cc0e59b147520889cca1e5c91927e38a --- /dev/null +++ b/client/components/admin/settings/NotAuthorizedPage.js @@ -0,0 +1,13 @@ +import React from 'react'; + +import { useTranslation } from '../../providers/TranslationProvider'; + +export function NotAuthorizedPage() { + const t = useTranslation(); + + return <section className='page-container page-static page-settings'> + <div className='content'> + <p>{t('You_are_not_authorized_to_view_this_page')}</p> + </div> + </section>; +} diff --git a/client/components/admin/settings/NotAuthorizedPage.stories.js b/client/components/admin/settings/NotAuthorizedPage.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..df29af858e1404c3c3dfe6d522593f958937d50a --- /dev/null +++ b/client/components/admin/settings/NotAuthorizedPage.stories.js @@ -0,0 +1,11 @@ +import React from 'react'; + +import { NotAuthorizedPage } from './NotAuthorizedPage'; + +export default { + title: 'admin/settings/NotAuthorizedPage', + component: NotAuthorizedPage, +}; + +export const _default = () => + <NotAuthorizedPage />; diff --git a/client/components/admin/settings/ResetSettingButton.js b/client/components/admin/settings/ResetSettingButton.js new file mode 100644 index 0000000000000000000000000000000000000000..69655de70cfa66bb8679acb99a77d0b645a95f40 --- /dev/null +++ b/client/components/admin/settings/ResetSettingButton.js @@ -0,0 +1,27 @@ +import { Button, Icon } from '@rocket.chat/fuselage'; +import React from 'react'; +import styled from 'styled-components'; + +import { useTranslation } from '../../providers/TranslationProvider'; + +// TODO: get rid of it +const StyledResetSettingButton = styled(Button)` + padding-block: 0 !important; + padding-top: 0 !important; + padding-bottom: 0 !important; +`; + +export function ResetSettingButton(props) { + const t = useTranslation(); + + return <StyledResetSettingButton + aria-label={t('Reset')} + danger + ghost + small + title={t('Reset')} + {...props} + > + <Icon name='undo' /> + </StyledResetSettingButton>; +} diff --git a/client/components/admin/settings/Section.js b/client/components/admin/settings/Section.js new file mode 100644 index 0000000000000000000000000000000000000000..95e8280cf7f4bbd752da6daa2c96abdd69855bb8 --- /dev/null +++ b/client/components/admin/settings/Section.js @@ -0,0 +1,51 @@ +import { Accordion, Button, FieldGroup, Paragraph, Text } from '@rocket.chat/fuselage'; +import React from 'react'; + +import { useTranslation } from '../../providers/TranslationProvider'; +import { Setting } from './Setting'; +import { useSection } from './SettingsState'; + +export function Section({ children, groupId, hasReset = true, help, sectionName, solo }) { + const section = useSection(groupId, sectionName); + const t = useTranslation(); + + const handleResetSectionClick = () => { + section.reset(); + }; + + return <Accordion.Item + data-qa-section={sectionName} + noncollapsible={solo || !section.name} + title={section.name && t(section.name)} + > + {help && <Paragraph hintColor>{help}</Paragraph>} + + <FieldGroup> + {section.settings.map((settingId) => <Setting key={settingId} settingId={settingId} />)} + + {hasReset && section.canReset && <Button + children={t('Reset_section_settings')} + className='reset-group' + danger + data-section={section.name} + ghost + onClick={handleResetSectionClick} + />} + + {children} + </FieldGroup> + </Accordion.Item>; +} + +Section.Skeleton = function Skeleton() { + return <Accordion.Item + noncollapsible + title={<Text.Skeleton animated subtitle />} + > + <Paragraph.Skeleton animated /> + + <FieldGroup> + {Array.from({ length: 10 }).map((_, i) => <Setting.Skeleton key={i} />)} + </FieldGroup> + </Accordion.Item>; +}; diff --git a/client/components/admin/settings/Setting.js b/client/components/admin/settings/Setting.js new file mode 100644 index 0000000000000000000000000000000000000000..9d3a5c8e503294309b4aa0276db5e464fc473b52 --- /dev/null +++ b/client/components/admin/settings/Setting.js @@ -0,0 +1,131 @@ +import { Callout, Field, InputBox, Label, Text } from '@rocket.chat/fuselage'; +import { useDebouncedCallback } from '@rocket.chat/fuselage-hooks'; +import React, { useEffect, useMemo, useState } from 'react'; + +import { MarkdownText } from '../../basic/MarkdownText'; +import { RawText } from '../../basic/RawText'; +import { useTranslation } from '../../providers/TranslationProvider'; +import { GenericSettingInput } from './inputs/GenericSettingInput'; +import { BooleanSettingInput } from './inputs/BooleanSettingInput'; +import { StringSettingInput } from './inputs/StringSettingInput'; +import { RelativeUrlSettingInput } from './inputs/RelativeUrlSettingInput'; +import { PasswordSettingInput } from './inputs/PasswordSettingInput'; +import { IntSettingInput } from './inputs/IntSettingInput'; +import { SelectSettingInput } from './inputs/SelectSettingInput'; +import { LanguageSettingInput } from './inputs/LanguageSettingInput'; +import { ColorSettingInput } from './inputs/ColorSettingInput'; +import { FontSettingInput } from './inputs/FontSettingInput'; +import { CodeSettingInput } from './inputs/CodeSettingInput'; +import { ActionSettingInput } from './inputs/ActionSettingInput'; +import { AssetSettingInput } from './inputs/AssetSettingInput'; +import { RoomPickSettingInput } from './inputs/RoomPickSettingInput'; +import { useSetting } from './SettingsState'; + +const getInputComponentByType = (type) => ({ + boolean: BooleanSettingInput, + string: StringSettingInput, + relativeUrl: RelativeUrlSettingInput, + password: PasswordSettingInput, + int: IntSettingInput, + select: SelectSettingInput, + language: LanguageSettingInput, + color: ColorSettingInput, + font: FontSettingInput, + code: CodeSettingInput, + action: ActionSettingInput, + asset: AssetSettingInput, + roomPick: RoomPickSettingInput, +})[type] || GenericSettingInput; + +const MemoizedSetting = React.memo(function MemoizedSetting({ + type, + hint, + callout, + ...inputProps +}) { + const InputComponent = getInputComponentByType(type); + + return <Field> + <InputComponent {...inputProps} /> + {hint && <Field.Hint>{hint}</Field.Hint>} + {callout && <Callout type='warning' title={callout} />} + </Field>; +}); + +export function Setting({ settingId }) { + const { + value: contextValue, + editor: contextEditor, + ...setting + } = useSetting(settingId); + + const t = useTranslation(); + + const [value, setValue] = useState(contextValue); + const setContextValue = useDebouncedCallback((value) => setting.update({ value }), 70, []); + + useEffect(() => { + setValue(contextValue); + }, [contextValue]); + + const [editor, setEditor] = useState(contextEditor); + const setContextEditor = useDebouncedCallback((editor) => setting.update({ editor }), 70, []); + + useEffect(() => { + setEditor(contextEditor); + }, [contextEditor]); + + const onChangeValue = (value) => { + setValue(value); + setContextValue(value); + }; + + const onChangeEditor = (editor) => { + setEditor(editor); + setContextEditor(editor); + }; + + const onResetButtonClick = () => { + setting.reset(); + }; + + const { + _id, + disableReset, + readonly, + type, + packageValue, + blocked, + i18nLabel, + i18nDescription, + alert, + } = setting; + + const label = (i18nLabel && t(i18nLabel)) || (_id || t(_id)); + const hint = useMemo(() => t.has(i18nDescription) && <MarkdownText>{t(i18nDescription)}</MarkdownText>, [i18nDescription]); + const callout = useMemo(() => alert && <RawText>{t(alert)}</RawText>, [alert]); + const hasResetButton = !disableReset && !readonly && type !== 'asset' && value !== packageValue && !blocked; + + return <MemoizedSetting + type={type} + label={label} + hint={hint} + callout={callout} + {...setting} + value={value} + editor={editor} + hasResetButton={hasResetButton} + onChangeValue={onChangeValue} + onChangeEditor={onChangeEditor} + onResetButtonClick={onResetButtonClick} + />; +} + +Setting.Skeleton = function Skeleton() { + return <Field> + <Label> + <Text.Skeleton animated width='1/4' /> + </Label> + <InputBox.Skeleton animated /> + </Field>; +}; diff --git a/client/components/admin/settings/SettingsRoute.js b/client/components/admin/settings/SettingsRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..778e85f2365632e948433ed7956871d4ad6b887e --- /dev/null +++ b/client/components/admin/settings/SettingsRoute.js @@ -0,0 +1,27 @@ +import React from 'react'; + +import { useAtLeastOnePermission } from '../../../hooks/usePermissions'; +import { useAdminSideNav } from '../hooks'; +import { GroupSelector } from './GroupSelector'; +import { NotAuthorizedPage } from './NotAuthorizedPage'; +import { SettingsState } from './SettingsState'; + +export function SettingsRoute({ + group: groupId, +}) { + useAdminSideNav(); + + const hasPermission = useAtLeastOnePermission([ + 'view-privileged-setting', + 'edit-privileged-setting', + 'manage-selected-settings', + ]); + + if (!hasPermission) { + return <NotAuthorizedPage />; + } + + return <SettingsState> + <GroupSelector groupId={groupId} /> + </SettingsState>; +} diff --git a/client/components/admin/settings/SettingsState.js b/client/components/admin/settings/SettingsState.js new file mode 100644 index 0000000000000000000000000000000000000000..5d39179e11edbf47604363ba2ee99e4ff0d4af0d --- /dev/null +++ b/client/components/admin/settings/SettingsState.js @@ -0,0 +1,384 @@ +import { Meteor } from 'meteor/meteor'; +import { Mongo } from 'meteor/mongo'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import React, { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState } from 'react'; +import toastr from 'toastr'; + +import { PrivateSettingsCachedCollection } from '../../../../app/ui-admin/client/SettingsCachedCollection'; +import { handleError } from '../../../../app/utils/client/lib/handleError'; +import { useBatchSetSettings } from '../../../hooks/useBatchSetSettings'; +import { useEventCallback } from '../../../hooks/useEventCallback'; +import { useReactiveValue } from '../../../hooks/useReactiveValue'; + +const SettingsContext = createContext({}); + +let privateSettingsCachedCollection; // Remove this singleton (╯°□°)╯︵ â”»â”â”» + +const getPrivateSettingsCachedCollection = () => { + if (privateSettingsCachedCollection) { + return [privateSettingsCachedCollection, Promise.resolve()]; + } + + privateSettingsCachedCollection = new PrivateSettingsCachedCollection(); + + return [privateSettingsCachedCollection, privateSettingsCachedCollection.init()]; +}; + +const compareStrings = (a = '', b = '') => { + if (a === b || (!a && !b)) { + return 0; + } + + return a > b ? 1 : -1; +}; + +const compareSettings = (a, b) => + compareStrings(a.section, b.section) + || compareStrings(a.sorter, b.sorter) + || compareStrings(a.i18nLabel, b.i18nLabel); + +const settingsReducer = (states, { type, payload }) => { + const { + settings, + persistedSettings, + } = states; + + switch (type) { + case 'add': { + return { + settings: [...settings, ...payload].sort(compareSettings), + persistedSettings: [...persistedSettings, ...payload].sort(compareSettings), + }; + } + + case 'change': { + const mapping = (setting) => (setting._id !== payload._id ? setting : payload); + + return { + settings: settings.map(mapping), + persistedSettings: settings.map(mapping), + }; + } + + case 'remove': { + const mapping = (setting) => setting._id !== payload; + + return { + settings: settings.filter(mapping), + persistedSettings: persistedSettings.filter(mapping), + }; + } + + case 'hydrate': { + const map = {}; + payload.forEach((setting) => { + map[setting._id] = setting; + }); + + const mapping = (setting) => (map[setting._id] ? { ...setting, ...map[setting._id] } : setting); + + return { + settings: settings.map(mapping), + persistedSettings, + }; + } + } + + return states; +}; + +export function SettingsState({ children }) { + const [isLoading, setLoading] = useState(true); + + const [subscribers] = useState(new Set()); + + const stateRef = useRef({ settings: [], persistedSettings: [] }); + + const enhancedReducer = useCallback((state, action) => { + const newState = settingsReducer(state, action); + + stateRef.current = newState; + + subscribers.forEach((subscriber) => { + subscriber(newState); + }); + + return newState; + }, [settingsReducer, subscribers]); + + const [, dispatch] = useReducer(enhancedReducer, { settings: [], persistedSettings: [] }); + + const collectionsRef = useRef({}); + + useEffect(() => { + const [privateSettingsCachedCollection, loadingPromise] = getPrivateSettingsCachedCollection(); + + const stopLoading = () => { + setLoading(false); + }; + + loadingPromise.then(stopLoading, stopLoading); + + const { collection: persistedSettingsCollection } = privateSettingsCachedCollection; + const settingsCollection = new Mongo.Collection(null); + + collectionsRef.current = { + persistedSettingsCollection, + settingsCollection, + }; + }, [collectionsRef]); + + useEffect(() => { + if (isLoading) { + return; + } + + const { current: { persistedSettingsCollection, settingsCollection } } = collectionsRef; + + const query = persistedSettingsCollection.find(); + + const syncCollectionsHandle = query.observe({ + added: (data) => settingsCollection.insert(data), + changed: (data) => settingsCollection.update(data._id, data), + removed: ({ _id }) => settingsCollection.remove(_id), + }); + + const addedQueue = []; + let addedActionTimer; + + const syncStateHandle = query.observe({ + added: (data) => { + addedQueue.push(data); + clearTimeout(addedActionTimer); + addedActionTimer = setTimeout(() => { + dispatch({ type: 'add', payload: addedQueue }); + }, 70); + }, + changed: (data) => { + dispatch({ type: 'change', payload: data }); + }, + removed: ({ _id }) => { + dispatch({ type: 'remove', payload: _id }); + }, + }); + + return () => { + syncCollectionsHandle.stop(); + syncStateHandle.stop(); + clearTimeout(addedActionTimer); + }; + }, [isLoading, collectionsRef]); + + const updateTimersRef = useRef({}); + + const updateAtCollection = useCallback(({ _id, ...data }) => { + const { current: { settingsCollection } } = collectionsRef; + const { current: updateTimers } = updateTimersRef; + clearTimeout(updateTimers[_id]); + updateTimers[_id] = setTimeout(() => { + settingsCollection.update(_id, { $set: data }); + }, 70); + }, [collectionsRef, updateTimersRef]); + + const hydrate = useCallback((changes) => { + changes.forEach(updateAtCollection); + dispatch({ type: 'hydrate', payload: changes }); + }, [updateAtCollection, dispatch]); + + const isDisabled = useCallback(({ blocked, enableQuery }) => { + if (blocked) { + return true; + } + + if (!enableQuery) { + return false; + } + + const { current: { settingsCollection } } = collectionsRef; + + const queries = [].concat(typeof enableQuery === 'string' ? JSON.parse(enableQuery) : enableQuery); + return !queries.every((query) => !!settingsCollection.findOne(query)); + }, [collectionsRef]); + + const contextValue = useMemo(() => ({ + subscribers, + stateRef, + hydrate, + isDisabled, + }), [ + subscribers, + stateRef, + hydrate, + isDisabled, + ]); + + return <SettingsContext.Provider children={children} value={contextValue} />; +} + +const useSelector = (selector, equalityFunction = (a, b) => a === b) => { + const { subscribers, stateRef } = useContext(SettingsContext); + const [value, setValue] = useState(() => selector(stateRef.current)); + + const handleUpdate = useEventCallback((selector, equalityFunction, value, state) => { + const newValue = selector(state); + + if (!equalityFunction(newValue, value)) { + setValue(newValue); + } + }, selector, equalityFunction, value); + + useEffect(() => { + subscribers.add(handleUpdate); + + return () => { + subscribers.delete(handleUpdate); + }; + }, [handleUpdate]); + + useLayoutEffect(() => { + handleUpdate(stateRef.current); + }); + + return value; +}; + +export const useGroup = (groupId) => { + const group = useSelector((state) => state.settings.find(({ _id, type }) => _id === groupId && type === 'group')); + + const filterSettings = (settings) => settings.filter(({ group }) => group === groupId); + + const changed = useSelector((state) => filterSettings(state.settings).some(({ changed }) => changed)); + const sections = useSelector((state) => Array.from(new Set(filterSettings(state.settings).map(({ section }) => section || ''))), (a, b) => a.length === b.length && a.join() === b.join()); + + const batchSetSettings = useBatchSetSettings(); + const { stateRef, hydrate } = useContext(SettingsContext); + + const save = useEventCallback(async (filterSettings, { current: state }, batchSetSettings) => { + const settings = filterSettings(state.settings); + + const changes = settings.filter(({ changed }) => changed) + .map(({ _id, value, editor }) => ({ _id, value, editor })); + + if (changes.length === 0) { + return; + } + + try { + await batchSetSettings(changes); + + if (changes.some(({ _id }) => _id === 'Language')) { + const lng = Meteor.user().language + || changes.filter(({ _id }) => _id === 'Language').shift().value + || 'en'; + + TAPi18n._loadLanguage(lng) + .then(() => toastr.success(TAPi18n.__('Settings_updated', { lng }))) + .catch(handleError); + + return; + } + + toastr.success(TAPi18n.__('Settings_updated')); + } catch (error) { + handleError(error); + } + }, filterSettings, stateRef, batchSetSettings); + + const cancel = useEventCallback((filterSettings, { current: state }, hydrate) => { + const settings = filterSettings(state.settings); + const persistedSettings = filterSettings(state.persistedSettings); + + const changes = settings.filter(({ changed }) => changed) + .map((field) => { + const { _id, value, editor } = persistedSettings.find(({ _id }) => _id === field._id); + return { _id, value, editor, changed: false }; + }); + + hydrate(changes); + }, filterSettings, stateRef, hydrate); + + return group && { ...group, sections, changed, save, cancel }; +}; + +export const useSection = (groupId, sectionName) => { + sectionName = sectionName || ''; + + const filterSettings = (settings) => + settings.filter(({ group, section }) => group === groupId && ((!sectionName && !section) || (sectionName === section))); + + const changed = useSelector((state) => filterSettings(state.settings).some(({ changed }) => changed)); + const canReset = useSelector((state) => filterSettings(state.settings).some(({ value, packageValue }) => value !== packageValue)); + const settingsIds = useSelector((state) => filterSettings(state.settings).map(({ _id }) => _id), (a, b) => a.length === b.length && a.join() === b.join()); + + const { stateRef, hydrate } = useContext(SettingsContext); + + const reset = useEventCallback((filterSettings, { current: state }, hydrate) => { + const settings = filterSettings(state.settings); + const persistedSettings = filterSettings(state.persistedSettings); + + const changes = settings.map((setting) => { + const { _id, value, packageValue, editor } = persistedSettings.find(({ _id }) => _id === setting._id); + return { + _id, + value: packageValue, + editor, + changed: packageValue !== value, + }; + }); + + hydrate(changes); + }, filterSettings, stateRef, hydrate); + + return { + name: sectionName, + changed, + canReset, + settings: settingsIds, + reset, + }; +}; + +export const useSetting = (_id) => { + const { stateRef, hydrate, isDisabled } = useContext(SettingsContext); + + const selectSetting = (settings) => settings.find((setting) => setting._id === _id); + + const setting = useSelector((state) => selectSetting(state.settings)); + const sectionChanged = useSelector((state) => state.settings.some(({ section, changed }) => section === setting.section && changed)); + const disabled = useReactiveValue(() => isDisabled(setting), [setting.blocked, setting.enableQuery]); + + const update = useEventCallback((selectSetting, { current: state }, hydrate, data) => { + const setting = { ...selectSetting(state.settings), ...data }; + const persistedSetting = selectSetting(state.persistedSettings); + + const changes = [{ + _id: setting._id, + value: setting.value, + editor: setting.editor, + changed: (setting.value !== persistedSetting.value) || (setting.editor !== persistedSetting.editor), + }]; + + hydrate(changes); + }, selectSetting, stateRef, hydrate); + + const reset = useEventCallback((selectSetting, { current: state }, hydrate) => { + const { _id, value, packageValue, editor } = selectSetting(state.persistedSettings); + + const changes = [{ + _id, + value: packageValue, + editor, + changed: packageValue !== value, + }]; + + hydrate(changes); + }, selectSetting, stateRef, hydrate); + + return { + ...setting, + sectionChanged, + disabled, + update, + reset, + }; +}; diff --git a/client/components/admin/settings/groups/AssetsGroupPage.js b/client/components/admin/settings/groups/AssetsGroupPage.js new file mode 100644 index 0000000000000000000000000000000000000000..7f9b49f93965e31d73d0359282c4e0228f69ffeb --- /dev/null +++ b/client/components/admin/settings/groups/AssetsGroupPage.js @@ -0,0 +1,23 @@ +import { Button } from '@rocket.chat/fuselage'; +import React from 'react'; + +import { useTranslation } from '../../../providers/TranslationProvider'; +import { GroupPage } from '../GroupPage'; +import { Section } from '../Section'; + +export function AssetsGroupPage({ group }) { + const solo = group.sections.length === 1; + const t = useTranslation(); + + return <GroupPage group={group} headerButtons={<> + <Button className='refresh-clients'>{t('Apply_and_refresh_all_clients')}</Button> + </>}> + {group.sections.map((sectionName) => <Section + key={sectionName} + groupId={group._id} + hasReset={false} + sectionName={sectionName} + solo={solo} + />)} + </GroupPage>; +} diff --git a/client/components/admin/settings/groups/GenericGroupPage.js b/client/components/admin/settings/groups/GenericGroupPage.js new file mode 100644 index 0000000000000000000000000000000000000000..09b4e190f85c2b21c050b758c4c848d500d5fa9e --- /dev/null +++ b/client/components/admin/settings/groups/GenericGroupPage.js @@ -0,0 +1,17 @@ +import React from 'react'; + +import { GroupPage } from '../GroupPage'; +import { Section } from '../Section'; + +export function GenericGroupPage({ group }) { + const solo = group.sections.length === 1; + + return <GroupPage group={group}> + {group.sections.map((sectionName) => <Section + key={sectionName} + groupId={group._id} + sectionName={sectionName} + solo={solo} + />)} + </GroupPage>; +} diff --git a/client/components/admin/settings/groups/OAuthGroupPage.js b/client/components/admin/settings/groups/OAuthGroupPage.js new file mode 100644 index 0000000000000000000000000000000000000000..44bf71af1671fcd88aed26fa0e86c9259ec23058 --- /dev/null +++ b/client/components/admin/settings/groups/OAuthGroupPage.js @@ -0,0 +1,40 @@ +import { Button } from '@rocket.chat/fuselage'; +import { Meteor } from 'meteor/meteor'; +import React from 'react'; +import s from 'underscore.string'; + +import { RawText } from '../../../basic/RawText'; +import { useTranslation } from '../../../providers/TranslationProvider'; +import { GroupPage } from '../GroupPage'; +import { Section } from '../Section'; + +export function OAuthGroupPage({ group }) { + const solo = group.sections.length === 1; + const t = useTranslation(); + + const sectionIsCustomOAuth = (sectionName) => sectionName && /^Custom OAuth:\s.+/.test(sectionName); + + const callbackURL = (sectionName) => { + const id = s.strRight(sectionName, 'Custom OAuth: ').toLowerCase(); + return Meteor.absoluteUrl(`_oauth/${ id }`); + }; + + return <GroupPage group={group} headerButtons={<> + <Button className='refresh-oauth'>{t('Refresh_oauth_services')}</Button> + <Button className='add-custom-oauth'>{t('Add_custom_oauth')}</Button> + </>}> + {group.sections.map((sectionName) => (sectionIsCustomOAuth(sectionName) + ? <Section + key={sectionName} + groupId={group._id} + help={<RawText>{t('Custom_oauth_helper', callbackURL(sectionName))}</RawText>} + sectionName={sectionName} + solo={solo} + > + <div className='submit'> + <Button cancel className='remove-custom-oauth'>{t('Remove_custom_oauth')}</Button> + </div> + </Section> + : <Section key={sectionName} groupId={group._id} sectionName={sectionName} solo={solo} />))} + </GroupPage>; +} diff --git a/client/components/admin/settings/inputs/ActionSettingInput.js b/client/components/admin/settings/inputs/ActionSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..bdcad8acf14902e3950bca00e6513fd35a298647 --- /dev/null +++ b/client/components/admin/settings/inputs/ActionSettingInput.js @@ -0,0 +1,44 @@ +import { Button, Field } from '@rocket.chat/fuselage'; +import { Meteor } from 'meteor/meteor'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import React from 'react'; +import toastr from 'toastr'; + +import { useTranslation } from '../../../providers/TranslationProvider'; +import { handleError } from '../../../../../app/utils/client'; + +export function ActionSettingInput({ + _id, + actionText, + value, + disabled, + sectionChanged, +}) { + const t = useTranslation(); + + const handleClick = async () => { + Meteor.call(value, (err, data) => { + if (err) { + err.details = Object.assign(err.details || {}, { + errorTitle: 'Error', + }); + handleError(err); + return; + } + + const args = [data.message].concat(data.params); + toastr.success(TAPi18n.__.apply(TAPi18n, args), TAPi18n.__('Success')); + }); + }; + + return <> + <Button + data-qa-setting-id={_id} + children={t(actionText)} + disabled={disabled || sectionChanged} + primary + onClick={handleClick} + /> + {sectionChanged && <Field.Hint>{t('Save_to_enable_this_action')}</Field.Hint>} + </>; +} diff --git a/client/components/admin/settings/inputs/AssetSettingInput.js b/client/components/admin/settings/inputs/AssetSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..22abcbcf90edbaecc2ed6bada98d307785603955 --- /dev/null +++ b/client/components/admin/settings/inputs/AssetSettingInput.js @@ -0,0 +1,72 @@ +import { Button, Icon, Label } from '@rocket.chat/fuselage'; +import { Meteor } from 'meteor/meteor'; +import { Random } from 'meteor/random'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import React from 'react'; +import toastr from 'toastr'; + +import { handleError } from '../../../../../app/utils/client'; +import { useTranslation } from '../../../providers/TranslationProvider'; + +export function AssetSettingInput({ + _id, + label, + value, + asset, + fileConstraints, +}) { + const t = useTranslation(); + + const handleUpload = (event) => { + event = event.originalEvent || event; + + let { files } = event.target; + if (!files || files.length === 0) { + if (event.dataTransfer && event.dataTransfer.files) { + files = event.dataTransfer.files; + } else { + files = []; + } + } + + Object.values(files).forEach((blob) => { + toastr.info(TAPi18n.__('Uploading_file')); + const reader = new FileReader(); + reader.readAsBinaryString(blob); + reader.onloadend = () => Meteor.call('setAsset', reader.result, blob.type, asset, function(err) { + if (err != null) { + handleError(err); + console.log(err); + return; + } + return toastr.success(TAPi18n.__('File_uploaded')); + }); + }); + }; + + const handleDeleteButtonClick = () => { + Meteor.call('unsetAsset', asset); + }; + + return <> + <Label htmlFor={_id} text={label} title={_id} /> + <div className='settings-file-preview'> + {value.url + ? <div className='preview' style={{ backgroundImage: `url(${ value.url }?_dc=${ Random.id() })` }} /> + : <div className='preview no-file background-transparent-light secondary-font-color'><Icon icon='icon-upload' /></div>} + <div className='action'> + {value.url + ? <Button onClick={handleDeleteButtonClick}> + <Icon name='trash' />{t('Delete')} + </Button> + : <div className='rc-button rc-button--primary'>{t('Select_file')} + <input + type='file' + accept={fileConstraints.extensions && fileConstraints.extensions.length && `.${ fileConstraints.extensions.join(', .') }`} + onChange={handleUpload} + /> + </div>} + </div> + </div> + </>; +} diff --git a/client/components/admin/settings/inputs/BooleanSettingInput.js b/client/components/admin/settings/inputs/BooleanSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..b48508b45dbcedcd5fefab056c81b78fdb012fec --- /dev/null +++ b/client/components/admin/settings/inputs/BooleanSettingInput.js @@ -0,0 +1,40 @@ +import { + Field, + Label, + ToggleSwitch, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function BooleanSettingInput({ + _id, + label, + disabled, + readonly, + autocomplete, + value, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const handleChange = (event) => { + const value = event.currentTarget.checked; + onChangeValue(value); + }; + + return <Field.Row> + <Label position='end' text={label} title={_id}> + <ToggleSwitch + data-qa-setting-id={_id} + value='true' + checked={value === true} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + </Label> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row>; +} diff --git a/client/components/admin/settings/inputs/CodeSettingInput.js b/client/components/admin/settings/inputs/CodeSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..daed128d7c6c743ce1f06d4dfcf7a06475383964 --- /dev/null +++ b/client/components/admin/settings/inputs/CodeSettingInput.js @@ -0,0 +1,143 @@ +import { Button, Field, Label } from '@rocket.chat/fuselage'; +import { useToggle } from '@rocket.chat/fuselage-hooks'; +import React, { useEffect, useRef, useState } from 'react'; + +import { useTranslation } from '../../../providers/TranslationProvider'; +import { ResetSettingButton } from '../ResetSettingButton'; + +function CodeMirror({ + lineNumbers = true, + lineWrapping = true, + mode = 'javascript', + gutters = ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], + foldGutter = true, + matchBrackets = true, + autoCloseBrackets = true, + matchTags = true, + showTrailingSpace = true, + highlightSelectionMatches = true, + readOnly, + value: valueProp, + defaultValue, + onChange, + ...props +}) { + const [editor, setEditor] = useState(); + const [value, setValue] = useState(valueProp || defaultValue); + const ref = useRef(); + + useEffect(() => { + let editor; + + const setupCodeMirror = async () => { + const CodeMirror = await import('codemirror/lib/codemirror.js'); + await import('../../../../../app/ui/client/lib/codeMirror/codeMirror'); + await import('codemirror/lib/codemirror.css'); + + const { current: textarea } = ref; + + if (!textarea) { + return; + } + + editor = CodeMirror.fromTextArea(textarea, { + lineNumbers, + lineWrapping, + mode, + gutters, + foldGutter, + matchBrackets, + autoCloseBrackets, + matchTags, + showTrailingSpace, + highlightSelectionMatches, + readOnly, + }); + + editor.on('change', (doc) => { + const value = doc.getValue(); + setValue(value); + onChange(value); + }); + + setEditor(editor); + }; + + setupCodeMirror(); + + return () => { + if (!editor) { + return; + } + + editor.toTextArea(); + }; + }, [ref]); + + useEffect(() => { + setValue(valueProp); + }, [valueProp]); + + useEffect(() => { + if (!editor) { + return; + } + + if (value !== editor.getValue()) { + editor.setValue(value); + } + }, [editor, ref, value]); + + return <textarea readOnly ref={ref} style={{ display: 'none' }} value={value} {...props}/>; +} + +export function CodeSettingInput({ + _id, + label, + value, + code, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const t = useTranslation(); + + const [fullScreen, toggleFullScreen] = useToggle(false); + + const handleChange = (value) => { + onChangeValue(value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <div + className={[ + 'code-mirror-box', + fullScreen && 'code-mirror-box-fullscreen content-background-color', + ].filter(Boolean).join(' ')} + > + <div className='title'>{label}</div> + <CodeMirror + data-qa-setting-id={_id} + id={_id} + mode={code} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + <div className='buttons'> + <Button primary onClick={() => toggleFullScreen()}>{fullScreen ? t('Exit_Full_Screen') : t('Full_Screen')}</Button> + </div> + </div> + </>; +} diff --git a/client/components/admin/settings/inputs/ColorSettingInput.js b/client/components/admin/settings/inputs/ColorSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..a5523ac60f541e6d44c57fd2e0c60ba06f767bd8 --- /dev/null +++ b/client/components/admin/settings/inputs/ColorSettingInput.js @@ -0,0 +1,112 @@ +import { + Field, + InputBox, + Label, + SelectInput, + TextInput, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { useTranslation } from '../../../providers/TranslationProvider'; +import { ResetSettingButton } from '../ResetSettingButton'; + +export function ColorSettingInput({ + _id, + label, + value, + editor, + allowedTypes, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onChangeEditor, + onResetButtonClick, +}) { + const t = useTranslation(); + + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + const handleEditorTypeChange = (event) => { + const editor = event.currentTarget.value.trim(); + onChangeEditor(editor); + }; + + return <> + <div + style={{ + display: 'flex', + flexFlow: 'row nowrap', + margin: '0 -0.5rem', + }} + > + <Field + style={{ + flex: '2 2 0', + margin: '0 0.5rem', + }} + > + <Label htmlFor={_id} text={label} title={_id} /> + {editor === 'color' && <InputBox + data-qa-setting-id={_id} + type='color' + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + style={{ + width: '100%', + }} + />} + {editor === 'expression' && <TextInput + data-qa-setting-id={_id} + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + style={{ + width: '100%', + }} + />} + </Field> + <Field + style={{ + flex: '1 1 0', + margin: '0 0.5rem', + }} + > + <Field.Row> + <Label htmlFor={`${ _id }_editor`} text={t('Type')} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <SelectInput + data-qa-setting-id={`${ _id }_editor`} + type='color' + id={`${ _id }_editor`} + value={editor} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleEditorTypeChange} + > + {allowedTypes && allowedTypes.map((allowedType) => + <SelectInput.Option key={allowedType} value={allowedType}>{t(allowedType)}</SelectInput.Option> + )} + </SelectInput> + </Field> + </div> + <Field.Hint> + Variable name: {_id.replace(/theme-color-/, '@')} + </Field.Hint> + </>; +} diff --git a/client/components/admin/settings/inputs/FontSettingInput.js b/client/components/admin/settings/inputs/FontSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..899e28271195ff50f99c4eecf43db4058595f178 --- /dev/null +++ b/client/components/admin/settings/inputs/FontSettingInput.js @@ -0,0 +1,42 @@ +import { + Field, + Label, + TextInput, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function FontSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <TextInput + data-qa-setting-id={_id} + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + </>; +} diff --git a/client/components/admin/settings/inputs/GenericSettingInput.js b/client/components/admin/settings/inputs/GenericSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..c21892ae5f082c3e7583e9200f47e0e125b8ffcc --- /dev/null +++ b/client/components/admin/settings/inputs/GenericSettingInput.js @@ -0,0 +1,42 @@ +import { + Field, + Label, + TextInput, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function GenericSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <TextInput + data-qa-setting-id={_id} + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + </>; +} diff --git a/client/components/admin/settings/inputs/IntSettingInput.js b/client/components/admin/settings/inputs/IntSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..1e5048d0addb6e35f984f2fae556a77a9e9814c7 --- /dev/null +++ b/client/components/admin/settings/inputs/IntSettingInput.js @@ -0,0 +1,43 @@ +import { + Field, + Label, + InputBox, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function IntSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + onChangeValue, + hasResetButton, + onResetButtonClick, +}) { + const handleChange = (event) => { + onChangeValue(parseInt(event.currentTarget.value, 10)); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <InputBox + data-qa-setting-id={_id} + id={_id} + type='number' + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + </>; +} diff --git a/client/components/admin/settings/inputs/LanguageSettingInput.js b/client/components/admin/settings/inputs/LanguageSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..f5e9eb73ffa10354b98e681ad6c6b60de27f669e --- /dev/null +++ b/client/components/admin/settings/inputs/LanguageSettingInput.js @@ -0,0 +1,49 @@ +import { + Field, + Label, + SelectInput, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { useLanguages } from '../../../providers/TranslationProvider'; +import { ResetSettingButton } from '../ResetSettingButton'; + +export function LanguageSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const languages = useLanguages(); + + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <SelectInput + data-qa-setting-id={_id} + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + > + {languages.map(({ key, name }) => + <SelectInput.Option key={key} value={key} dir='auto'>{name}</SelectInput.Option> + )} + </SelectInput> + </>; +} diff --git a/client/components/admin/settings/inputs/PasswordSettingInput.js b/client/components/admin/settings/inputs/PasswordSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..77cd9525b3c56ec1e9357e0d94c6608e63365be5 --- /dev/null +++ b/client/components/admin/settings/inputs/PasswordSettingInput.js @@ -0,0 +1,42 @@ +import { + Field, + Label, + PasswordInput, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function PasswordSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <PasswordInput + data-qa-setting-id={_id} + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + </>; +} diff --git a/client/components/admin/settings/inputs/RelativeUrlSettingInput.js b/client/components/admin/settings/inputs/RelativeUrlSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..a675a4550497789009ebb7c576a16cce791d3528 --- /dev/null +++ b/client/components/admin/settings/inputs/RelativeUrlSettingInput.js @@ -0,0 +1,43 @@ +import { + Field, + Label, + UrlInput, +} from '@rocket.chat/fuselage'; +import { Meteor } from 'meteor/meteor'; +import React from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function RelativeUrlSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <UrlInput + data-qa-setting-id={_id} + id={_id} + value={Meteor.absoluteUrl(value)} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + </>; +} diff --git a/client/components/admin/settings/inputs/RoomPickSettingInput.js b/client/components/admin/settings/inputs/RoomPickSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..c59be9b192df6b793a0bb9a25345d3fa157f4cb3 --- /dev/null +++ b/client/components/admin/settings/inputs/RoomPickSettingInput.js @@ -0,0 +1,88 @@ +import { Field, Icon, Label } from '@rocket.chat/fuselage'; +import { Blaze } from 'meteor/blaze'; +import { Template } from 'meteor/templating'; +import React, { useRef, useEffect, useLayoutEffect } from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function RoomPickSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + value = value || []; + + const wrapperRef = useRef(); + const valueRef = useRef(value); + + const handleRemoveRoomButtonClick = (rid) => () => { + onChangeValue(value.filter(({ _id }) => _id !== rid)); + }; + + useLayoutEffect(() => { + valueRef.current = value; + }); + + useEffect(() => { + const view = Blaze.renderWithData(Template.inputAutocomplete, { + id: _id, + name: _id, + class: 'search autocomplete rc-input__element', + autocomplete: autocomplete === false ? 'off' : undefined, + readOnly: readonly, + placeholder, + disabled, + settings: { + limit: 10, + // inputDelay: 300 + rules: [ + { + // @TODO maybe change this 'collection' and/or template + collection: 'CachedChannelList', + subscription: 'channelAndPrivateAutocomplete', + field: 'name', + template: Template.roomSearch, + noMatchTemplate: Template.roomSearchEmpty, + matchAll: true, + selector: (match) => ({ name: match }), + sort: 'name', + }, + ], + }, + + }, wrapperRef.current); + + $('.autocomplete', wrapperRef.current).on('autocompleteselect', (event, doc) => { + const { current: value } = valueRef; + onChangeValue([...value.filter(({ _id }) => _id !== doc._id), doc]); + event.currentTarget.value = ''; + event.currentTarget.focus(); + }); + + return () => { + Blaze.remove(view); + }; + }, [valueRef]); + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <div style={{ position: 'relative' }} ref={wrapperRef} /> + <ul className='selected-rooms'> + {value.map(({ _id, name }) => + <li key={_id} className='remove-room' onClick={handleRemoveRoomButtonClick(_id)}> + {name} <Icon name='cross' /> + </li> + )} + </ul> + </>; +} diff --git a/client/components/admin/settings/inputs/SelectSettingInput.js b/client/components/admin/settings/inputs/SelectSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..8ad1ac8ca3c0899acaee11db72b18f8a82e3c367 --- /dev/null +++ b/client/components/admin/settings/inputs/SelectSettingInput.js @@ -0,0 +1,50 @@ +import { + Field, + Label, + SelectInput, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { useTranslation } from '../../../providers/TranslationProvider'; +import { ResetSettingButton } from '../ResetSettingButton'; + +export function SelectSettingInput({ + _id, + label, + value, + placeholder, + readonly, + autocomplete, + disabled, + values, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const t = useTranslation(); + + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + <SelectInput + data-qa-setting-id={_id} + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + > + {values.map(({ key, i18nLabel }) => + <SelectInput.Option key={key} value={key}>{t(i18nLabel)}</SelectInput.Option> + )} + </SelectInput> + </>; +} diff --git a/client/components/admin/settings/inputs/StringSettingInput.js b/client/components/admin/settings/inputs/StringSettingInput.js new file mode 100644 index 0000000000000000000000000000000000000000..17c9b1e451d6ff4873048cd6e13145b7f876b0da --- /dev/null +++ b/client/components/admin/settings/inputs/StringSettingInput.js @@ -0,0 +1,56 @@ +import { + Field, + Label, + TextAreaInput, + TextInput, +} from '@rocket.chat/fuselage'; +import React from 'react'; + +import { ResetSettingButton } from '../ResetSettingButton'; + +export function StringSettingInput({ + _id, + label, + disabled, + multiline, + placeholder, + readonly, + autocomplete, + value, + hasResetButton, + onChangeValue, + onResetButtonClick, +}) { + const handleChange = (event) => { + onChangeValue(event.currentTarget.value); + }; + + return <> + <Field.Row> + <Label htmlFor={_id} text={label} title={_id} /> + {hasResetButton && <ResetSettingButton data-qa-reset-setting-id={_id} onClick={onResetButtonClick} />} + </Field.Row> + {multiline + ? <TextAreaInput + data-qa-setting-id={_id} + id={_id} + rows={4} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> + : <TextInput + data-qa-setting-id={_id} + id={_id} + value={value} + placeholder={placeholder} + disabled={disabled} + readOnly={readonly} + autoComplete={autocomplete === false ? 'off' : undefined} + onChange={handleChange} + /> } + </>; +} diff --git a/client/components/basic/Button.js b/client/components/basic/Button.js index 60cd9708a2eca8ea5d693089eb986e467cb9d769..187409e31e962f93599367799bc7746a48de35a1 100644 --- a/client/components/basic/Button.js +++ b/client/components/basic/Button.js @@ -6,6 +6,8 @@ export const Button = ({ invisible, primary, secondary, + cancel, + nude, submit, ...props }) => <button @@ -15,6 +17,8 @@ export const Button = ({ primary && 'rc-button--primary', secondary && 'rc-button--secondary', invisible && 'rc-button--invisible', + cancel && 'rc-button--cancel', + nude && 'rc-button--nude', className, ].filter(Boolean).join(' ')} {...props} diff --git a/client/components/basic/Button.stories.js b/client/components/basic/Button.stories.js index 27428a33ba6ac268a46e21e675c3ae4919a20f39..435dc9569ce991c12ea627f48715aabe819bec98 100644 --- a/client/components/basic/Button.stories.js +++ b/client/components/basic/Button.stories.js @@ -1,20 +1,33 @@ +import { action } from '@storybook/addon-actions'; +import { boolean, text } from '@storybook/addon-knobs'; import React from 'react'; -import { rocketChatWrapper } from '../../../.storybook/helpers'; import { Button } from './Button'; export default { title: 'basic/Button', component: Button, - decorators: [ - rocketChatWrapper, - ], }; -export const _default = () => <Button>Button</Button>; +export const _default = () => <Button + children={text('children', 'Button')} + invisible={boolean('invisible')} + primary={boolean('primary')} + secondary={boolean('secondary')} + cancel={boolean('cancel')} + nude={boolean('nude')} + submit={boolean('submit')} + onClick={action('click')} +/>; export const invisible = () => <Button invisible>Button</Button>; export const primary = () => <Button primary>Button</Button>; export const secondary = () => <Button secondary>Button</Button>; + +export const cancel = () => <Button cancel>Button</Button>; + +export const nude = () => <Button nude>Button</Button>; + +export const submit = () => <Button submit>Button</Button>; diff --git a/client/components/basic/ErrorAlert.stories.js b/client/components/basic/ErrorAlert.stories.js index a5b8731620eede38f23aadc8c94829ed0217330d..1419157742e8a9d9100d9b5b7391b25054a84645 100644 --- a/client/components/basic/ErrorAlert.stories.js +++ b/client/components/basic/ErrorAlert.stories.js @@ -1,14 +1,10 @@ import React from 'react'; -import { rocketChatWrapper } from '../../../.storybook/helpers'; import { ErrorAlert } from './ErrorAlert'; export default { title: 'basic/ErrorAlert', component: ErrorAlert, - decorators: [ - rocketChatWrapper, - ], }; export const _default = () => <ErrorAlert>Content</ErrorAlert>; diff --git a/client/components/basic/Icon.js b/client/components/basic/Icon.js index 2fc4eb3322c6b509463cd14a68b56a7e9a491d50..88cc2478681b32313fff4b0db3ba404992cd3b55 100644 --- a/client/components/basic/Icon.js +++ b/client/components/basic/Icon.js @@ -1,6 +1,6 @@ import React from 'react'; -export const Icon = ({ icon, block = '', baseUrl = '', className }) => <svg +const SvgIcon = ({ icon, block = '', baseUrl = '', className }) => <svg className={[ 'rc-icon', block, @@ -11,3 +11,12 @@ export const Icon = ({ icon, block = '', baseUrl = '', className }) => <svg > <use xlinkHref={`${ baseUrl }#icon-${ icon }`} /> </svg>; + +const FontIcon = ({ icon, className }) => <i + className={[icon, className].filter(Boolean).join(' ')} +/>; + +export const Icon = ({ icon, ...props }) => + (/^icon-/.test(icon) + ? <FontIcon icon={icon} {...props} /> + : <SvgIcon icon={icon} {...props} />); diff --git a/client/components/basic/Input.stories.js b/client/components/basic/Input.stories.js index 43d1885c743c2b4e859b800a13f5d280fb2cabc4..95891b0c6fd7eb20d3dea0fdc030f33134232c50 100644 --- a/client/components/basic/Input.stories.js +++ b/client/components/basic/Input.stories.js @@ -1,14 +1,10 @@ import React from 'react'; -import { rocketChatWrapper } from '../../../.storybook/helpers'; import { Input } from './Input'; export default { title: 'basic/Input', component: Input, - decorators: [ - rocketChatWrapper, - ], }; export const _default = () => <Input />; diff --git a/client/components/basic/Link.stories.js b/client/components/basic/Link.stories.js index 6423435215e3c083dfa53e8ce9eb0c3ca3382000..90694dae63694b8e5803364c6334c2fad5041443 100644 --- a/client/components/basic/Link.stories.js +++ b/client/components/basic/Link.stories.js @@ -1,14 +1,10 @@ import React from 'react'; -import { rocketChatWrapper } from '../../../.storybook/helpers'; import { Link } from './Link'; export default { title: 'basic/Link', component: Link, - decorators: [ - rocketChatWrapper, - ], }; export const _default = () => <Link href='#'>Link</Link>; diff --git a/client/components/basic/MarkdownText.js b/client/components/basic/MarkdownText.js new file mode 100644 index 0000000000000000000000000000000000000000..698d5bde6b2b6863b38ed38434ffe47bca2d0bf2 --- /dev/null +++ b/client/components/basic/MarkdownText.js @@ -0,0 +1,5 @@ +import React from 'react'; + +import { Markdown } from '../../../app/markdown/client'; + +export const MarkdownText = ({ children }) => <span dangerouslySetInnerHTML={{ __html: Markdown.parseNotEscaped(children) }} />; diff --git a/client/components/basic/RawText.js b/client/components/basic/RawText.js new file mode 100644 index 0000000000000000000000000000000000000000..70cd93393365ed8921b6fd9b9c76523b6e579fa1 --- /dev/null +++ b/client/components/basic/RawText.js @@ -0,0 +1,3 @@ +import React from 'react'; + +export const RawText = ({ children }) => <span dangerouslySetInnerHTML={{ __html: children }} />; diff --git a/client/components/connectionStatus/ConnectionStatusAlert.js b/client/components/connectionStatus/ConnectionStatusAlert.js index 24bb99718b13537ac331cced0fd4477714d27f78..37a2ee58833ce9a1611c89fadacaa7149e29c38e 100644 --- a/client/components/connectionStatus/ConnectionStatusAlert.js +++ b/client/components/connectionStatus/ConnectionStatusAlert.js @@ -1,8 +1,8 @@ import { Icon } from '@rocket.chat/fuselage'; import React, { useEffect, useRef, useState } from 'react'; -import { useConnectionStatus, useReconnect } from '../contexts/ConnectionStatusContext'; -import { useTranslation } from '../contexts/TranslationContext'; +import { useConnectionStatus, useReconnect } from '../providers/ConnectionStatusProvider'; +import { useTranslation } from '../providers/TranslationProvider'; import './ConnectionStatusAlert.css'; export function ConnectionStatusAlert() { @@ -48,7 +48,7 @@ export function ConnectionStatusAlert() { return <div className='ConnectionStatusAlert' role='alert'> <strong> - <Icon iconName='warning' /> {t('meteor_status', { context: status })} + <Icon name='warning' /> {t('meteor_status', { context: status })} </strong> {status === 'waiting' && <> diff --git a/client/components/connectionStatus/ConnectionStatusAlert.stories.js b/client/components/connectionStatus/ConnectionStatusAlert.stories.js index 896d6376c8e76ef8ebec5f95e09f3aea80d4a6d5..91c20b065acba899e1eed83c0908ace9f0a8d064 100644 --- a/client/components/connectionStatus/ConnectionStatusAlert.stories.js +++ b/client/components/connectionStatus/ConnectionStatusAlert.stories.js @@ -1,16 +1,12 @@ import { action } from '@storybook/addon-actions'; import React from 'react'; -import { rocketChatWrapper } from '../../../.storybook/helpers'; import { ConnectionStatusAlert } from './ConnectionStatusAlert'; import { ConnectionStatusProvider } from '../providers/ConnectionStatusProvider.mock'; export default { title: 'connectionStatus/ConnectionStatusAlert', component: ConnectionStatusAlert, - decorators: [ - rocketChatWrapper, - ], }; export const connected = () => <ConnectionStatusProvider connected status='connected' reconnect={action('reconnect')}> diff --git a/client/components/contexts/ConnectionStatusContext.js b/client/components/contexts/ConnectionStatusContext.js deleted file mode 100644 index a8f33e99a4db978703cab901f14f5df6e48d4464..0000000000000000000000000000000000000000 --- a/client/components/contexts/ConnectionStatusContext.js +++ /dev/null @@ -1,14 +0,0 @@ -import { createContext, useContext } from 'react'; - -export const ConnectionStatusContext = createContext({ - status: { - connected: true, - status: 'connected', - retryCount: 0, - }, - reconnect: () => {}, -}); - -export const useConnectionStatus = () => useContext(ConnectionStatusContext).status; - -export const useReconnect = () => useContext(ConnectionStatusContext).reconnect; diff --git a/client/components/contexts/RouterContext.js b/client/components/contexts/RouterContext.js deleted file mode 100644 index bc9d41d31c532895fa7e224b57a04469f111fe8e..0000000000000000000000000000000000000000 --- a/client/components/contexts/RouterContext.js +++ /dev/null @@ -1,38 +0,0 @@ -import { createContext, useContext, useEffect, useMemo, useState } from 'react'; - -export const RouterContext = createContext({ - navigateTo: () => {}, - replaceWith: () => {}, - getRouteParameter: () => {}, - watchRouteParameter: () => {}, - getQueryStringParameter: () => {}, - watchQueryStringParameter: () => {}, -}); - -export const useRoute = (pathDefinition) => { - const { navigateTo, replaceWith } = useContext(RouterContext); - - return useMemo(() => { - const navigate = (...args) => navigateTo(pathDefinition, ...args); - navigate.replacingState = (...args) => replaceWith(pathDefinition, ...args); - return navigate; - }, [navigateTo, replaceWith]); -}; - -export const useRouteParameter = (name) => { - const { getRouteParameter, watchRouteParameter } = useContext(RouterContext); - const [parameter, setParameter] = useState(getRouteParameter(name)); - - useEffect(() => watchRouteParameter(name, setParameter), [watchRouteParameter, name]); - - return parameter; -}; - -export const useQueryStringParameter = (name) => { - const { getQueryStringParameter, watchQueryStringParameter } = useContext(RouterContext); - const [parameter, setParameter] = useState(getQueryStringParameter(name)); - - useEffect(() => watchQueryStringParameter(name, setParameter), [watchQueryStringParameter, name]); - - return parameter; -}; diff --git a/client/components/contexts/TranslationContext.js b/client/components/contexts/TranslationContext.js deleted file mode 100644 index 67986658f6a659301eac394863939c3f3b550f2e..0000000000000000000000000000000000000000 --- a/client/components/contexts/TranslationContext.js +++ /dev/null @@ -1,11 +0,0 @@ -import { createContext, useContext } from 'react'; - -const translate = function(key) { - return key; -}; - -translate.has = () => true; - -export const TranslationContext = createContext(translate); - -export const useTranslation = () => useContext(TranslationContext); diff --git a/client/components/header/BurgerMenuButton.js b/client/components/header/BurgerMenuButton.js index 42ade4c25f50e09bcddbab0471bfa217e0e342b7..0cff17f9c64eb23143ee42396a08ef7202097142 100644 --- a/client/components/header/BurgerMenuButton.js +++ b/client/components/header/BurgerMenuButton.js @@ -1,83 +1,27 @@ -import React, { useMemo } from 'react'; - -import { ChatSubscription } from '../../../app/models/client/models/ChatSubscription'; -import { menu } from '../../../app/ui-utils/client/lib/menu'; -import { useEmbeddedLayout } from '../../hooks/useEmbeddedLayout'; -import { useReactiveValue } from '../../hooks/useReactiveValue'; -import { useSession } from '../../hooks/useSession'; -import { useUserPreference } from '../../hooks/useUserPreference'; +import React from 'react'; import './BurgerMenuButton.css'; -const useSidebarState = () => { - const isOpen = useSession('isMenuOpen'); - const toggle = () => menu.toggle(); - return [isOpen, toggle]; -}; - -const useUnreadMessagesBadge = () => { - const alertUnreadMessages = useUserPreference('unreadAlert') !== false; - const openedRoom = useSession('openedRoom'); - const [unreadCount, unreadAlert] = useReactiveValue(() => ChatSubscription - .find({ - open: true, - hideUnreadStatus: { $ne: true }, - rid: { $ne: openedRoom }, - }, { - fields: { - unread: 1, - alert: 1, - unreadAlert: 1, - }, - }) - .fetch() - .reduce(([unreadCount, unreadAlert], { alert, unread, unreadAlert: alertType }) => { - if (alert || unread > 0) { - unreadCount += unread; - if (alert === true && alertType !== 'nothing') { - if (alertType === 'all' || alertUnreadMessages !== false) { - unreadAlert = '•'; - } - } - } - - return [unreadCount, unreadAlert]; - }, [0, false]), [openedRoom, alertUnreadMessages]); - - return useMemo(() => { - if (unreadCount > 0) { - return unreadCount > 99 ? '99+' : unreadCount.toString(10); - } - - return unreadAlert || ''; - }, [unreadCount, unreadAlert]); -}; - -export function BurgerMenuButton() { - const [isSidebarOpen, toggleSidebarOpen] = useSidebarState(); - const isLayoutEmbedded = useEmbeddedLayout(); - const unreadMessagesBadge = useUnreadMessagesBadge(); - - const handleClick = () => { - toggleSidebarOpen(); - }; - - return <button - aria-label={isSidebarOpen ? 'Close menu' : 'Open menu'} - className={[ - 'rc-old', - 'burger', - !!isSidebarOpen && 'menu-opened', - ].filter(Boolean).join(' ')} - type='button' - onClick={handleClick} - > - <i className='burger__line' aria-hidden='true' /> - <i className='burger__line' aria-hidden='true' /> - <i className='burger__line' aria-hidden='true' /> - {!isLayoutEmbedded && unreadMessagesBadge - && <div className='unread-burger-alert color-error-contrast background-error-color'> - {unreadMessagesBadge} - </div>} - </button>; -} +export const BurgerMenuButton = ({ + isSidebarOpen, + isLayoutEmbedded, + unreadMessagesBadge, + onClick, +}) => <button + aria-label={isSidebarOpen ? 'Close menu' : 'Open menu'} + className={[ + 'rc-old', + 'burger', + !!isSidebarOpen && 'menu-opened', + ].filter(Boolean).join(' ')} + type='button' + onClick={onClick} +> + <i className='burger__line' aria-hidden='true' /> + <i className='burger__line' aria-hidden='true' /> + <i className='burger__line' aria-hidden='true' /> + {!isLayoutEmbedded && unreadMessagesBadge + && <div className='unread-burger-alert color-error-contrast background-error-color'> + {unreadMessagesBadge} + </div>} +</button>; diff --git a/client/components/header/BurgerMenuButton.stories.js b/client/components/header/BurgerMenuButton.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..e81574d9d4c68306fcc97f1ae2422fbafa4cbdd2 --- /dev/null +++ b/client/components/header/BurgerMenuButton.stories.js @@ -0,0 +1,25 @@ +import { action } from '@storybook/addon-actions'; +import { boolean, text } from '@storybook/addon-knobs/react'; +import React from 'react'; + +import { BurgerMenuButton } from './BurgerMenuButton'; + +export default { + title: 'header/BurgerMenuButton', + component: BurgerMenuButton, + decorators: [(fn) => <div style={{ margin: '1rem' }}>{fn()}</div>], + parameters: { + viewport: { defaultViewport: 'mobile1' }, + }, +}; + +export const _default = () => <BurgerMenuButton + isSidebarOpen={boolean('isSidebarOpen')} + isLayoutEmbedded={boolean('isLayoutEmbedded')} + unreadMessagesBadge={text('unreadMessagesBadge')} + onClick={action('click')} +/>; + +export const whenSidebarOpen = () => <BurgerMenuButton isSidebarOpen />; + +export const unreadMessagesBadge = () => <BurgerMenuButton unreadMessagesBadge='99' />; diff --git a/client/components/header/Header.js b/client/components/header/Header.js index c3a3f4ff829dc7e708cbb222d1de6c32d488131d..36cf9af7e88066f6a67657c798a8a387dbf039db 100644 --- a/client/components/header/Header.js +++ b/client/components/header/Header.js @@ -1,7 +1,10 @@ +import { Text } from '@rocket.chat/fuselage'; import React from 'react'; -import { useTranslation } from '../contexts/TranslationContext'; +import { useEmbeddedLayout } from '../../hooks/useEmbeddedLayout'; +import { useTranslation } from '../providers/TranslationProvider'; import { BurgerMenuButton } from './BurgerMenuButton'; +import { useSidebarState, useUnreadMessagesBadge } from './hooks'; export function Header({ children, @@ -9,15 +12,31 @@ export function Header({ rawSectionName, sectionName, }) { + const [isSidebarOpen, toggleSidebarOpen] = useSidebarState(); + const isLayoutEmbedded = useEmbeddedLayout(); + const unreadMessagesBadge = useUnreadMessagesBadge(); const t = useTranslation(); + const handleClick = () => { + toggleSidebarOpen(); + }; + return <header className='rc-header'> <div className='rc-header__wrap'> <div className='rc-header__block rc-header--burger'> - <BurgerMenuButton /> + <BurgerMenuButton + isSidebarOpen={isSidebarOpen} + isLayoutEmbedded={isLayoutEmbedded} + unreadMessagesBadge={unreadMessagesBadge} + onClick={handleClick} + /> </div> - <span className='rc-header__block'>{rawSectionName || t(sectionName)}</span> + <span className='rc-header__block'> + <Text is='h1' headline defaultColor> + {rawSectionName || t(sectionName)} + </Text> + </span> {children} @@ -25,3 +44,7 @@ export function Header({ </div> </header>; } + +Header.ActionBlock = (props) => <div className='rc-header__block rc-header__block-action' {...props} />; + +Header.ButtonSection = (props) => <div className='rc-header__section-button' {...props} />; diff --git a/client/components/header/Header.stories.js b/client/components/header/Header.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..68142c7c47bb094127e5210629edb7a6b2564cbb --- /dev/null +++ b/client/components/header/Header.stories.js @@ -0,0 +1,32 @@ +import { boolean, text } from '@storybook/addon-knobs/react'; +import React from 'react'; + +import { Button } from '../basic/Button'; +import { Header } from './Header'; + +export default { + title: 'header/Header', + component: Header, +}; + +export const _default = () => + <Header + hideHelp={boolean('hideHelp')} + rawSectionName={text('rawSectionName')} + sectionName={text('sectionName')} + />; + +export const withRawSectionName = () => + <Header rawSectionName='Welcome to Rocket.Chat' />; + +export const withSectionName = () => + <Header sectionName='Accounts_Enrollment_Email_Subject_Default' />; + +export const withButton = () => + <Header rawSectionName='Welcome to Rocket.Chat' hideHelp> + <Header.ActionBlock> + <Button primary type='button'> + Hooray! + </Button> + </Header.ActionBlock> + </Header>; diff --git a/client/components/header/hooks.js b/client/components/header/hooks.js new file mode 100644 index 0000000000000000000000000000000000000000..7594890786295149c304f6dfc3a40dba151010b3 --- /dev/null +++ b/client/components/header/hooks.js @@ -0,0 +1,53 @@ +import { useMemo } from 'react'; + +import { ChatSubscription } from '../../../app/models/client/models/ChatSubscription'; +import { menu } from '../../../app/ui-utils/client/lib/menu'; +import { useReactiveValue } from '../../hooks/useReactiveValue'; +import { useSession } from '../../hooks/useSession'; +import { useUserPreference } from '../../hooks/useUserPreference'; + +import './BurgerMenuButton.css'; + +export const useSidebarState = () => { + const isOpen = useSession('isMenuOpen'); + const toggle = () => menu.toggle(); + return [isOpen, toggle]; +}; + +export const useUnreadMessagesBadge = () => { + const alertUnreadMessages = useUserPreference('unreadAlert') !== false; + const openedRoom = useSession('openedRoom'); + const [unreadCount, unreadAlert] = useReactiveValue(() => ChatSubscription + .find({ + open: true, + hideUnreadStatus: { $ne: true }, + rid: { $ne: openedRoom }, + }, { + fields: { + unread: 1, + alert: 1, + unreadAlert: 1, + }, + }) + .fetch() + .reduce(([unreadCount, unreadAlert], { alert, unread, unreadAlert: alertType }) => { + if (alert || unread > 0) { + unreadCount += unread; + if (alert === true && alertType !== 'nothing') { + if (alertType === 'all' || alertUnreadMessages !== false) { + unreadAlert = '•'; + } + } + } + + return [unreadCount, unreadAlert]; + }, [0, false]), [openedRoom, alertUnreadMessages]); + + return useMemo(() => { + if (unreadCount > 0) { + return unreadCount > 99 ? '99+' : unreadCount.toString(10); + } + + return unreadAlert || ''; + }, [unreadCount, unreadAlert]); +}; diff --git a/client/components/pageNotFound/PageNotFound.js b/client/components/pageNotFound/PageNotFound.js index 0b6e77a0078ff76f6e44ce48dc55a209dbc3f6a1..15f4d11c0c69d69da2c2c904923cd17f3fd87332 100644 --- a/client/components/pageNotFound/PageNotFound.js +++ b/client/components/pageNotFound/PageNotFound.js @@ -1,10 +1,11 @@ import { Button, ButtonGroup } from '@rocket.chat/fuselage'; import React from 'react'; -import { useTranslation } from '../contexts/TranslationContext'; +import { useTranslation } from '../providers/TranslationProvider'; import { useWipeInitialPageLoading } from '../../hooks/useWipeInitialPageLoading'; import { ConnectionStatusAlert } from '../connectionStatus/ConnectionStatusAlert'; -import { useRoute } from '../contexts/RouterContext'; +import { useRoute } from '../providers/RouterProvider'; +import './PageNotFound.css'; export function PageNotFound() { useWipeInitialPageLoading(); diff --git a/client/components/pageNotFound/PageNotFound.stories.js b/client/components/pageNotFound/PageNotFound.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..44c6e33737d583d2e8890016829ab4ec92c2cc10 --- /dev/null +++ b/client/components/pageNotFound/PageNotFound.stories.js @@ -0,0 +1,10 @@ +import React from 'react'; + +import { PageNotFound } from './PageNotFound'; + +export default { + title: 'pageNotFound/PageNotFound', + component: PageNotFound, +}; + +export const _default = () => <PageNotFound />; diff --git a/client/components/providers/ConnectionStatusProvider.js b/client/components/providers/ConnectionStatusProvider.js index 954136ef3d5fdd8c920b518c76f20eac229e256f..aa284d5807073cb58f94203d26c3ebb82932de0b 100644 --- a/client/components/providers/ConnectionStatusProvider.js +++ b/client/components/providers/ConnectionStatusProvider.js @@ -1,9 +1,17 @@ import { Meteor } from 'meteor/meteor'; -import React, { useMemo } from 'react'; +import React, { createContext, useContext, useMemo } from 'react'; -import { ConnectionStatusContext } from '../contexts/ConnectionStatusContext'; import { useReactiveValue } from '../../hooks/useReactiveValue'; +export const ConnectionStatusContext = createContext({ + status: { + connected: true, + status: 'connected', + retryCount: 0, + }, + reconnect: () => {}, +}); + export function ConnectionStatusProvider({ children }) { const status = useReactiveValue(() => ({ ...Meteor.status() })); @@ -16,3 +24,7 @@ export function ConnectionStatusProvider({ children }) { {children} </ConnectionStatusContext.Provider>; } + +export const useConnectionStatus = () => useContext(ConnectionStatusContext).status; + +export const useReconnect = () => useContext(ConnectionStatusContext).reconnect; diff --git a/client/components/providers/ConnectionStatusProvider.mock.js b/client/components/providers/ConnectionStatusProvider.mock.js index cab3c974e1448e98d567fe7e13cf6b35d1624cde..4997341ebc6ee1f69153be621db9735a80cd0769 100644 --- a/client/components/providers/ConnectionStatusProvider.mock.js +++ b/client/components/providers/ConnectionStatusProvider.mock.js @@ -1,6 +1,6 @@ import React from 'react'; -import { ConnectionStatusContext } from '../contexts/ConnectionStatusContext'; +import { ConnectionStatusContext } from './ConnectionStatusProvider'; export function ConnectionStatusProvider({ children, diff --git a/client/components/providers/RouterProvider.js b/client/components/providers/RouterProvider.js index 6074ee072a351d2f8267a91bc6aeeba6f65baf0d..9ff3e65a53988c0df1d01795dc08e25a4bf43e9d 100644 --- a/client/components/providers/RouterProvider.js +++ b/client/components/providers/RouterProvider.js @@ -1,8 +1,15 @@ import { FlowRouter } from 'meteor/kadira:flow-router'; import { Tracker } from 'meteor/tracker'; -import React from 'react'; +import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; -import { RouterContext } from '../contexts/RouterContext'; +export const RouterContext = createContext({ + navigateTo: () => {}, + replaceWith: () => {}, + getRouteParameter: () => {}, + watchRouteParameter: () => {}, + getQueryStringParameter: () => {}, + watchQueryStringParameter: () => {}, +}); const navigateTo = (pathDefinition, parameters, queryStringParameters) => { FlowRouter.go(pathDefinition, parameters, queryStringParameters); @@ -48,3 +55,31 @@ export function RouterProvider({ children }) { {children} </RouterContext.Provider>; } + +export const useRoute = (pathDefinition) => { + const { navigateTo, replaceWith } = useContext(RouterContext); + + return useMemo(() => { + const navigate = (...args) => navigateTo(pathDefinition, ...args); + navigate.replacingState = (...args) => replaceWith(pathDefinition, ...args); + return navigate; + }, [navigateTo, replaceWith]); +}; + +export const useRouteParameter = (name) => { + const { getRouteParameter, watchRouteParameter } = useContext(RouterContext); + const [parameter, setParameter] = useState(getRouteParameter(name)); + + useEffect(() => watchRouteParameter(name, setParameter), [watchRouteParameter, name]); + + return parameter; +}; + +export const useQueryStringParameter = (name) => { + const { getQueryStringParameter, watchQueryStringParameter } = useContext(RouterContext); + const [parameter, setParameter] = useState(getQueryStringParameter(name)); + + useEffect(() => watchQueryStringParameter(name, setParameter), [watchQueryStringParameter, name]); + + return parameter; +}; diff --git a/client/components/providers/TranslationProvider.js b/client/components/providers/TranslationProvider.js index 6baeb569e959fc12c00bd82e17fc4f8ee55ede14..2b2e169eddc005b03f9e8ca4cf4ef0ca532384a1 100644 --- a/client/components/providers/TranslationProvider.js +++ b/client/components/providers/TranslationProvider.js @@ -1,9 +1,16 @@ -import React, { useMemo } from 'react'; +import React, { createContext, useContext, useMemo } from 'react'; import { TAPi18n, TAPi18next } from 'meteor/rocketchat:tap-i18n'; -import { TranslationContext } from '../contexts/TranslationContext'; import { useReactiveValue } from '../../hooks/useReactiveValue'; +const translate = function(key) { + return key; +}; + +translate.has = () => true; + +export const TranslationContext = createContext(translate); + const createContextValue = (language) => { const translate = (key, ...replaces) => { if (typeof replaces[0] === 'object') { @@ -30,7 +37,11 @@ const createContextValue = (language) => { const has = (key, { lng = language, ...options } = {}) => TAPi18next.exists(key, { ...options, lng }); translate.has = has; - return translate; + + return { + language, + translate, + }; }; export function TranslationProvider({ children }) { @@ -42,3 +53,23 @@ export function TranslationProvider({ children }) { {children} </TranslationContext.Provider>; } + +export const useTranslation = () => useContext(TranslationContext).translate; + +export const useLanguage = () => useContext(TranslationContext).language; + +export const useLanguages = () => useReactiveValue(() => { + const languages = TAPi18n.getLanguages(); + + const result = Object.entries(languages) + .map(([key, language]) => ({ ...language, key: key.toLowerCase() })) + .sort((a, b) => a.key - b.key); + + result.unshift({ + name: 'Default', + en: 'Default', + key: '', + }); + + return result; +}, []); diff --git a/client/components/providers/TranslationProvider.mock.js b/client/components/providers/TranslationProvider.mock.js index 0337567be6bc053c7272527325d5044948672328..81e537da958c8908e76d18fc37681e5241f7cd6e 100644 --- a/client/components/providers/TranslationProvider.mock.js +++ b/client/components/providers/TranslationProvider.mock.js @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import i18next from 'i18next'; -import { TranslationContext } from '../contexts/TranslationContext'; +import { TranslationContext } from './TranslationProvider'; export function TranslationProvider({ children }) { const [contextValue, setContextValue] = useState(); diff --git a/client/components/setupWizard/Epilogue.js b/client/components/setupWizard/Epilogue.js index 9206532ca2269c3d10dbf14b0dc898770968366a..2ab1e76efc5e2b6130e69f03cfefdadb51779d41 100644 --- a/client/components/setupWizard/Epilogue.js +++ b/client/components/setupWizard/Epilogue.js @@ -1,22 +1,25 @@ -import React from 'react'; import { Button } from '@rocket.chat/fuselage'; +import React from 'react'; -import { useTranslation } from '../contexts/TranslationContext'; +import { useSetSetting } from '../../hooks/useSetSetting'; import { useSetting } from '../../hooks/useSetting'; -import { setSetting } from './functions'; +import { useTranslation } from '../providers/TranslationProvider'; import './Epilogue.css'; -export function Epilogue() { +export function Epilogue({ + logoSrc = 'images/logo/logo.svg', +}) { const t = useTranslation(); const siteUrl = useSetting('Site_Url'); + const setShowSetupWizard = useSetSetting('Show_Setup_Wizard'); const handleClick = () => { - setSetting('Show_Setup_Wizard', 'completed'); + setShowSetupWizard('completed'); }; return <section className='SetupWizard__Epilogue'> <header className='SetupWizard__Epilogue-header'> - <img className='SetupWizard__Epilogue-headerLogo' src='images/logo/logo.svg' /> + <img className='SetupWizard__Epilogue-headerLogo' src={logoSrc} /> </header> <main className='SetupWizard__Epilogue-content'> @@ -24,7 +27,7 @@ export function Epilogue() { <h1 className='SetupWizard__Epilogue-title'>{t('Your_workspace_is_ready')}</h1> <span className='SetupWizard__Epilogue-linkLabel'>{t('Your_server_link')}</span> <span className='SetupWizard__Epilogue-link'>{siteUrl}</span> - <Button type='button' primary onClick={handleClick} className='SetupWizard__Epilogue__goToWorkspace'> + <Button primary onClick={handleClick} className='SetupWizard__Epilogue__goToWorkspace'> {t('Go_to_your_workspace')} </Button> </main> diff --git a/client/components/setupWizard/Epilogue.stories.js b/client/components/setupWizard/Epilogue.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..0674903dae94e5364ec423bb64988f48cc6d2e12 --- /dev/null +++ b/client/components/setupWizard/Epilogue.stories.js @@ -0,0 +1,11 @@ +import React from 'react'; + +import { Epilogue } from './Epilogue'; + +export default { + title: 'setupWizard/Epilogue', + component: Epilogue, +}; + +export const _default = () => + <Epilogue logoSrc='https://open.rocket.chat/images/logo/logo.svg' />; diff --git a/client/components/setupWizard/Pager.js b/client/components/setupWizard/Pager.js index 018e3a18ecd81acaaabbb46ef8e841c7d6158e07..5fe1373d02881f3ea2616a89fc0aec85aa3b74be 100644 --- a/client/components/setupWizard/Pager.js +++ b/client/components/setupWizard/Pager.js @@ -1,7 +1,7 @@ import { Button, ButtonGroup } from '@rocket.chat/fuselage'; import React from 'react'; -import { useTranslation } from '../contexts/TranslationContext'; +import { useTranslation } from '../providers/TranslationProvider'; export function Pager({ disabled, onBackClick, isContinueEnabled = true }) { const t = useTranslation(); diff --git a/client/components/setupWizard/Pager.stories.js b/client/components/setupWizard/Pager.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..5bdfdb6cf0f0c2c33f9c9e7a6afa7f8252ba4152 --- /dev/null +++ b/client/components/setupWizard/Pager.stories.js @@ -0,0 +1,25 @@ +import { action } from '@storybook/addon-actions'; +import { boolean } from '@storybook/addon-knobs'; +import React from 'react'; + +import { Pager } from './Pager'; + +export default { + title: 'setupWizard/Pager', + component: Pager, +}; + +export const _default = () => + <Pager + disabled={boolean('disabled')} + isContinueEnabled={boolean('isContinueEnabled')} + />; + +export const withBackButton = () => + <Pager onBackClick={action('backClick')} />; + +export const disabled = () => + <Pager disabled onBackClick={action('backClick')} />; + +export const withContinueDisabled = () => + <Pager isContinueEnabled={false} onBackClick={action('backClick')} />; diff --git a/client/components/setupWizard/SetupWizardRoute.js b/client/components/setupWizard/SetupWizardRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..d7ec333383e98dd2f69e450b739e6200188ac216 --- /dev/null +++ b/client/components/setupWizard/SetupWizardRoute.js @@ -0,0 +1,7 @@ +import React from 'react'; + +import { SetupWizard } from './SetupWizard'; + +export function SetupWizardRoute() { + return <SetupWizard />; +} diff --git a/client/components/setupWizard/SideBar.js b/client/components/setupWizard/SideBar.js index efcb2dbc768c576c8337ec5465a200ea07f8e5b3..4429e9b365afec97bdbb5b3e4fb3e1095cd97410 100644 --- a/client/components/setupWizard/SideBar.js +++ b/client/components/setupWizard/SideBar.js @@ -1,17 +1,18 @@ import React from 'react'; -import { useTranslation } from '../contexts/TranslationContext'; -import { useSetupWizardStepsState } from './StepsState'; +import { useTranslation } from '../providers/TranslationProvider'; import './SideBar.css'; -export function SideBar({ steps = [] }) { - const { currentStep } = useSetupWizardStepsState(); - +export function SideBar({ + logoSrc = 'images/logo/logo.svg', + currentStep = 1, + steps = [], +}) { const t = useTranslation(); return <aside className='SetupWizard__SideBar'> <header className='SetupWizard__SideBar-header'> - <img className='SetupWizard__SideBar-headerLogo' src='images/logo/logo.svg' /> + <img className='SetupWizard__SideBar-headerLogo' src={logoSrc} /> <span className='SetupWizard__SideBar-headerTag'>{t('Setup_Wizard')}</span> </header> diff --git a/client/components/setupWizard/SideBar.stories.js b/client/components/setupWizard/SideBar.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..ec2cf54d4ccd846278ff5f338b3537cc05592bab --- /dev/null +++ b/client/components/setupWizard/SideBar.stories.js @@ -0,0 +1,57 @@ +import { select } from '@storybook/addon-knobs'; +import React from 'react'; + +import { SideBar } from './SideBar'; + +export default { + title: 'setupWizard/SideBar', + component: SideBar, +}; + +export const _default = () => + <SideBar + logoSrc='https://open.rocket.chat/images/logo/logo.svg' + steps={[ + { + step: 1, + title: 'Define the problem', + }, + { + step: 2, + title: 'Generate alternative solutions', + }, + { + step: 3, + title: 'Select an alternative', + }, + { + step: 4, + title: 'Implement the solution', + }, + ]} + currentStep={select('currentStep', [1, 2, 3, 4])} + />; + +export const atSomeStep = () => + <SideBar + logoSrc='https://open.rocket.chat/images/logo/logo.svg' + steps={[ + { + step: 1, + title: 'Define the problem', + }, + { + step: 2, + title: 'Generate alternative solutions', + }, + { + step: 3, + title: 'Select an alternative', + }, + { + step: 4, + title: 'Implement the solution', + }, + ]} + currentStep={2} + />; diff --git a/client/components/setupWizard/StateChecker.js b/client/components/setupWizard/StateChecker.js index ccc27966a146308a57fedf7986b70ddbb8899520..6ed11fd31a47a1b632e585317953f5d9f1840e03 100644 --- a/client/components/setupWizard/StateChecker.js +++ b/client/components/setupWizard/StateChecker.js @@ -5,7 +5,7 @@ import { Users } from '../../../app/models'; import { useSetting } from '../../hooks/useSetting'; import { useUserId } from '../../hooks/useUserId'; import { useReactiveValue } from '../../hooks/useReactiveValue'; -import { useRoute } from '../contexts/RouterContext'; +import { useRoute } from '../providers/RouterProvider'; export function StateChecker({ children }) { const setupWizardState = useSetting('Show_Setup_Wizard'); diff --git a/client/components/setupWizard/StepHeader.js b/client/components/setupWizard/StepHeader.js index 2d3560479749343a6b071e8f4cc873899ea990df..6a801872d27544a24562c2bfa40d313a3163f658 100644 --- a/client/components/setupWizard/StepHeader.js +++ b/client/components/setupWizard/StepHeader.js @@ -1,7 +1,7 @@ import { Headline } from '@rocket.chat/fuselage'; import React from 'react'; -import { useTranslation } from '../contexts/TranslationContext'; +import { useTranslation } from '../providers/TranslationProvider'; import './StepHeader.css'; export function StepHeader({ number, title }) { diff --git a/client/components/setupWizard/StepHeader.stories.js b/client/components/setupWizard/StepHeader.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..ece0dba6ee9046260e7aa15afeda58bc613cef95 --- /dev/null +++ b/client/components/setupWizard/StepHeader.stories.js @@ -0,0 +1,15 @@ +import { number, text } from '@storybook/addon-knobs'; +import React from 'react'; + +import { StepHeader } from './StepHeader'; + +export default { + title: 'setupWizard/StepHeader', + component: StepHeader, +}; + +export const _default = () => + <StepHeader + number={number('number', 1)} + title={text('title', 'Title')} + />; diff --git a/client/components/setupWizard/Steps.js b/client/components/setupWizard/Steps.js index e8dff18514a21f48c46e6abf5a9b13ccf0c97dbc..d3378f4082fe21390cd6af8a3e2af627364498e8 100644 --- a/client/components/setupWizard/Steps.js +++ b/client/components/setupWizard/Steps.js @@ -1,9 +1,9 @@ import React from 'react'; +import { useTranslation } from '../providers/TranslationProvider'; import { AdminUserInformationStep } from './steps/AdminUserInformationStep'; import { SettingsBasedStep } from './steps/SettingsBasedStep'; import { RegisterServerStep } from './steps/RegisterServerStep'; -import { useTranslation } from '../contexts/TranslationContext'; import { Epilogue } from './Epilogue'; import { SideBar } from './SideBar'; import { useSetupWizardStepsState, finalStep } from './StepsState'; @@ -36,13 +36,14 @@ export function Steps() { title: t('Register_Server'), }, ]} + currentStep={currentStep} /> <section className='SetupWizard__Steps'> <div className='SetupWizard__Steps-wrapper'> - <AdminUserInformationStep step={1} title={t('Admin_Info')} /> - <SettingsBasedStep step={2} title={t('Organization_Info')} /> - <SettingsBasedStep step={3} title={t('Server_Info')} /> - <RegisterServerStep step={4} title={t('Register_Server')} /> + <AdminUserInformationStep step={1} title={t('Admin_Info')} active={currentStep === 1} /> + <SettingsBasedStep step={2} title={t('Organization_Info')} active={currentStep === 2} /> + <SettingsBasedStep step={3} title={t('Server_Info')} active={currentStep === 3} /> + <RegisterServerStep step={4} title={t('Register_Server')} active={currentStep === 4} /> </div> </section> </>; diff --git a/client/components/setupWizard/StepsState.js b/client/components/setupWizard/StepsState.js index 40c120fe5ed062efca1f7fc4fb26ccc52b718a20..00faf62966e25d540e51e029246da8aaf0fc2889 100644 --- a/client/components/setupWizard/StepsState.js +++ b/client/components/setupWizard/StepsState.js @@ -1,9 +1,9 @@ import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; import { useUserId } from '../../hooks/useUserId'; -import { useRouteParameter, useRoute } from '../contexts/RouterContext'; +import { useRouteParameter, useRoute } from '../providers/RouterProvider'; -const Context = createContext(); +const Context = createContext({}); export const useSetupWizardStepsState = () => useContext(Context); diff --git a/client/components/setupWizard/functions.js b/client/components/setupWizard/functions.js deleted file mode 100644 index d96e0a33e90bce890149c1b7bae22fd6b4b21981..0000000000000000000000000000000000000000 --- a/client/components/setupWizard/functions.js +++ /dev/null @@ -1,20 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { settings } from '../../../app/settings/lib/settings'; - -const withPromisifiedReturn = (f) => (...args) => new Promise((resolve, reject) => { - f(...args, (error, ...returnedValues) => { - if (error) { - reject(error); - return; - } - - resolve(returnedValues); - }); -}); - -export const loginWithPassword = withPromisifiedReturn(Meteor.loginWithPassword.bind(Meteor)); - -export const batchSetSettings = withPromisifiedReturn(settings.batchSet.bind(settings)); - -export const setSetting = withPromisifiedReturn(settings.set.bind(settings)); diff --git a/client/components/setupWizard/steps/AdminUserInformationStep.js b/client/components/setupWizard/steps/AdminUserInformationStep.js index 0a278badf4cd3aaecc18923e5676927c6c84ffc8..e99663aa2f02e5a5989d5c9e1e13e3f9fc8cdad9 100644 --- a/client/components/setupWizard/steps/AdminUserInformationStep.js +++ b/client/components/setupWizard/steps/AdminUserInformationStep.js @@ -1,46 +1,57 @@ -import { Input, Field, FieldGroup, Label } from '@rocket.chat/fuselage'; +import { + EmailInput, + Field, + FieldGroup, + Icon, + Label, + PasswordInput, + TextInput, +} from '@rocket.chat/fuselage'; import { Session } from 'meteor/session'; import React, { useMemo, useState } from 'react'; import toastr from 'toastr'; -import { call } from '../../../../app/ui-utils/client'; import { handleError } from '../../../../app/utils/client'; import { callbacks } from '../../../../app/callbacks/client'; import { useFocus } from '../../../hooks/useFocus'; +import { useLoginWithPassword } from '../../../hooks/useLoginWithPassword'; +import { useMethod } from '../../../hooks/useMethod'; import { useSetting } from '../../../hooks/useSetting'; -import { useTranslation } from '../../contexts/TranslationContext'; +import { useTranslation } from '../../providers/TranslationProvider'; import { useSetupWizardStepsState } from '../StepsState'; import { Step } from '../Step'; import { StepHeader } from '../StepHeader'; import { Pager } from '../Pager'; import { StepContent } from '../StepContent'; -import { loginWithPassword } from '../functions'; -const registerAdminUser = async ({ name, username, email, password, onRegistrationEmailSent }) => { - await call('registerUser', { name, username, email, pass: password }); - callbacks.run('userRegistered'); +export function AdminUserInformationStep({ step, title, active }) { + const { goToNextStep } = useSetupWizardStepsState(); - try { - await loginWithPassword(email, password); - } catch (error) { - if (error.error === 'error-invalid-email') { - onRegistrationEmailSent && onRegistrationEmailSent(); - return; - } - handleError(error); - throw error; - } + const loginWithPassword = useLoginWithPassword(); + const registerUser = useMethod('registerUser'); + const defineUsername = useMethod('setUsername'); - Session.set('forceLogin', false); + const registerAdminUser = async ({ name, username, email, password, onRegistrationEmailSent }) => { + await registerUser({ name, username, email, pass: password }); + callbacks.run('userRegistered'); - await call('setUsername', username); + try { + await loginWithPassword(email, password); + } catch (error) { + if (error.error === 'error-invalid-email') { + onRegistrationEmailSent && onRegistrationEmailSent(); + return; + } + handleError(error); + throw error; + } + + Session.set('forceLogin', false); - callbacks.run('usernameSet'); -}; + await defineUsername(username); -export function AdminUserInformationStep({ step, title }) { - const { currentStep, goToNextStep } = useSetupWizardStepsState(); - const active = step === currentStep; + callbacks.run('usernameSet'); + }; const regexpForUsernameValidation = useSetting('UTF8_Names_Validation'); const usernameRegExp = useMemo(() => new RegExp(`^${ regexpForUsernameValidation }$`), [regexpForUsernameValidation]); @@ -111,53 +122,52 @@ export function AdminUserInformationStep({ step, title }) { <StepContent> <FieldGroup> <Field> - <Label text={t('Name')}> - <Input - ref={autoFocusRef} - type='text' - icon='user' - placeholder={t('Type_your_name')} - value={name} - onChange={({ currentTarget: { value } }) => setName(value)} - error={!isNameValid} - /> - </Label> + <Label text={t('Name')} /> + <TextInput + ref={autoFocusRef} + addon={<Icon name='user' />} + placeholder={t('Type_your_name')} + value={name} + onChange={({ currentTarget: { value } }) => setName(value)} + error={!isNameValid} + /> </Field> <Field> - <Label text={t('Username')}> - <Input - type='text' - icon='at' - placeholder={t('Type_your_username')} - value={username} - onChange={({ currentTarget: { value } }) => setUsername(value)} - error={!isUsernameValid && t('Invalid_username')} - /> - </Label> + <Field.Row> + <Label text={t('Username')} /> + {!isUsernameValid && <Field.Error>{t('Invalid_username')}</Field.Error>} + </Field.Row> + <TextInput + addon={<Icon name='at' />} + placeholder={t('Type_your_username')} + value={username} + onChange={({ currentTarget: { value } }) => setUsername(value)} + error={!isUsernameValid} + /> </Field> <Field> - <Label text={t('Organization_Email')}> - <Input - type='email' - icon='mail' - placeholder={t('Type_your_email')} - value={email} - onChange={({ currentTarget: { value } }) => setEmail(value)} - error={!isEmailValid && t('Invalid_email')} - /> - </Label> + <Field.Row> + <Label text={t('Organization_Email')} /> + {!isEmailValid && <Field.Error>{t('Invalid_email')}</Field.Error>} + </Field.Row> + <EmailInput + addon={<Icon name='mail' />} + placeholder={t('Type_your_email')} + value={email} + onChange={({ currentTarget: { value } }) => setEmail(value)} + error={!isEmailValid} + /> </Field> <Field> - <Label text={t('Password')}> - <Input - type='password' - icon='key' - placeholder={t('Type_your_password')} - value={password} - onChange={({ currentTarget: { value } }) => setPassword(value)} - error={!isPasswordValid} - /> - </Label> + <Label text={t('Password')} /> + <PasswordInput + type='password' + addon={<Icon name='key' />} + placeholder={t('Type_your_password')} + value={password} + onChange={({ currentTarget: { value } }) => setPassword(value)} + error={!isPasswordValid} + /> </Field> </FieldGroup> </StepContent> diff --git a/client/components/setupWizard/steps/AdminUserInformationStep.stories.js b/client/components/setupWizard/steps/AdminUserInformationStep.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..4a9fc568d10044285dc873aeec8938e5ae22999a --- /dev/null +++ b/client/components/setupWizard/steps/AdminUserInformationStep.stories.js @@ -0,0 +1,16 @@ +import { boolean, select, text } from '@storybook/addon-knobs'; +import React from 'react'; + +import { AdminUserInformationStep } from './AdminUserInformationStep'; + +export default { + title: 'setupWizard/steps/AdminUserInformationStep', + component: AdminUserInformationStep, +}; + +export const _default = () => + <AdminUserInformationStep + step={select('step', [1, 2, 3, 4, 'final'], 1)} + title={text('title', 'Admin Info')} + active={boolean('active', true)} + />; diff --git a/client/components/setupWizard/steps/RegisterServerStep.js b/client/components/setupWizard/steps/RegisterServerStep.js index 8a29c8d00393262f00bb752fdc95cce0a50e4fce..c57f15ea228c25dc84f00ff269d73527b738ca49 100644 --- a/client/components/setupWizard/steps/RegisterServerStep.js +++ b/client/components/setupWizard/steps/RegisterServerStep.js @@ -1,18 +1,20 @@ -import { CheckBox, Label, RadioButton, useMergedRefs } from '@rocket.chat/fuselage'; +import { CheckBox, Label, RadioButton } from '@rocket.chat/fuselage'; +import { useMergedRefs } from '@rocket.chat/fuselage-hooks'; import React, { useRef, useState } from 'react'; -import { call } from '../../../../app/ui-utils/client'; import { handleError } from '../../../../app/utils/client'; -import { useTranslation } from '../../contexts/TranslationContext'; +import { useBatchSetSettings } from '../../../hooks/useBatchSetSettings'; +import { useFocus } from '../../../hooks/useFocus'; +import { useMethod } from '../../../hooks/useMethod'; import { Icon } from '../../basic/Icon'; +import { useTranslation } from '../../providers/TranslationProvider'; import { Pager } from '../Pager'; import { useSetupWizardParameters } from '../ParametersProvider'; import { Step } from '../Step'; import { StepContent } from '../StepContent'; import { StepHeader } from '../StepHeader'; import { useSetupWizardStepsState } from '../StepsState'; -import { batchSetSettings } from '../functions'; -import { useFocus } from '../../../hooks/useFocus'; +import './RegisterServerStep.css'; const Option = React.forwardRef(({ children, label, selected, disabled, ...props }, ref) => { const innerRef = useRef(); @@ -43,11 +45,9 @@ const Item = ({ children, icon, ...props }) => {children} </li>; -export function RegisterServerStep({ step, title }) { +export function RegisterServerStep({ step, title, active }) { const { canDeclineServerRegistration } = useSetupWizardParameters(); - const { currentStep, goToPreviousStep, goToFinalStep } = useSetupWizardStepsState(); - - const active = step === currentStep; + const { goToPreviousStep, goToFinalStep } = useSetupWizardStepsState(); const [registerServer, setRegisterServer] = useState(true); const [optInMarketingEmails, setOptInMarketingEmails] = useState(true); @@ -56,6 +56,10 @@ export function RegisterServerStep({ step, title }) { const [commiting, setComitting] = useState(false); + const batchSetSettings = useBatchSetSettings(); + + const registerCloudWorkspace = useMethod('cloud:registerWorkspace'); + const handleBackClick = () => { goToPreviousStep(); }; @@ -86,7 +90,7 @@ export function RegisterServerStep({ step, title }) { ]); if (registerServer) { - await call('cloud:registerWorkspace'); + await registerCloudWorkspace(); } setComitting(false); diff --git a/client/components/setupWizard/steps/RegisterServerStep.stories.js b/client/components/setupWizard/steps/RegisterServerStep.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..cccb66ea23c8bf0810122643f73629e6fff4f757 --- /dev/null +++ b/client/components/setupWizard/steps/RegisterServerStep.stories.js @@ -0,0 +1,16 @@ +import { boolean, select, text } from '@storybook/addon-knobs'; +import React from 'react'; + +import { RegisterServerStep } from './RegisterServerStep'; + +export default { + title: 'setupWizard/steps/RegisterServerStep', + component: RegisterServerStep, +}; + +export const _default = () => + <RegisterServerStep + step={select('step', [1, 2, 3, 4, 'final'], 4)} + title={text('title', 'Register Server')} + active={boolean('active', true)} + />; diff --git a/client/components/setupWizard/steps/SettingsBasedStep.js b/client/components/setupWizard/steps/SettingsBasedStep.js index 6c0aed84efab34d9c960971aa1c8e82c0c18cd51..5123dd1e6a637ad7e97692af7ee50e2c3aaa1573 100644 --- a/client/components/setupWizard/steps/SettingsBasedStep.js +++ b/client/components/setupWizard/steps/SettingsBasedStep.js @@ -1,18 +1,18 @@ -import { Input, Field, FieldGroup, Label } from '@rocket.chat/fuselage'; +import { Field, FieldGroup, Label, SelectInput, TextInput } from '@rocket.chat/fuselage'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import React, { useEffect, useReducer, useState } from 'react'; import { handleError } from '../../../../app/utils/client'; +import { useBatchSetSettings } from '../../../hooks/useBatchSetSettings'; import { useFocus } from '../../../hooks/useFocus'; -import { useTranslation } from '../../contexts/TranslationContext'; import { useReactiveValue } from '../../../hooks/useReactiveValue'; +import { useTranslation } from '../../providers/TranslationProvider'; import { Pager } from '../Pager'; import { useSetupWizardParameters } from '../ParametersProvider'; import { useSetupWizardStepsState } from '../StepsState'; import { Step } from '../Step'; import { StepHeader } from '../StepHeader'; import { StepContent } from '../StepContent'; -import { batchSetSettings } from '../functions'; const useFields = () => { const reset = 'RESET'; @@ -37,15 +37,13 @@ const useFields = () => { return { fields, resetFields, setFieldValue }; }; -export function SettingsBasedStep({ step, title }) { +export function SettingsBasedStep({ step, title, active }) { const { settings } = useSetupWizardParameters(); const { currentStep, goToPreviousStep, goToNextStep } = useSetupWizardStepsState(); const { fields, resetFields, setFieldValue } = useFields(); const [commiting, setCommiting] = useState(false); - const active = step === currentStep; - - const languages = useReactiveValue(() => TAPi18n.getLanguages(), []); + const languages = useReactiveValue(() => TAPi18n && TAPi18n.getLanguages(), []); useEffect(() => { resetFields( @@ -59,6 +57,8 @@ export function SettingsBasedStep({ step, title }) { const t = useTranslation(); + const batchSetSettings = useBatchSetSettings(); + const handleBackClick = () => { goToPreviousStep(); }; @@ -88,42 +88,41 @@ export function SettingsBasedStep({ step, title }) { <FieldGroup> {fields.map(({ _id, type, i18nLabel, value, values }, i) => <Field key={i}> - <Label text={t(i18nLabel)}> - {type === 'string' && <Input - type='text' - name={_id} - ref={i === 0 ? autoFocusRef : undefined} - value={value} - onChange={({ currentTarget: { value } }) => setFieldValue(_id, value)} - />} - - {type === 'select' && <Input - type='select' - name={_id} - placeholder={t('Select_an_option')} - ref={i === 0 ? autoFocusRef : undefined} - value={value} - onChange={({ currentTarget: { value } }) => setFieldValue(_id, value)} - > - {values - .map(({ i18nLabel, key }) => ({ label: t(i18nLabel), value: key })) - .map(({ label, value }) => <option key={value} value={value}>{label}</option>)} - </Input>} - - {type === 'language' && <Input - type='select' - name={_id} - placeholder={t('Default')} - ref={i === 0 ? autoFocusRef : undefined} - value={value} - onChange={({ currentTarget: { value } }) => setFieldValue(_id, value)} - > - {Object.entries(languages) - .map(([key, { name }]) => ({ label: name, value: key })) - .sort((a, b) => a.key - b.key) - .map(({ label, value }) => <option key={value} value={value}>{label}</option>)} - </Input>} - </Label> + <Label text={t(i18nLabel)} /> + {type === 'string' && <TextInput + type='text' + name={_id} + ref={i === 0 ? autoFocusRef : undefined} + value={value} + onChange={({ currentTarget: { value } }) => setFieldValue(_id, value)} + />} + + {type === 'select' && <SelectInput + type='select' + name={_id} + placeholder={t('Select_an_option')} + ref={i === 0 ? autoFocusRef : undefined} + value={value} + onChange={({ currentTarget: { value } }) => setFieldValue(_id, value)} + > + {values + .map(({ i18nLabel, key }) => ({ label: t(i18nLabel), value: key })) + .map(({ label, value }) => <SelectInput.Option key={value} value={value}>{label}</SelectInput.Option>)} + </SelectInput>} + + {type === 'language' && <SelectInput + type='select' + name={_id} + placeholder={t('Default')} + ref={i === 0 ? autoFocusRef : undefined} + value={value} + onChange={({ currentTarget: { value } }) => setFieldValue(_id, value)} + > + {Object.entries(languages) + .map(([key, { name }]) => ({ label: name, value: key })) + .sort((a, b) => a.key - b.key) + .map(({ label, value }) => <SelectInput.Option key={value} value={value}>{label}</SelectInput.Option>)} + </SelectInput>} </Field> )} </FieldGroup> diff --git a/client/components/setupWizard/steps/SettingsBasedStep.stories.js b/client/components/setupWizard/steps/SettingsBasedStep.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..9d9a1ec10be6c0a2701e3fe7227f4dfa2fc77c87 --- /dev/null +++ b/client/components/setupWizard/steps/SettingsBasedStep.stories.js @@ -0,0 +1,16 @@ +import { boolean, select, text } from '@storybook/addon-knobs'; +import React from 'react'; + +import { SettingsBasedStep } from './SettingsBasedStep'; + +export default { + title: 'setupWizard/steps/SettingsBasedStep', + component: SettingsBasedStep, +}; + +export const _default = () => + <SettingsBasedStep + step={select('step', [1, 2, 3, 4, 'final'], 2)} + title={text('title', 'Settings-Based Step')} + active={boolean('active', true)} + />; diff --git a/client/hooks/useAutorun.js b/client/hooks/useAutorun.js new file mode 100644 index 0000000000000000000000000000000000000000..a0bc30c9a4f18df4bf28d3023790f229350930f2 --- /dev/null +++ b/client/hooks/useAutorun.js @@ -0,0 +1,12 @@ +import { Tracker } from 'meteor/tracker'; +import { useEffect } from 'react'; + +export const useAutorun = (autorunFunction, deps = []) => { + useEffect(() => { + const computation = Tracker.autorun(autorunFunction); + + return () => { + computation.stop(); + }; + }, deps); +}; diff --git a/client/hooks/useBatchSetSettings.js b/client/hooks/useBatchSetSettings.js new file mode 100644 index 0000000000000000000000000000000000000000..7f9ef583a093d31cef79d84e0e94fde4e1c0e9c1 --- /dev/null +++ b/client/hooks/useBatchSetSettings.js @@ -0,0 +1,14 @@ +import { useCallback } from 'react'; + +import { settings } from '../../app/settings/lib/settings'; + +export const useBatchSetSettings = () => useCallback((entries) => new Promise((resolve, reject) => { + settings.batchSet(entries, (error, result) => { + if (error) { + reject(error); + return; + } + + resolve(result); + }); +}), []); diff --git a/client/hooks/useEmbeddedLayout.js b/client/hooks/useEmbeddedLayout.js index 1c4456b1389a7f7d2a5507c623181f595a4a4411..fa6da02c4227809313cbe13f0051348efc7beca9 100644 --- a/client/hooks/useEmbeddedLayout.js +++ b/client/hooks/useEmbeddedLayout.js @@ -1,3 +1,3 @@ -import { useQueryStringParameter } from '../components/contexts/RouterContext'; +import { useQueryStringParameter } from '../components/providers/RouterProvider'; export const useEmbeddedLayout = () => useQueryStringParameter('layout') === 'embedded'; diff --git a/client/hooks/useEventCallback.js b/client/hooks/useEventCallback.js new file mode 100644 index 0000000000000000000000000000000000000000..f623844f961282b4b51fd9bcca0b2df95f7b21a5 --- /dev/null +++ b/client/hooks/useEventCallback.js @@ -0,0 +1,13 @@ +import { useCallback, useLayoutEffect, useRef } from 'react'; + +export const useEventCallback = (fn, ...deps) => { + const fnRef = useRef(fn); + const depsRef = useRef(deps); + + useLayoutEffect(() => { + fnRef.current = fn; + depsRef.current = deps; + }); + + return useCallback((...args) => (0, fnRef.current)(...depsRef.current, ...args), []); +}; diff --git a/client/hooks/useLazyRef.js b/client/hooks/useLazyRef.js new file mode 100644 index 0000000000000000000000000000000000000000..a45e92a3828d336f74288bdcaf7de51906c6dd45 --- /dev/null +++ b/client/hooks/useLazyRef.js @@ -0,0 +1,6 @@ +import { useRef, useState } from 'react'; + +export const useLazyRef = (fn) => { + const [value] = useState(fn); + return useRef(value); +}; diff --git a/client/hooks/useLoginWithPassword.js b/client/hooks/useLoginWithPassword.js new file mode 100644 index 0000000000000000000000000000000000000000..f28c29fdec0cab0c8b4a5465b43537d65aa757f7 --- /dev/null +++ b/client/hooks/useLoginWithPassword.js @@ -0,0 +1,13 @@ +import { Meteor } from 'meteor/meteor'; +import { useCallback } from 'react'; + +export const useLoginWithPassword = () => useCallback((user, password) => new Promise((resolve, reject) => { + Meteor.loginWithPassword(user, password, (error, result) => { + if (error) { + reject(error); + return; + } + + resolve(result); + }); +}), []); diff --git a/client/hooks/useMethod.js b/client/hooks/useMethod.js new file mode 100644 index 0000000000000000000000000000000000000000..f2d76e6bb90a39f4dcc1264ed87f21cf345b6fb8 --- /dev/null +++ b/client/hooks/useMethod.js @@ -0,0 +1,13 @@ +import { Meteor } from 'meteor/meteor'; +import { useCallback } from 'react'; + +export const useMethod = (methodName) => useCallback((...args) => new Promise((resolve, reject) => { + Meteor.call(methodName, ...args, (error, result) => { + if (error) { + reject(error); + return; + } + + resolve(result); + }); +}), [methodName]); diff --git a/client/hooks/useNonReactiveValue.js b/client/hooks/useNonReactiveValue.js new file mode 100644 index 0000000000000000000000000000000000000000..7f833801cbf21fbc2dfebae0c7d1cc8bd4a3a7a6 --- /dev/null +++ b/client/hooks/useNonReactiveValue.js @@ -0,0 +1,4 @@ +import { Tracker } from 'meteor/tracker'; +import { useMemo } from 'react'; + +export const useNonReactiveValue = (getValue) => useMemo(() => Tracker.nonreactive(getValue), []); diff --git a/client/hooks/useReactiveValue.js b/client/hooks/useReactiveValue.js index 00e63cad57cc7e9a2966fa232ac2f60fbcd134a4..99f38345d5db6f03a83fb5dcc3151bf36d94ebb0 100644 --- a/client/hooks/useReactiveValue.js +++ b/client/hooks/useReactiveValue.js @@ -1,18 +1,15 @@ -import { Tracker } from 'meteor/tracker'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; -export const useReactiveValue = (getValue, deps = []) => { - const [value, setValue] = useState(getValue); +import { useAutorun } from './useAutorun'; +import { useNonReactiveValue } from './useNonReactiveValue'; - useEffect(() => { - const computation = Tracker.autorun(() => { - const newValue = getValue(); - setValue(() => newValue); - }); +export const useReactiveValue = (getValue, deps = []) => { + const initialValue = useNonReactiveValue(getValue); + const [value, setValue] = useState(() => initialValue); - return () => { - computation.stop(); - }; + useAutorun(() => { + const newValue = getValue(); + setValue(() => newValue); }, deps); return value; diff --git a/client/hooks/useRocketChatInformation.js b/client/hooks/useRocketChatInformation.js new file mode 100644 index 0000000000000000000000000000000000000000..8432c9195e69cd70c6cbd83edefbf756b4f912ef --- /dev/null +++ b/client/hooks/useRocketChatInformation.js @@ -0,0 +1,3 @@ +import { Info } from '../../app/utils'; + +export const useRocketChatInformation = () => Info; diff --git a/client/hooks/useSetSetting.js b/client/hooks/useSetSetting.js new file mode 100644 index 0000000000000000000000000000000000000000..6dca2f21e1c9e22a790fa35ed8e53ad9f20cd463 --- /dev/null +++ b/client/hooks/useSetSetting.js @@ -0,0 +1,14 @@ +import { useCallback } from 'react'; + +import { settings } from '../../app/settings/lib/settings'; + +export const useSetSetting = (settingName) => useCallback((value) => new Promise((resolve, reject) => { + settings.set(settingName, value, (error, result) => { + if (error) { + reject(error); + return; + } + + resolve(result); + }); +}), [settingName]); diff --git a/client/hooks/useSetting.js b/client/hooks/useSetting.js index 1d287c2e8196bf9ff8bb52dbd3ac5c4a9b38232b..e67f2fbac18db5da8b303280c7945db6263621b7 100644 --- a/client/hooks/useSetting.js +++ b/client/hooks/useSetting.js @@ -1,4 +1,4 @@ import { settings } from '../../app/settings/client'; import { useReactiveValue } from './useReactiveValue'; -export const useSetting = (settingName) => useReactiveValue(() => settings.get(settingName)); +export const useSetting = (settingName) => useReactiveValue(() => settings.get(settingName), [settingName]); diff --git a/client/importsCss.js b/client/importsCss.js index 2fb3453faa9d20302d1c402afe9c42d798aba51c..0947ae6763026b5d807a40afa484988a382aaab6 100644 --- a/client/importsCss.js +++ b/client/importsCss.js @@ -1,4 +1,4 @@ -import './RocketChat.font.css'; +import './rocketchat.font.css'; import '../app/chatpal-search/client/style.css'; import '../app/theme/client/main.css'; import '../app/theme/client/vendor/photoswipe.css'; diff --git a/client/rocketchat.font.css b/client/rocketchat.font.css new file mode 100644 index 0000000000000000000000000000000000000000..b1d1a2b3dcd5251560b1a183e4a17d952b6b50bc --- /dev/null +++ b/client/rocketchat.font.css @@ -0,0 +1,14 @@ +@font-face { + font-family: 'RocketChat'; + font-weight: 400; + font-style: normal; + font-display: auto; + + src: url('/fonts/rocketchat.eot'); + src: + url('/fonts/rocketchat.eot?#iefix') format('embedded-opentype'), + url('/fonts/rocketchat.woff2') format('woff2'), + url('/fonts/rocketchat.woff') format('woff'), + url('/fonts/rocketchat.ttf') format('truetype'), + url('/fonts/rocketchat.svg#RocketChat') format('svg'); +} diff --git a/client/routes.js b/client/routes.js index 6fc5cbde8994e6133e8b36b9b0e1b01980e0d034..2f768d11e89998da2f22f58fb966011bc7ab9d8e 100644 --- a/client/routes.js +++ b/client/routes.js @@ -7,8 +7,9 @@ import { Blaze } from 'meteor/blaze'; import { HTML } from 'meteor/htmljs'; import { FlowRouter } from 'meteor/kadira:flow-router'; import { BlazeLayout } from 'meteor/kadira:blaze-layout'; -import { Template } from 'meteor/templating'; +import { ReactiveVar } from 'meteor/reactive-var'; import { Session } from 'meteor/session'; +import { Template } from 'meteor/templating'; import { KonchatNotification } from '../app/ui'; import { ChatSubscription } from '../app/models'; @@ -39,18 +40,29 @@ const createTemplateForComponent = async ( // eslint-disable-next-line new-cap renderContainerView = () => HTML.DIV() ) => { - const React = await import('react'); - const ReactDOM = await import('react-dom'); - const { MeteorProvider } = await import('./components/providers/MeteorProvider'); - const name = component.displayName || component.name; if (!name) { throw new Error('the component must have a name'); } + if (Template[name]) { + Template[name].props.set(props); + return name; + } + Template[name] = new Blaze.Template(name, renderContainerView); + Template[name].props = new ReactiveVar(props); + + const React = await import('react'); + const ReactDOM = await import('react-dom'); + const { MeteorProvider } = await import('./components/providers/MeteorProvider'); + + function TemplateComponent() { + return React.createElement(component, Template[name].props.get()); + } + Template[name].onRendered(() => { Template.instance().autorun((computation) => { if (computation.firstRun) { @@ -59,7 +71,7 @@ const createTemplateForComponent = async ( ReactDOM.render( React.createElement(MeteorProvider, { - children: React.createElement(component, props), + children: React.createElement(TemplateComponent), }), Template.instance().firstNode); }); }); @@ -221,60 +233,21 @@ FlowRouter.route('/setup-wizard/:step?', { }, }); -FlowRouter.route('/admin/users', { - name: 'admin-users', - action() { - BlazeLayout.render('main', { center: 'adminUsers' }); - }, -}); - -FlowRouter.route('/admin/rooms', { - name: 'admin-rooms', - action() { - BlazeLayout.render('main', { center: 'adminRooms' }); - }, -}); - -FlowRouter.route('/admin/import', { - name: 'admin-import', - action() { - BlazeLayout.render('main', { center: 'adminImport' }); - }, -}); - -FlowRouter.route('/admin/import/history', { - name: 'admin-import-history', - action() { - BlazeLayout.render('main', { center: 'adminImportHistory' }); - }, -}); - -FlowRouter.route('/admin/import/prepare/:importer', { - name: 'admin-import-prepare', - action() { - BlazeLayout.render('main', { center: 'adminImportPrepare' }); - }, -}); - -FlowRouter.route('/admin/import/progress/:importer', { - name: 'admin-import-progress', - action() { - BlazeLayout.render('main', { center: 'adminImportProgress' }); - }, -}); - FlowRouter.route('/admin/:group?', { name: 'admin', action: async ({ group = 'info' } = {}) => { switch (group) { case 'info': { - const { InformationPage } = await import('./components/admin/info/InformationPage'); - BlazeLayout.render('main', { center: await createTemplateForComponent(InformationPage) }); + const { InformationRoute } = await import('./components/admin/info/InformationRoute'); + BlazeLayout.render('main', { center: await createTemplateForComponent(InformationRoute) }); break; } - default: - BlazeLayout.render('main', { center: 'admin' }); + default: { + const { SettingsRoute } = await import('./components/admin/settings/SettingsRoute'); + BlazeLayout.render('main', { center: await createTemplateForComponent(SettingsRoute, { group }) }); + // BlazeLayout.render('main', { center: 'admin' }); + } } }, }); diff --git a/package-lock.json b/package-lock.json index ca9f47010a58f5c330320fed50e68b5b3c931176..3f502cf95d352aec4484dbe9b6f08b21fce9080e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -181,7 +181,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -374,9 +374,9 @@ } }, "@babel/types": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", - "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1292,9 +1292,9 @@ } }, "@babel/plugin-transform-flow-strip-types": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.4.tgz", - "integrity": "sha512-WyVedfeEIILYEaWGAUWzVNyqG4sfsNooMhXWsu/YzOvVGcsnPb5PguysjJqI3t3qiaYj0BR8T2f5njdjTGe44Q==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.6.3.tgz", + "integrity": "sha512-l0ETkyEofkqFJ9LS6HChNIKtVJw2ylKbhYMlJ5C6df+ldxxaLIyXY4yOdDQQspfFpV8/vDiaWoJlvflstlYNxg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -1468,9 +1468,9 @@ } }, "@babel/plugin-transform-react-constant-elements": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.6.0.tgz", - "integrity": "sha512-np/nPuII8DHOZWB3u8u+NSeKlEz0eBrOlnVksIQog4C9NGVzXO+NLxMcXn4Eu4GMFzOw2W6Tyo6L3+Wv8z9Y5w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.6.3.tgz", + "integrity": "sha512-1/YogSSU7Tby9rq2VCmhuRg+6pxsHy2rI7w/oo8RKoBt6uBUFG+mk6x13kK+FY1/ggN92HAfg7ADd1v1+NCOKg==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.0.0", @@ -1606,9 +1606,9 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.6.0.tgz", - "integrity": "sha512-yzw7EopOOr6saONZ3KA3lpizKnWRTe+rfBqg4AmQbSow7ik7fqmzrfIqt053osLwLE2AaTqGinLM2tl6+M/uog==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.6.3.tgz", + "integrity": "sha512-aiWINBrPMSC3xTXRNM/dfmyYuPNKY/aexYqBgh0HBI5Y+WO5oRAqW/oROYeYHrF4Zw12r9rK4fMk/ZlAmqx/FQ==", "dev": true, "requires": { "@babel/helper-create-class-features-plugin": "^7.6.0", @@ -1846,9 +1846,9 @@ } }, "@emotion/core": { - "version": "10.0.17", - "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.17.tgz", - "integrity": "sha512-gykyjjr0sxzVuZBVTVK4dUmYsorc2qLhdYgSiOVK+m7WXgcYTKZevGWZ7TLAgTZvMelCTvhNq8xnf8FR1IdTbg==", + "version": "10.0.21", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.21.tgz", + "integrity": "sha512-U9zbc7ovZ2ceIwbLXYZPJy6wPgnOdTNT4jENZ31ee6v2lojetV5bTbCVk6ciT8G3wQRyVaTTfUCH9WCrMzpRIw==", "dev": true, "requires": { "@babel/runtime": "^7.5.5", @@ -1860,9 +1860,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -1948,9 +1948,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -2370,17 +2370,28 @@ } }, "@rocket.chat/fuselage": { - "version": "0.2.0-alpha.4", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.2.0-alpha.4.tgz", - "integrity": "sha512-LMmzAAUZk1TYSUKURZWv2KMuc96sOsrb8j+/U7fBfW14bpzSDmsw7q6SmnVKYAfoZ6Cxa6nO77ZSxwY3/p/aMA==", + "version": "0.2.0-dev.53", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.2.0-dev.53.tgz", + "integrity": "sha512-f3TGZKgXhTRRTyNDhCUOLTPJN+I3uwi1F3s4ZoC4JAge0gM5VG5RzHDbDw9rHe7RhMEYKfxvCOTNunBkCFmTXA==", "requires": { - "@rocket.chat/icons": "^0.2.0-alpha.0" + "@rocket.chat/fuselage-tokens": "^0.2.0-alpha.15", + "@rocket.chat/icons": "^0.2.0-alpha.16" } }, + "@rocket.chat/fuselage-hooks": { + "version": "0.2.0-dev.50", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.2.0-dev.50.tgz", + "integrity": "sha512-58SuGnso0EvZlmSMjwm6Mhuv27VYdGtPV4RfU7MKtPLzgfzW5VFxLdHBCfiHLIvMlu4hQKEKsfk544Eob5ztag==" + }, + "@rocket.chat/fuselage-tokens": { + "version": "0.2.0-alpha.15", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.2.0-alpha.15.tgz", + "integrity": "sha512-vMaBpfFCYJFe4oS1YhYhOJfTNMxwwkv2Rl0KDo2OuWp4kRyNhfQG2sEDvGTM/EcZsCh0//mcbJ6neufh3jA4iQ==" + }, "@rocket.chat/icons": { - "version": "0.2.0-alpha.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.2.0-alpha.0.tgz", - "integrity": "sha512-7bzc7frrOfSypD/QvJ+eBfiD5XZSpxzN8taaOB2g0AHDUYcS/yIDpZLRH0Eq0fVe4A4gXsg0MRgcU0cJzuXQ+g==" + "version": "0.2.0-dev.49", + "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.2.0-dev.49.tgz", + "integrity": "sha512-Mk27YutpExRyBqT1ULn+6RsbzBFBpZ0dYh4EoV09eHMO9FRraK5pXJpBmqfv2+yJPff163Yu1AReNc/NICQ1Og==" }, "@rocket.chat/livechat": { "version": "1.2.5", @@ -2475,6 +2486,41 @@ } } }, + "@settlin/spacebars-loader": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@settlin/spacebars-loader/-/spacebars-loader-1.0.7.tgz", + "integrity": "sha512-i/1mtmE/53v6Kc342iJnt3HvjMVdeS/o/TEYFnxJ4oL7lF7+dK47npYmyMYAH0jj2PGl5xhyt/syGDfV35J+9Q==", + "dev": true, + "requires": { + "loader-utils": "0.2.x", + "lodash": "^4.17.15", + "meteor-blaze-tools": "^1.2.4", + "meteor-core": "^1.2.4", + "meteor-html-tools": "^1.2.4", + "meteor-htmljs": "^1.2.4", + "meteor-spacebars-compiler": "^1.2.4" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } + }, "@slack/client": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/@slack/client/-/client-4.8.0.tgz", @@ -2506,17 +2552,17 @@ } }, "@storybook/addon-actions": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-5.2.1.tgz", - "integrity": "sha512-tu4LGeRGAq+sLlsRPE1PzGyYU9JyM3HMLXnOCh5dvRSS8wnoDw1zQ55LPOXH6aoJGdsrvktiw+uTVf4OyN7ryg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-5.2.4.tgz", + "integrity": "sha512-5E8uXopy6Gq5R3MXrPf0VM9QiLaGLxLCXtDYHQ0gku+HhPYR25KQudS/PyuO+OWzuyB0fsvTi240B3zw+zilOg==", "dev": true, "requires": { - "@storybook/addons": "5.2.1", - "@storybook/api": "5.2.1", - "@storybook/client-api": "5.2.1", - "@storybook/components": "5.2.1", - "@storybook/core-events": "5.2.1", - "@storybook/theming": "5.2.1", + "@storybook/addons": "5.2.4", + "@storybook/api": "5.2.4", + "@storybook/client-api": "5.2.4", + "@storybook/components": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/theming": "5.2.4", "core-js": "^3.0.1", "fast-deep-equal": "^2.0.1", "global": "^4.3.2", @@ -2528,25 +2574,26 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } }, "@storybook/addon-knobs": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-5.2.1.tgz", - "integrity": "sha512-JCSqrGYyVVBNkudhvla7qc9m0/Mn1UMaMzIxH5kewEE1KWZcCkdXD5hDASN39pkn3mX1yyqveP8jiyIL9vVBLg==", - "dev": true, - "requires": { - "@storybook/addons": "5.2.1", - "@storybook/api": "5.2.1", - "@storybook/client-api": "5.2.1", - "@storybook/components": "5.2.1", - "@storybook/core-events": "5.2.1", - "@storybook/theming": "5.2.1", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-5.2.4.tgz", + "integrity": "sha512-VYxbDARJs5RwTEOlcfa98tkDXLcRocB7QXLqt8wwCdXPIqkuoVeQLROXGYJm2NzSn49RyHPKUuVWnRhy34qBbQ==", + "dev": true, + "requires": { + "@storybook/addons": "5.2.4", + "@storybook/api": "5.2.4", + "@storybook/client-api": "5.2.4", + "@storybook/components": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/theming": "5.2.4", + "@types/react-color": "^3.0.1", "copy-to-clipboard": "^3.0.8", "core-js": "^3.0.1", "escape-html": "^1.0.3", @@ -2561,9 +2608,9 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "qs": { @@ -2575,14 +2622,14 @@ } }, "@storybook/addon-links": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-5.2.1.tgz", - "integrity": "sha512-N5f+lzai+ctHfzHoYWECYsg3lKGJuqhkVctro46fHSW7s/GB8+l78nDcV7hDjNEXDES8QN5C1fPYihatdgpSJA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-5.2.4.tgz", + "integrity": "sha512-MG+Qne4gUWGYx2qQuLQXNcl7oOBF4PbIcR0oboZNrkZ+D+6f3nHwyb53CTtzVTc+SF45CFFYLHvFdGZvv5fcAw==", "dev": true, "requires": { - "@storybook/addons": "5.2.1", - "@storybook/core-events": "5.2.1", - "@storybook/router": "5.2.1", + "@storybook/addons": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/router": "5.2.4", "common-tags": "^1.8.0", "core-js": "^3.0.1", "global": "^4.3.2", @@ -2591,9 +2638,9 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "qs": { @@ -2604,40 +2651,67 @@ } } }, + "@storybook/addon-viewport": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-5.2.4.tgz", + "integrity": "sha512-R49wSaiouSVBYeus5Xibv+XXX9Nc3/rZ1NB5yIgj658aDeuB8WgkHbM3dKd/GrWeVZWv3o4CjW81ernd3f8sdw==", + "dev": true, + "requires": { + "@storybook/addons": "5.2.4", + "@storybook/api": "5.2.4", + "@storybook/client-logger": "5.2.4", + "@storybook/components": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/theming": "5.2.4", + "core-js": "^3.0.1", + "global": "^4.3.2", + "memoizerific": "^1.11.3", + "prop-types": "^15.7.2", + "util-deprecate": "^1.0.2" + }, + "dependencies": { + "core-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", + "dev": true + } + } + }, "@storybook/addons": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-5.2.1.tgz", - "integrity": "sha512-kdx97tTKsMf/lBlT40uLYsHMF1J71mn2j41RNaCXmWw/PrKCDmiNfinemN2wtbwRSvGqb3q/BAqjKLvUtWynGg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-5.2.4.tgz", + "integrity": "sha512-Q+bnVlBA308qnELxnh18hBDRSUgltR9KbV537285dUL/okv/NC6n51mxJwIaG+ksBW2wU+5e6tqSayaKF3uHLw==", "dev": true, "requires": { - "@storybook/api": "5.2.1", - "@storybook/channels": "5.2.1", - "@storybook/client-logger": "5.2.1", - "@storybook/core-events": "5.2.1", + "@storybook/api": "5.2.4", + "@storybook/channels": "5.2.4", + "@storybook/client-logger": "5.2.4", + "@storybook/core-events": "5.2.4", "core-js": "^3.0.1", "global": "^4.3.2", "util-deprecate": "^1.0.2" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } }, "@storybook/api": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/api/-/api-5.2.1.tgz", - "integrity": "sha512-EXN6sqkGHRuNq0W6BZXOlxe2I2dmN0yUdQLiUOpzH2I3mXnVHpad/0v76dRc9fZbC4LaYUSxR8lBTr0rqIb4mA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-5.2.4.tgz", + "integrity": "sha512-KqAB+NkHIHdwu749NDP+7i44jy1bFgpq7GTJlG+sx/XLZHQveK/8yn109g9bXHFth7SvdXI1+9GA/apzwBU/Mw==", "dev": true, "requires": { - "@storybook/channels": "5.2.1", - "@storybook/client-logger": "5.2.1", - "@storybook/core-events": "5.2.1", - "@storybook/router": "5.2.1", - "@storybook/theming": "5.2.1", + "@storybook/channels": "5.2.4", + "@storybook/client-logger": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/router": "5.2.4", + "@storybook/theming": "5.2.4", "core-js": "^3.0.1", "fast-deep-equal": "^2.0.1", "global": "^4.3.2", @@ -2648,14 +2722,14 @@ "semver": "^6.0.0", "shallow-equal": "^1.1.0", "store2": "^2.7.1", - "telejson": "^2.2.2", + "telejson": "^3.0.2", "util-deprecate": "^1.0.2" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "semver": { @@ -2667,55 +2741,55 @@ } }, "@storybook/channel-postmessage": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-5.2.1.tgz", - "integrity": "sha512-gmnn9qU1iLCpfF6bZuEM3QQOZsAviWeIpiezjrd/qkxatgr3qtbXd4EoZpcVuQw314etarWtNxVpcX6PXcASjQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-5.2.4.tgz", + "integrity": "sha512-ic7/Ho8z2/aOMjoEbr5p8rijOfO3SZdJnwMvDdUxrqvYq7yACZWidPo3w2+iBwQi9HLqEsWesP1c2doJBxVGRw==", "dev": true, "requires": { - "@storybook/channels": "5.2.1", - "@storybook/client-logger": "5.2.1", + "@storybook/channels": "5.2.4", + "@storybook/client-logger": "5.2.4", "core-js": "^3.0.1", "global": "^4.3.2", - "telejson": "^2.2.2" + "telejson": "^3.0.2" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } }, "@storybook/channels": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-5.2.1.tgz", - "integrity": "sha512-AsF/Hwx91SDOgiOGOBSWS8EJAgqVm939n2nkfdLSJQQmX5EdPRAc3EIE3f13tyQub2yNx0OR4UzQDWgjwfVsEQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-5.2.4.tgz", + "integrity": "sha512-/r39yEZ5QiGdiq95DhXBypdBo7urkD3Sp1WDyK48uGkZ0gdHWSPy3BBy8OJhEhfNz7nVisTiVIBr4gIrubKDjw==", "dev": true, "requires": { "core-js": "^3.0.1" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } }, "@storybook/client-api": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-5.2.1.tgz", - "integrity": "sha512-VxexqxrbORCGqwx2j0/91Eu1A/vq+rSVIesWwzIowmoLfBwRwDdskO20Yn9U7iMSpux4RvHGF6y1Q1ZtnXm9aA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-5.2.4.tgz", + "integrity": "sha512-SOwzEFHoNapURhNqdcI7HA76o5tkWvs2+2s++i/S7xsAd3KyefIVDOdqSMlAxJkxZb8Mlrb3UNRxlrpA8SZqNA==", "dev": true, "requires": { - "@storybook/addons": "5.2.1", - "@storybook/channel-postmessage": "5.2.1", - "@storybook/channels": "5.2.1", - "@storybook/client-logger": "5.2.1", - "@storybook/core-events": "5.2.1", - "@storybook/router": "5.2.1", + "@storybook/addons": "5.2.4", + "@storybook/channel-postmessage": "5.2.4", + "@storybook/channels": "5.2.4", + "@storybook/client-logger": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/router": "5.2.4", "common-tags": "^1.8.0", "core-js": "^3.0.1", "eventemitter3": "^4.0.0", @@ -2728,9 +2802,9 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "eventemitter3": { @@ -2763,30 +2837,30 @@ } }, "@storybook/client-logger": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-5.2.1.tgz", - "integrity": "sha512-wzxSE9t3DaLCdd/gnGFnjevmYRZ92F3TEwhUP/QDXM9cZkNsRKHkjE61qjiO5aQPaZQG6Ea9ayWEQEMgZXDucg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-5.2.4.tgz", + "integrity": "sha512-ofp6QQPQZBU+RvlAH5KpZRsfAFHecCZDnl/7YG6FwjHseJr3jHTYmBGGjJDMHFHq+Q7FGQu/yVb9lMFgoQ43QQ==", "dev": true, "requires": { "core-js": "^3.0.1" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } }, "@storybook/components": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-5.2.1.tgz", - "integrity": "sha512-cik5J/mTm1b1TOI17qM+2Mikk3rjb3SbBD4WlNz3Zvn+Hw0ukgbx6kQwVBgujhMlDtsHreidyEgIg4TM13S0Tg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-5.2.4.tgz", + "integrity": "sha512-APhw+XGag0RTCRJ8eCWKVr8dLt9SRqnS8LtzcZJbokCYRxRTFzhmX2eVEE1v+d0gHib1/yh2COxOjMzv3m/rQA==", "dev": true, "requires": { - "@storybook/client-logger": "5.2.1", - "@storybook/theming": "5.2.1", + "@storybook/client-logger": "5.2.4", + "@storybook/theming": "5.2.4", "@types/react-syntax-highlighter": "10.1.0", "core-js": "^3.0.1", "global": "^4.3.2", @@ -2806,17 +2880,17 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } }, "@storybook/core": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-5.2.1.tgz", - "integrity": "sha512-mGGvN3GWeLxZ9lYZ4IuD1IoJD+cn6XXm2Arzw+k6KEtJJDFrC5SjESTDGLVFienX5s2tgH4FjYb9Ps9sKfhHlg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-5.2.4.tgz", + "integrity": "sha512-r5kDgZETNawHxpsAPw+h+pRk6l/mJhsSHeDo9/OdYtYFW7lmk2gadViXOTM+6gIWc6vQ8y750bgkahmyIIY0nQ==", "dev": true, "requires": { "@babel/plugin-proposal-class-properties": "^7.3.3", @@ -2824,15 +2898,15 @@ "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-transform-react-constant-elements": "^7.2.0", "@babel/preset-env": "^7.4.5", - "@storybook/addons": "5.2.1", - "@storybook/channel-postmessage": "5.2.1", - "@storybook/client-api": "5.2.1", - "@storybook/client-logger": "5.2.1", - "@storybook/core-events": "5.2.1", - "@storybook/node-logger": "5.2.1", - "@storybook/router": "5.2.1", - "@storybook/theming": "5.2.1", - "@storybook/ui": "5.2.1", + "@storybook/addons": "5.2.4", + "@storybook/channel-postmessage": "5.2.4", + "@storybook/client-api": "5.2.4", + "@storybook/client-logger": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/node-logger": "5.2.4", + "@storybook/router": "5.2.4", + "@storybook/theming": "5.2.4", + "@storybook/ui": "5.2.4", "airbnb-js-shims": "^1 || ^2", "ansi-to-html": "^0.6.11", "autoprefixer": "^9.4.9", @@ -3105,9 +3179,9 @@ "dev": true }, "bluebird": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.0.tgz", - "integrity": "sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", "dev": true }, "body-parser": { @@ -3227,9 +3301,9 @@ "dev": true }, "commander": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", - "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "content-disposition": { @@ -3248,9 +3322,9 @@ "dev": true }, "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "ejs": { @@ -3461,9 +3535,9 @@ "dev": true }, "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -3808,9 +3882,9 @@ "dev": true }, "terser": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.4.tgz", - "integrity": "sha512-Kcrn3RiW8NtHBP0ssOAzwa2MsIRQ8lJWiBG/K7JgqPlomA3mtb2DEmp4/hrUA+Jujx+WZ02zqd7GYD+QRBB/2Q==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.8.tgz", + "integrity": "sha512-otmIRlRVmLChAWsnSFNO0Bfk6YySuBp6G9qrHiJwlLDd4mxe2ta4sjI7TzIR+W1nBMjilzrMcPOz9pSusgx3hQ==", "dev": true, "requires": { "commander": "^2.20.0", @@ -3960,9 +4034,9 @@ "dev": true }, "webpack": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.0.tgz", - "integrity": "sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==", + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -4038,26 +4112,26 @@ } }, "@storybook/core-events": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-5.2.1.tgz", - "integrity": "sha512-AIYV/I+baQ0KxvEM7QAKqUedLn2os0XU9HTdtfZJTC3U9wjmR2ah2ScD6T0n7PBz3MderkvZG6dNjs9h8gRquQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-5.2.4.tgz", + "integrity": "sha512-nQknCmaz2S2HW6PSGcuFzve7Y1Js2Cb268vUG0ZMNtJZwFawqYc+KSQHqmOY0pVm8dyROTcWCudPA0k+hk6N5Q==", "dev": true, "requires": { "core-js": "^3.0.1" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } }, "@storybook/node-logger": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-5.2.1.tgz", - "integrity": "sha512-rz+snXZyKwTegKEf15w4uaFWIKpgaWzTw+Ar8mxa+mX7C2DP65TOc+JGYZ7lsXdred+0WP0DhnmhGu2cX8z3lA==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-5.2.4.tgz", + "integrity": "sha512-4OOzce02IAfrRv+Y7h3icyw6WIuDekpWF2eYjgYVVvAJYklCEwgeBTBCY0/2TJjPPTBDPUKHVP1Bdz3Vpci9pA==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -4103,9 +4177,9 @@ "dev": true }, "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "supports-color": { @@ -4120,18 +4194,19 @@ } }, "@storybook/react": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-5.2.1.tgz", - "integrity": "sha512-brUG8iK2+1Fk5VFZWpAoSokCx21MaPX1zSAVA+Z/Ia0I0sFfurhpQgAGlVePTy9r7dtEEEdniZVtJOH/tHqk4Q==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-5.2.4.tgz", + "integrity": "sha512-AO0qwbD/2UGe5CrVizbaek+gCAPWkPVc0KUk38cT1mcuLpXwt1zZe7iHLQf2zOeBVSiBkPLOHrEtzDfnIJXKFQ==", "dev": true, "requires": { "@babel/plugin-transform-react-constant-elements": "^7.2.0", "@babel/preset-flow": "^7.0.0", "@babel/preset-react": "^7.0.0", - "@storybook/addons": "5.2.1", - "@storybook/core": "5.2.1", - "@storybook/node-logger": "5.2.1", + "@storybook/addons": "5.2.4", + "@storybook/core": "5.2.4", + "@storybook/node-logger": "5.2.4", "@svgr/webpack": "^4.0.3", + "@types/webpack-env": "^1.13.7", "babel-plugin-add-react-displayname": "^0.0.5", "babel-plugin-named-asset-import": "^0.3.1", "babel-plugin-react-docgen": "^3.0.0", @@ -4361,9 +4436,9 @@ "dev": true }, "bluebird": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.0.tgz", - "integrity": "sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", "dev": true }, "browserify-zlib": { @@ -4419,15 +4494,15 @@ } }, "commander": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", - "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "eslint-scope": { @@ -4652,9 +4727,9 @@ "dev": true }, "terser": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.4.tgz", - "integrity": "sha512-Kcrn3RiW8NtHBP0ssOAzwa2MsIRQ8lJWiBG/K7JgqPlomA3mtb2DEmp4/hrUA+Jujx+WZ02zqd7GYD+QRBB/2Q==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.8.tgz", + "integrity": "sha512-otmIRlRVmLChAWsnSFNO0Bfk6YySuBp6G9qrHiJwlLDd4mxe2ta4sjI7TzIR+W1nBMjilzrMcPOz9pSusgx3hQ==", "dev": true, "requires": { "commander": "^2.20.0", @@ -4722,9 +4797,9 @@ "dev": true }, "webpack": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.0.tgz", - "integrity": "sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==", + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -4780,9 +4855,9 @@ } }, "@storybook/router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/router/-/router-5.2.1.tgz", - "integrity": "sha512-Mlk275cyPoKtnP4DwQ5D8gTfnaRPL6kDZOSn0wbTMa6pQOfYKgJsa7tjzeAtZuZ/j8hKI4gAfT/auMgH6g+94A==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-5.2.4.tgz", + "integrity": "sha512-GL7eGdj5oYST0mE9fThJB9ye9tTTgrP+aP3okZ6MeMGtNytb7bmJRpAD2E4ouuPTQVppyHI5re8g/HUxUNOT1g==", "dev": true, "requires": { "@reach/router": "^1.2.1", @@ -4795,9 +4870,9 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "qs": { @@ -4809,14 +4884,14 @@ } }, "@storybook/theming": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-5.2.1.tgz", - "integrity": "sha512-lbAfcyI7Tx8swduIPmlu/jdWzqTBN/v82IEQbZbPR4LS5OHRPmhXPNgFGrcH4kFAiD0GoezSsdum1x0ZZpsQUQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-5.2.4.tgz", + "integrity": "sha512-2ZlqBrmnm8N0352Fnu2+GB3pEsHL4Eb2eKxV0VLLgkjJuAlm7CK6+I/e4ZknQWxwYm2pQj1y6ta68A62fGBYyA==", "dev": true, "requires": { "@emotion/core": "^10.0.14", "@emotion/styled": "^10.0.14", - "@storybook/client-logger": "5.2.1", + "@storybook/client-logger": "5.2.4", "common-tags": "^1.8.0", "core-js": "^3.0.1", "deep-object-diff": "^1.1.0", @@ -4829,9 +4904,9 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "resolve-from": { @@ -4843,21 +4918,19 @@ } }, "@storybook/ui": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-5.2.1.tgz", - "integrity": "sha512-h6Yf1ro/nZcz4nQAU+eSVPxVmpqv7uT7RMb3Vz+VLTY59IEA/sWcoIgA4MIxwf14nVcWOqSmVBJzNKWwc+NGJw==", - "dev": true, - "requires": { - "@storybook/addon-actions": "5.2.1", - "@storybook/addon-knobs": "5.2.1", - "@storybook/addons": "5.2.1", - "@storybook/api": "5.2.1", - "@storybook/channels": "5.2.1", - "@storybook/client-logger": "5.2.1", - "@storybook/components": "5.2.1", - "@storybook/core-events": "5.2.1", - "@storybook/router": "5.2.1", - "@storybook/theming": "5.2.1", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-5.2.4.tgz", + "integrity": "sha512-zsS43k1h4bWEW6oj9FNHlUL3niHoJJ8v7iqYbRtVM12rxrYhV3K8TGVG3LCuNB75i3Be0Myy+/RHA4x9kco08A==", + "dev": true, + "requires": { + "@storybook/addons": "5.2.4", + "@storybook/api": "5.2.4", + "@storybook/channels": "5.2.4", + "@storybook/client-logger": "5.2.4", + "@storybook/components": "5.2.4", + "@storybook/core-events": "5.2.4", + "@storybook/router": "5.2.4", + "@storybook/theming": "5.2.4", "copy-to-clipboard": "^3.0.8", "core-js": "^3.0.1", "core-js-pure": "^3.0.1", @@ -4873,7 +4946,7 @@ "qs": "^6.6.0", "react": "^16.8.3", "react-dom": "^16.8.3", - "react-draggable": "^3.3.2", + "react-draggable": "^4.0.3", "react-helmet-async": "^1.0.2", "react-hotkeys": "2.0.0-pre4", "react-sizeme": "^2.6.7", @@ -4881,14 +4954,14 @@ "resolve-from": "^5.0.0", "semver": "^6.0.0", "store2": "^2.7.1", - "telejson": "^2.2.2", + "telejson": "^3.0.2", "util-deprecate": "^1.0.2" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "qs": { @@ -5048,9 +5121,9 @@ }, "dependencies": { "@babel/types": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", - "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -5211,7 +5284,7 @@ }, "@types/events": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" }, "@types/express": { @@ -5247,6 +5320,12 @@ "integrity": "sha512-cS5owqtwzLN5kY+l+KgKdRJ/Cee8tlmQoGQuIE9tWnSmS3JMKzmxo2HIAk2wODMifGwO20d62xZQLYz+RLfXmw==", "dev": true }, + "@types/is-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz", + "integrity": "sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w==", + "dev": true + }, "@types/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/is-stream/-/is-stream-1.1.0.tgz", @@ -5316,9 +5395,9 @@ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, "@types/reach__router": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.2.5.tgz", - "integrity": "sha512-Lna9cD38dN3deqJ6ThZgMKoAzW1LE3u+uUbPGdHUqquoM/fnZitSV1xfJxHjovu4SsNkpN9udkte3wEyrBPawQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.2.6.tgz", + "integrity": "sha512-Oh5DAVr/L2svBvubw6QEFpXGu295Y406BPs4i9t1n2pp7M+q3pmCmhzb9oZV5wncR41KCD3NHl1Yhi7uKnTPsA==", "dev": true, "requires": { "@types/history": "*", @@ -5326,15 +5405,24 @@ } }, "@types/react": { - "version": "16.9.4", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.4.tgz", - "integrity": "sha512-ItGNmJvQ0IvWt8rbk5PLdpdQhvBVxAaXI9hDlx7UMd8Ie1iMIuwMNiKeTfmVN517CdplpyXvA22X4zm4jGGZnw==", + "version": "16.9.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.6.tgz", + "integrity": "sha512-ulPWlBFO0DQiObqxEm3t4icozuakPy5O81g6QyHv+Nyo1UPL+QVq2rmq1e4J8oHY7jl0HEtMAHNwNIzv6FRuTQ==", "dev": true, "requires": { "@types/prop-types": "*", "csstype": "^2.2.0" } }, + "@types/react-color": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.1.tgz", + "integrity": "sha512-J6mYm43Sid9y+OjZ7NDfJ2VVkeeuTPNVImNFITgQNXodHteKfl/t/5pAR5Z9buodZ2tCctsZjgiMlQOpfntakw==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-syntax-highlighter": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-10.1.0.tgz", @@ -5374,6 +5462,12 @@ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-Set5ZdrAaKI/qHdFlVMgm/GsAv/wkXhSTuZFkJ+JI7HK+wIkIlOaUXSXieIvJ0+OvGIqtREFoE+NHJtEq0gtEw==" }, + "@types/webpack-env": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.14.1.tgz", + "integrity": "sha512-0Ki9jAAhKDSuLDXOIMADg54Hu60SuBTEsWaJGGy5cV+SSUQ63J2a+RrYYGrErzz39fXzTibhKrAQJAb8M7PNcA==", + "dev": true + }, "@types/ws": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-5.1.2.tgz", @@ -5846,12 +5940,12 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, "ansi-to-html": { - "version": "0.6.11", - "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.11.tgz", - "integrity": "sha512-88XZtrcwrfkyn6fGstHnkaF1kl7hGtNCYh4vSmItgEV+6JnQHryDBf7udF4f2RhTRQmYvJvPcTtqgaqrxzc9oA==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.12.tgz", + "integrity": "sha512-qBkIqLW979675mP76yB7yVkzeAWtATegdnDQ0RA3CZzknx0yUlNxMSML4xFdBfTs2GWYFQ1FELfbGbVSPzJ+LA==", "dev": true, "requires": { - "entities": "^1.1.1" + "entities": "^1.1.2" } }, "anymatch": { @@ -6113,25 +6207,77 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, "array.prototype.flat": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz", - "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.2.tgz", + "integrity": "sha512-VXjh7lAL4KXKF2hY4FnEW9eRW6IhdvFW1sN/JwLbmECbCgACCnBHNyP3lFiYuttr0jxRN9Bsc5+G27dMseSWqQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.10.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.15.0", "function-bind": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.15.0.tgz", + "integrity": "sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "array.prototype.flatmap": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.1.tgz", - "integrity": "sha512-i18e2APdsiezkcqDyZor78Pbfjfds3S94dG6dgIV2ZASJaUf1N0dz2tGdrmwrmlZuNUgxH+wz6Z0zYVH2c5xzQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.2.tgz", + "integrity": "sha512-ZZtPLE74KNE+0XcPv/vQmcivxN+8FhwOLvt2udHauO0aDEpsXDQrmd5HuJGpgPVyaV8HvkDPWnJ2iaem0oCKtA==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.10.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.15.0", "function-bind": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.15.0.tgz", + "integrity": "sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "arraybuffer-to-string": { @@ -6364,7 +6510,7 @@ "dependencies": { "buffer": { "version": "4.9.1", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "requires": { "base64-js": "^1.0.2", @@ -6396,7 +6542,7 @@ }, "axios": { "version": "0.18.0", - "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { "follow-redirects": "^1.3.0", @@ -6481,7 +6627,7 @@ "dependencies": { "jsesc": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true } @@ -6796,7 +6942,7 @@ }, "babel-plugin-add-module-exports": { "version": "0.2.1", - "resolved": "http://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz", "integrity": "sha1-mumh9KjcZ/DN7E9K7aHkOl/2XiU=", "dev": true }, @@ -6831,9 +6977,9 @@ } }, "babel-plugin-emotion": { - "version": "10.0.19", - "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.19.tgz", - "integrity": "sha512-1pJb5uKN/gx6bi3gGr588Krj49sxARI9KmxhtMUa+NRJb6lR3OfC51mh3NlWRsOqdjWlT4cSjnZpnFq5K3T5ZA==", + "version": "10.0.21", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.21.tgz", + "integrity": "sha512-03o+T6sfVAJhNDcSdLapgv4IeewcFPzxlvBUVdSf7o5PI57ZSxoDvmy+ZulVWSu+rOWAWkEejNcsb29TuzJHbg==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", @@ -6860,9 +7006,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -7047,78 +7193,78 @@ }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", "dev": true }, "babel-plugin-syntax-async-generators": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", "dev": true }, "babel-plugin-syntax-class-constructor-call": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=", "dev": true }, "babel-plugin-syntax-class-properties": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", "dev": true }, "babel-plugin-syntax-decorators": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", "dev": true }, "babel-plugin-syntax-do-expressions": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz", "integrity": "sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0=", "dev": true }, "babel-plugin-syntax-dynamic-import": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", "dev": true }, "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", "dev": true }, "babel-plugin-syntax-export-extensions": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=", "dev": true }, "babel-plugin-syntax-flow": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", "dev": true }, "babel-plugin-syntax-function-bind": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz", "integrity": "sha1-SMSV8Xe98xqYHnMvVa3AvdJgH0Y=", "dev": true }, "babel-plugin-syntax-jsx": { "version": "6.18.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "dev": true }, @@ -7593,7 +7739,7 @@ }, "babel-preset-es2015": { "version": "6.3.13", - "resolved": "http://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.3.13.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.3.13.tgz", "integrity": "sha1-l9zn7ykuGMubK3VF2AxZPCjZUX8=", "dev": true, "requires": { @@ -7652,7 +7798,7 @@ }, "babel-preset-react": { "version": "6.3.13", - "resolved": "http://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.3.13.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.3.13.tgz", "integrity": "sha1-E9VeBqZfqqoHw5v2Op2DbgMhFvo=", "dev": true, "requires": { @@ -7720,12 +7866,12 @@ } }, "@babel/generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.2.tgz", - "integrity": "sha512-j8iHaIW4gGPnViaIHI7e9t/Hl8qLjERI6DcV9kEpAIDJsAOrcnXqRS7t+QbhL76pwbtqP+QCQLL0z1CyVmtjjQ==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", + "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", "dev": true, "requires": { - "@babel/types": "^7.6.0", + "@babel/types": "^7.6.3", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -7741,9 +7887,9 @@ } }, "@babel/parser": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.2.tgz", - "integrity": "sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", + "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", "dev": true }, "@babel/plugin-proposal-object-rest-spread": { @@ -7756,6 +7902,16 @@ "@babel/plugin-syntax-object-rest-spread": "^7.2.0" } }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.4.tgz", + "integrity": "sha512-WyVedfeEIILYEaWGAUWzVNyqG4sfsNooMhXWsu/YzOvVGcsnPb5PguysjJqI3t3qiaYj0BR8T2f5njdjTGe44Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0" + } + }, "@babel/preset-env": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.0.tgz", @@ -7835,26 +7991,26 @@ } }, "@babel/traverse": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.2.tgz", - "integrity": "sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", + "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.2", + "@babel/generator": "^7.6.3", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.2", - "@babel/types": "^7.6.0", + "@babel/parser": "^7.6.3", + "@babel/types": "^7.6.3", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" } }, "@babel/types": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", - "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -7872,9 +8028,9 @@ } }, "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -7908,7 +8064,7 @@ }, "babel-preset-stage-0": { "version": "6.3.13", - "resolved": "http://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.3.13.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.3.13.tgz", "integrity": "sha1-eKN8VvCzmI8qeZMtywzrj/N3sNE=", "dev": true, "requires": { @@ -8821,7 +8977,7 @@ }, "bl": { "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "requires": { "readable-stream": "^2.3.5", @@ -9086,7 +9242,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", @@ -9120,7 +9276,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { "bn.js": "^4.1.0", @@ -9308,7 +9464,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -9420,7 +9576,7 @@ "dependencies": { "callsites": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true } @@ -9511,7 +9667,7 @@ "dependencies": { "cheerio": { "version": "0.19.0", - "resolved": "http://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", "integrity": "sha1-dy5wFfLuKZZQltcepBdbdas1SSU=", "requires": { "css-select": "~1.0.0", @@ -9523,7 +9679,7 @@ }, "css-select": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz", "integrity": "sha1-sRIcpRhI3SZOIkTQWM7iVN7rRLA=", "requires": { "boolbase": "~1.0.0", @@ -9534,7 +9690,7 @@ }, "css-what": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", "integrity": "sha1-18wt9FGAZm+Z0rFEYmOUaeAPc2w=" }, "domhandler": { @@ -9555,7 +9711,7 @@ }, "htmlparser2": { "version": "3.8.3", - "resolved": "http://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", "requires": { "domelementtype": "1", @@ -9576,7 +9732,7 @@ }, "entities": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" } } @@ -9588,12 +9744,12 @@ }, "lodash": { "version": "3.10.1", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -9604,7 +9760,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" } } @@ -9682,7 +9838,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -9756,7 +9912,7 @@ }, "cheerio": { "version": "0.22.0", - "resolved": "http://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", "requires": { "css-select": "~1.2.0", @@ -9785,7 +9941,7 @@ }, "chimp": { "version": "0.51.1", - "resolved": "http://registry.npmjs.org/chimp/-/chimp-0.51.1.tgz", + "resolved": "https://registry.npmjs.org/chimp/-/chimp-0.51.1.tgz", "integrity": "sha1-6hIbzfJsidV/jvNBlUDPPCeaPMU=", "dev": true, "requires": { @@ -9831,7 +9987,7 @@ "dependencies": { "async": { "version": "0.9.2", - "resolved": "http://registry.npmjs.org/async/-/async-0.9.2.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", "dev": true }, @@ -9903,7 +10059,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -9955,7 +10111,7 @@ }, "progress": { "version": "1.1.8", - "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, @@ -9978,7 +10134,7 @@ }, "chokidar": { "version": "1.6.1", - "resolved": "http://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz", "integrity": "sha1-L0RHq16W5Q+z14n9kNTHLg5McMI=", "dev": true, "requires": { @@ -10377,7 +10533,7 @@ }, "color-convert": { "version": "0.5.3", - "resolved": "http://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" }, "color-name": { @@ -10396,7 +10552,7 @@ }, "colors": { "version": "1.1.2", - "resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, @@ -10638,9 +10794,9 @@ } }, "core-js-pure": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.2.1.tgz", - "integrity": "sha512-+qpvnYrsi/JDeQTArB7NnNc2VoMYLE1YSkziCDHgjexC2KH7OFiGhLUd3urxfyWmNjSwSW7NYXPWHMhuIJx9Ow==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.3.2.tgz", + "integrity": "sha512-sw695hB0UxFXrSkUthEby5tMdjOYN3hVC8IGQePF1m3JYb9e/KjT0TOFWzaSzlKwGNglKCgLYUjiJ7uZvactiw==", "dev": true }, "core-util-is": { @@ -10871,9 +11027,9 @@ "dev": true }, "bluebird": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.0.tgz", - "integrity": "sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", "dev": true }, "browserify-zlib": { @@ -10929,9 +11085,9 @@ } }, "commander": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", - "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "eslint-scope": { @@ -11148,9 +11304,9 @@ "dev": true }, "terser": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.4.tgz", - "integrity": "sha512-Kcrn3RiW8NtHBP0ssOAzwa2MsIRQ8lJWiBG/K7JgqPlomA3mtb2DEmp4/hrUA+Jujx+WZ02zqd7GYD+QRBB/2Q==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.8.tgz", + "integrity": "sha512-otmIRlRVmLChAWsnSFNO0Bfk6YySuBp6G9qrHiJwlLDd4mxe2ta4sjI7TzIR+W1nBMjilzrMcPOz9pSusgx3hQ==", "dev": true, "requires": { "commander": "^2.20.0", @@ -11218,9 +11374,9 @@ "dev": true }, "webpack": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.0.tgz", - "integrity": "sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==", + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -11342,7 +11498,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", @@ -11354,7 +11510,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", @@ -11386,7 +11542,7 @@ "dependencies": { "node-fetch": { "version": "2.1.2", - "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" } } @@ -11611,9 +11767,9 @@ "dev": true }, "schema-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.4.1.tgz", - "integrity": "sha512-RqYLpkPZX5Oc3fw/kHHHyP56fg5Y+XBpIpV8nCg0znIALfq3OH+Ea9Hfeac9BAMwG5IICltiZ0vxFvJQONfA5w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -11648,7 +11804,7 @@ }, "css-select": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "requires": { "boolbase": "~1.0.0", @@ -11741,9 +11897,9 @@ } }, "csstype": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.6.tgz", - "integrity": "sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.7.tgz", + "integrity": "sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ==", "dev": true }, "csv-parse": { @@ -11799,11 +11955,17 @@ "dependencies": { "core-js": { "version": "1.2.7", - "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" } } }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -12201,7 +12363,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -12294,7 +12456,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -12323,7 +12485,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", @@ -12342,7 +12504,7 @@ }, "doctrine": { "version": "1.5.0", - "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { @@ -12379,7 +12541,7 @@ "dependencies": { "domelementtype": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" } } @@ -12647,9 +12809,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -12841,7 +13003,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { "es6-promise": "^4.0.3" @@ -13326,7 +13488,7 @@ }, "events": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, "eventsource": { @@ -13564,7 +13726,7 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", @@ -13583,7 +13745,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { "depd": "~1.1.2", @@ -13753,7 +13915,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { @@ -13955,13 +14117,13 @@ "dependencies": { "lodash": { "version": "2.4.2", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", "dev": true }, "underscore.string": { "version": "2.3.3", - "resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", "dev": true } @@ -15120,7 +15282,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, "get-value": { @@ -15369,7 +15531,7 @@ "dependencies": { "minimist": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=", "dev": true } @@ -16065,7 +16227,7 @@ }, "hapi": { "version": "8.8.0", - "resolved": "http://registry.npmjs.org/hapi/-/hapi-8.8.0.tgz", + "resolved": "https://registry.npmjs.org/hapi/-/hapi-8.8.0.tgz", "integrity": "sha1-h+N6Bum0meiXkOLcERqpZotuYX8=", "dev": true, "requires": { @@ -16135,7 +16297,7 @@ }, "catbox": { "version": "4.3.0", - "resolved": "http://registry.npmjs.org/catbox/-/catbox-4.3.0.tgz", + "resolved": "https://registry.npmjs.org/catbox/-/catbox-4.3.0.tgz", "integrity": "sha1-IiN3vWfxKRrA4l0AAC0GWp3385o=", "dev": true, "requires": { @@ -16232,7 +16394,7 @@ }, "joi": { "version": "6.4.1", - "resolved": "http://registry.npmjs.org/joi/-/joi-6.4.1.tgz", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.4.1.tgz", "integrity": "sha1-9Q9CRTVgBo5jg9oVrC0w3Xzra24=", "dev": true, "requires": { @@ -16244,7 +16406,7 @@ "dependencies": { "isemail": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/isemail/-/isemail-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.1.1.tgz", "integrity": "sha1-4Mj23D9HCX53dzlcaJYnGqJWw7U=", "dev": true }, @@ -16277,7 +16439,7 @@ "dependencies": { "mime-db": { "version": "1.14.0", - "resolved": "http://registry.npmjs.org/mime-db/-/mime-db-1.14.0.tgz", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.14.0.tgz", "integrity": "sha1-1WHxC27mbbUflK5leilRp0IX7YM=", "dev": true } @@ -16678,9 +16840,9 @@ }, "dependencies": { "commander": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", - "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "source-map": { @@ -16690,13 +16852,21 @@ "dev": true }, "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.1.tgz", + "integrity": "sha512-+dSJLJpXBb6oMHP+Yvw8hUgElz4gLTh82XuX68QiJVTXaE5ibl6buzhNkQdYhBlIhozWOC9ge16wyRmjG4TwVQ==", "dev": true, "requires": { - "commander": "~2.20.0", + "commander": "2.20.0", "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + } } } } @@ -16787,7 +16957,7 @@ "dependencies": { "domelementtype": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" }, "readable-stream": { @@ -16804,7 +16974,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { "depd": "~1.1.2", @@ -17242,7 +17412,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -17602,7 +17772,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -17779,7 +17949,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-object": { @@ -17957,7 +18127,7 @@ }, "isemail": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" }, "isexe": { @@ -18010,7 +18180,7 @@ }, "jasmine-core": { "version": "2.99.1", - "resolved": "http://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", "dev": true }, @@ -18221,12 +18391,12 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { @@ -18469,18 +18639,18 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" } }, "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true }, "dotenv": { @@ -18605,7 +18775,7 @@ }, "promise": { "version": "6.1.0", - "resolved": "http://registry.npmjs.org/promise/-/promise-6.1.0.tgz", + "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=", "optional": true, "requires": { @@ -18837,7 +19007,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -18849,7 +19019,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -19412,7 +19582,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -19658,6 +19828,40 @@ } } }, + "meteor-blaze-tools": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/meteor-blaze-tools/-/meteor-blaze-tools-1.5.0.tgz", + "integrity": "sha1-Ooyy2puO9fFP+Tc4VrjEqYeTvRw=", + "dev": true, + "requires": { + "meteor-core": "^1.2.0", + "meteor-htmljs": "^1.2.0" + } + }, + "meteor-core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/meteor-core/-/meteor-core-1.3.1.tgz", + "integrity": "sha1-Ql3Py8oLRQQjAlBKXnF9wRN6os8=", + "dev": true + }, + "meteor-html-tools": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/meteor-html-tools/-/meteor-html-tools-1.5.0.tgz", + "integrity": "sha1-RGnGNccrKqtSUnAIFkAK5DMwQ8M=", + "dev": true, + "requires": { + "meteor-core": "^1.2.0" + } + }, + "meteor-htmljs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/meteor-htmljs/-/meteor-htmljs-1.5.0.tgz", + "integrity": "sha1-FMxvcfvK9XBSCR61vq5Z8vBbc98=", + "dev": true, + "requires": { + "meteor-core": "^1.2.0" + } + }, "meteor-node-stubs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-0.4.1.tgz", @@ -19777,7 +19981,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -19799,7 +20003,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -19834,6 +20038,17 @@ "integrity": "sha512-HP6tOr67z/9XU2Dr0F2SSr8WRTuE23AG9Dj578DCJPEYHs67OLKBviU8A8rwvbwMD7Lu2+Of+yAMz2Wd8r4yxg==", "dev": true }, + "meteor-spacebars-compiler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/meteor-spacebars-compiler/-/meteor-spacebars-compiler-1.3.2.tgz", + "integrity": "sha1-KcRzTt1FgfRk1w4UMD8N7A3RSVs=", + "dev": true, + "requires": { + "meteor-blaze-tools": "^1.2.0", + "meteor-html-tools": "^1.2.0", + "meteor-htmljs": "^1.2.0" + } + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -19995,7 +20210,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minimist-options": { @@ -20101,7 +20316,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -20134,7 +20349,7 @@ }, "commander": { "version": "2.15.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, @@ -20482,7 +20697,7 @@ }, "ncp": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", "optional": true }, @@ -20858,7 +21073,7 @@ }, "npm-install-package": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/npm-install-package/-/npm-install-package-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/npm-install-package/-/npm-install-package-2.1.0.tgz", "integrity": "sha1-1+/jz816sAYUuJbqUxGdyaslkSU=", "dev": true }, @@ -21139,7 +21354,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { "lcid": "^1.0.0" @@ -21229,7 +21444,7 @@ }, "pako": { "version": "0.2.9", - "resolved": "http://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" }, "parallel-transform": { @@ -21254,7 +21469,7 @@ }, "parse-asn1": { "version": "5.1.1", - "resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "requires": { "asn1.js": "^4.0.0", @@ -21481,7 +21696,7 @@ }, "es6-promise": { "version": "4.0.5", - "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", "integrity": "sha1-eILzCt3lskDM+n99eMVIMwlRrkI=", "dev": true }, @@ -21537,7 +21752,7 @@ }, "progress": { "version": "1.1.8", - "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, @@ -21585,7 +21800,7 @@ }, "tough-cookie": { "version": "2.3.4", - "resolved": "http://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "dev": true, "requires": { @@ -21818,9 +22033,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -22003,7 +22218,7 @@ }, "globby": { "version": "6.1.0", - "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { @@ -22016,7 +22231,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -22486,6 +22701,19 @@ "integrity": "sha512-L36NZwq2UK743US+vl1CRMdBRZCBmFYfThP9n9jCFhX1Wfk6BqnRSgt0Fy8q44IwxPee/GCzlo7T1c1JIeUDlQ==", "dev": true }, + "postcss-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-8.0.0.tgz", + "integrity": "sha512-E2cbOQ5aii2zNHh8F6fk1cxls7QVFZjLPSrqvmiza8OuXLzIpErij8BDS5Y3STPfJgpIMNCPEr8JlKQWEoozUw==", + "dev": true, + "requires": { + "mime": "^2.3.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.0", + "postcss": "^7.0.2", + "xxhashjs": "^0.2.1" + } + }, "postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", @@ -22848,9 +23076,9 @@ }, "dependencies": { "es-abstract": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", - "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.15.0.tgz", + "integrity": "sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ==", "dev": true, "requires": { "es-to-primitive": "^1.2.0", @@ -22861,8 +23089,8 @@ "is-regex": "^1.0.4", "object-inspect": "^1.6.0", "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.0.0", - "string.prototype.trimright": "^2.0.0" + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" } }, "object-keys": { @@ -22885,9 +23113,9 @@ }, "dependencies": { "es-abstract": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", - "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.15.0.tgz", + "integrity": "sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ==", "dev": true, "requires": { "es-to-primitive": "^1.2.0", @@ -22898,8 +23126,8 @@ "is-regex": "^1.0.4", "object-inspect": "^1.6.0", "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.0.0", - "string.prototype.trimright": "^2.0.0" + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" } }, "object-keys": { @@ -22921,9 +23149,9 @@ } }, "property-information": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.2.2.tgz", - "integrity": "sha512-N2moasZmjn2mjVGIWpaqz5qnz6QyeQSGgGvMtl81gA9cPTWa6wpesRSe/quNnOjUHpvSH1oZx0pdz0EEckLFnA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.3.0.tgz", + "integrity": "sha512-IslotQn1hBCZDY7SaJ3zmCjVea219VTwmOk6Pu3z9haU9m4+T8GwaDubur+6NMHEU+Fjs/6/p66z6QULPkcL1w==", "dev": true, "requires": { "xtend": "^4.0.1" @@ -23099,15 +23327,6 @@ "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", "dev": true }, - "raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dev": true, - "requires": { - "performance-now": "^2.1.0" - } - }, "ramda": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", @@ -23218,7 +23437,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } @@ -23258,9 +23477,9 @@ } }, "react-dev-utils": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.0.4.tgz", - "integrity": "sha512-VwR+mBUXPLdYk/rOz6s6qpasIFGd7GW0KXd/3bih+/qGcMQvPG19XxtjDMtiAg0zWiFwp1ugCzAjLThbzFjVqw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.1.0.tgz", + "integrity": "sha512-X2KYF/lIGyGwP/F/oXgGDF24nxDA2KC4b7AFto+eqzc/t838gpSGiaU8trTqHXOohuLxxc5qi1eDzsl9ucPDpg==", "dev": true, "requires": { "@babel/code-frame": "7.5.5", @@ -23282,7 +23501,7 @@ "loader-utils": "1.2.3", "open": "^6.3.0", "pkg-up": "2.0.0", - "react-error-overlay": "^6.0.2", + "react-error-overlay": "^6.0.3", "recursive-readdir": "2.2.2", "shell-quote": "1.7.2", "sockjs-client": "1.4.0", @@ -23380,9 +23599,9 @@ } }, "electron-to-chromium": { - "version": "1.3.272", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.272.tgz", - "integrity": "sha512-TjsDKYOZGgaD8tUJtRiiBNlIrv2Ol6SxNMy4yeTX0goRmoBhV941m4EN8QjA3vfshs16F5KLDyUv2m7GdTqIgg==", + "version": "1.3.282", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.282.tgz", + "integrity": "sha512-irSaDeCGgfMu1OA30bhqIBr+dx+pDJjRbwCpob7YWqVZbzXblybNzPGklVnWqv4EXxbkEAzQYqiNCqNTgu00lQ==", "dev": true }, "external-editor": { @@ -23500,12 +23719,12 @@ "dev": true }, "node-releases": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.33.tgz", - "integrity": "sha512-I0V30bWQEoHb+10W8oedVoUrdjW5wIkYm0w7vvcrPO95pZY738m1k77GF5sO0vKg5eXYg9oGtrMAETbgZGm11A==", + "version": "1.1.35", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.35.tgz", + "integrity": "sha512-JGcM/wndCN/2elJlU0IGdVEJQQnJwsLbgPCFd2pY7V0mxf17bZ0Gb/lgOtL29ZQhvEX5shnVhxQyZz3ex94N8w==", "dev": true, "requires": { - "semver": "^5.3.0" + "semver": "^6.3.0" } }, "rxjs": { @@ -23517,6 +23736,12 @@ "tslib": "^1.9.0" } }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -23588,9 +23813,9 @@ "dev": true }, "commander": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", - "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "doctrine": { @@ -23640,9 +23865,9 @@ } }, "react-draggable": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-3.3.2.tgz", - "integrity": "sha512-oaz8a6enjbPtx5qb0oDWxtDNuybOylvto1QLydsXgKmwT7e3GXC2eMVDwEMIUYJIFqVG72XpOv673UuuAq6LhA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.0.3.tgz", + "integrity": "sha512-4vD6zms+9QGeZ2RQXzlUBw8PBYUXy+dzYX5r22idjp9YwQKIIvD/EojL0rbjS1GK4C3P0rAJnmKa8gDQYWUDyA==", "dev": true, "requires": { "classnames": "^2.2.5", @@ -23650,9 +23875,9 @@ } }, "react-error-overlay": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.2.tgz", - "integrity": "sha512-DHRuRk3K4Lg9obI6J4Y+nKvtwjasYRU9CFL3ud42x9YJG1HbQjSNublapC/WBJOA726gNUbqbj0U2df9+uzspQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.3.tgz", + "integrity": "sha512-bOUvMWFQVk5oz8Ded9Xb7WVdEi3QGLC8tH7HmYP0Fdp4Bn3qw0tRFmr5TW6mvahzvmrK4a6bqWGfCevBflP+Xw==", "dev": true }, "react-fast-compare": { @@ -23773,19 +23998,19 @@ } }, "react-popper-tooltip": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-2.8.3.tgz", - "integrity": "sha512-g5tfxmuj8ClNVwH4zswYJcD3GKoc5RMeRawd/WZnbyZGEDecsRKaVL+Kj7L3BG7w5qb6/MHcLTG8yE4CidwezQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-2.9.1.tgz", + "integrity": "sha512-LSbvXLEQlNKWig2GMKQW/1bBwCkWIr9cpJ+WJpSGGGhX45CthRtwyilPPLJQkc3qI6UMTAXPp0Fe/pj9E77trg==", "dev": true, "requires": { - "@babel/runtime": "^7.4.5", - "react-popper": "^1.3.3" + "@babel/runtime": "^7.6.3", + "react-popper": "^1.3.4" }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -23800,27 +24025,25 @@ } }, "react-select": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-3.0.7.tgz", - "integrity": "sha512-m4DKFUGvjjghxovuo4NyGltq/qPwFV5LV1Bo8wl1tUt1UQZO0Lvru1yC62wkTsittf5A+k4gyM4c+MhfEiERSQ==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-3.0.8.tgz", + "integrity": "sha512-v9LpOhckLlRmXN5A6/mGGEft4FMrfaBFTGAnuPHcUgVId7Je42kTq9y0Z+Ye5z8/j0XDT3zUqza8gaRaI1PZIg==", "dev": true, "requires": { "@babel/runtime": "^7.4.4", "@emotion/cache": "^10.0.9", "@emotion/core": "^10.0.9", "@emotion/css": "^10.0.9", - "classnames": "^2.2.5", "memoize-one": "^5.0.0", "prop-types": "^15.6.0", - "raf": "^3.4.0", "react-input-autosize": "^2.2.2", "react-transition-group": "^2.2.1" }, "dependencies": { "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -23835,9 +24058,9 @@ } }, "react-sizeme": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-2.6.7.tgz", - "integrity": "sha512-xCjPoBP5jmeW58TxIkcviMZqabZis7tTvDFWf0/Wa5XCgVWQTIe74NQBes2N1Kmp64GRLkpm60BaP0kk+v8aCQ==", + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-2.6.8.tgz", + "integrity": "sha512-eJKHV226d/S3st2He7bLIlY7FAmi2ItvZmUCmLLNjIvYjtiv58BksuFhTBQmvAxWaXZGb3Ao/44wfAS1voRdjA==", "dev": true, "requires": { "element-resize-detector": "^1.1.15", @@ -23909,7 +24132,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -23943,7 +24166,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -24006,7 +24229,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -24191,7 +24414,7 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "dev": true }, @@ -24396,7 +24619,7 @@ }, "requestretry": { "version": "1.5.0", - "resolved": "http://registry.npmjs.org/requestretry/-/requestretry-1.5.0.tgz", + "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.5.0.tgz", "integrity": "sha1-7RV7ulNSbt6z7DKo5wSkmYvs5ic=", "dev": true, "requires": { @@ -24534,7 +24757,7 @@ }, "rimraf": { "version": "2.4.5", - "resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", "requires": { "glob": "^6.0.1" @@ -24629,7 +24852,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -24660,7 +24883,7 @@ }, "sax": { "version": "1.2.1", - "resolved": "http://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, "scandirectory": { @@ -24693,7 +24916,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" } } @@ -24778,7 +25001,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -24975,7 +25198,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", @@ -25151,9 +25374,9 @@ }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", + "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==", "dev": true } } @@ -25654,7 +25877,7 @@ }, "stream-browserify": { "version": "2.0.1", - "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", "requires": { "inherits": "~2.0.1", @@ -25686,7 +25909,7 @@ }, "stream-http": { "version": "2.8.1", - "resolved": "http://registry.npmjs.org/stream-http/-/stream-http-2.8.1.tgz", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.1.tgz", "integrity": "sha512-cQ0jo17BLca2r0GfRdZKYAGLU6JRoIWxqSOakUMuKOT6MOK7AAlE856L33QuDmAy/eeOrhLee3dZKX0Uadu93A==", "requires": { "builtin-status-codes": "^3.0.0", @@ -25742,16 +25965,42 @@ } }, "string.prototype.matchall": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-3.0.1.tgz", - "integrity": "sha512-NSiU0ILQr9PQ1SZmM1X327U5LsM+KfDTassJfqN1al1+0iNpKzmQ4BfXOJwRnTEqv8nKJ67mFpqRoPaGWwvy5A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-3.0.2.tgz", + "integrity": "sha512-hsRe42jQ8+OJej2GVjhnSVodQ3NQgHV0FDD6dW7ZTM22J4uIbuYiAADCCc1tfyN7ocEl/KUUbudM36E2tZcF8w==", "dev": true, "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", + "es-abstract": "^1.14.2", "function-bind": "^1.1.1", "has-symbols": "^1.0.0", "regexp.prototype.flags": "^1.2.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.15.0.tgz", + "integrity": "sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "string.prototype.padend": { @@ -25834,7 +26083,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -25857,7 +26106,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-indent": { @@ -26515,18 +26764,33 @@ } }, "telejson": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/telejson/-/telejson-2.2.2.tgz", - "integrity": "sha512-YyNwnKY0ilabOwYgC/J754En1xOe5PBIUIw+C9e0+5HjVVcnQE5/gdu2yET2pmSbp5bxIDqYNjvndj2PUkIiYA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-3.0.3.tgz", + "integrity": "sha512-gUOh6wox1zJjbGMg+e26NquZcp/F18EbIaqVvjiGqikRqVB4fYEAM8Nyin8smgwX30XhaRBOg+kCj4vInmvwAg==", "dev": true, "requires": { - "global": "^4.3.2", + "@types/is-function": "^1.0.0", + "global": "^4.4.0", "is-function": "^1.0.1", "is-regex": "^1.0.4", "is-symbol": "^1.0.2", - "isobject": "^3.0.1", - "lodash": "^4.17.11", + "isobject": "^4.0.0", + "lodash": "^4.17.15", "memoizerific": "^1.11.3" + }, + "dependencies": { + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "term-size": { @@ -26660,7 +26924,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -26884,7 +27148,7 @@ "dependencies": { "progress": { "version": "1.1.8", - "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=" } } @@ -27449,14 +27713,14 @@ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" }, "url-loader": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.1.0.tgz", - "integrity": "sha512-kVrp/8VfEm5fUt+fl2E0FQyrpmOYgMEkBsv8+UDP1wFhszECq5JyGF33I7cajlVY90zRZ6MyfgKXngLvHYZX8A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.2.0.tgz", + "integrity": "sha512-G8nk3np8ZAnwhHXas1JxJEwJyQdqFXAKJehfgZ/XrC48volFBRtO+FIKtF2u0Ma3bw+4vnDVjHPAQYlF9p2vsw==", "dev": true, "requires": { "loader-utils": "^1.2.3", "mime": "^2.4.4", - "schema-utils": "^2.0.0" + "schema-utils": "^2.4.1" }, "dependencies": { "ajv": { @@ -27516,9 +27780,9 @@ "dev": true }, "schema-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.4.1.tgz", - "integrity": "sha512-RqYLpkPZX5Oc3fw/kHHHyP56fg5Y+XBpIpV8nCg0znIALfq3OH+Ea9Hfeac9BAMwG5IICltiZ0vxFvJQONfA5w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -27580,14 +27844,14 @@ "dependencies": { "semver": { "version": "5.3.0", - "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" } } }, "util": { "version": "0.10.3", - "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "requires": { "inherits": "2.0.1" @@ -27642,7 +27906,7 @@ }, "valid-data-url": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/valid-data-url/-/valid-data-url-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-0.1.6.tgz", "integrity": "sha512-FXg2qXMzfAhZc0y2HzELNfUeiOjPr+52hU1DNBWiJJ2luXD+dD1R9NA48Ug5aj0ibbxroeGDc/RJv6ThiGgkDw==" }, "validate-npm-package-license": { @@ -28215,7 +28479,7 @@ }, "whatwg-fetch": { "version": "2.0.4", - "resolved": "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" }, "whatwg-mimetype": { @@ -28362,7 +28626,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", @@ -28449,7 +28713,7 @@ "dependencies": { "xmlbuilder": { "version": "9.0.7", - "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" } } @@ -28466,7 +28730,7 @@ }, "xolvio-ddp": { "version": "0.12.3", - "resolved": "http://registry.npmjs.org/xolvio-ddp/-/xolvio-ddp-0.12.3.tgz", + "resolved": "https://registry.npmjs.org/xolvio-ddp/-/xolvio-ddp-0.12.3.tgz", "integrity": "sha1-NqarlhKyQLWg0cCoNJCK8XwLjwI=", "dev": true, "requires": { @@ -28491,7 +28755,7 @@ }, "async": { "version": "0.9.2", - "resolved": "http://registry.npmjs.org/async/-/async-0.9.2.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", "dev": true }, @@ -28503,7 +28767,7 @@ }, "bl": { "version": "0.9.5", - "resolved": "http://registry.npmjs.org/bl/-/bl-0.9.5.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz", "integrity": "sha1-wGt5evCF6gC8Unr8jvzxHeIjIFQ=", "dev": true, "requires": { @@ -28512,7 +28776,7 @@ }, "bluebird": { "version": "2.11.0", - "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", "dev": true }, @@ -28524,7 +28788,7 @@ }, "combined-stream": { "version": "0.0.7", - "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", "dev": true, "requires": { @@ -28545,7 +28809,7 @@ }, "form-data": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz", "integrity": "sha1-Jvi8JtpkQOKZy9z7aQNcT3em5GY=", "dev": true, "requires": { @@ -28585,13 +28849,13 @@ }, "mime-db": { "version": "1.12.0", - "resolved": "http://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz", "integrity": "sha1-PQxjGA9FjrENMlqqN9fFiuMS6dc=", "dev": true }, "mime-types": { "version": "2.0.14", - "resolved": "http://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", "integrity": "sha1-MQ4VnbI+B3+Lsit0jav6SVcUCqY=", "dev": true, "requires": { @@ -28618,7 +28882,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -28630,7 +28894,7 @@ }, "request": { "version": "2.53.0", - "resolved": "http://registry.npmjs.org/request/-/request-2.53.0.tgz", + "resolved": "https://registry.npmjs.org/request/-/request-2.53.0.tgz", "integrity": "sha1-GAo66St7Y5gC5PlUXdj83rcddgw=", "dev": true, "requires": { @@ -28669,7 +28933,7 @@ }, "xolvio-fiber-utils": { "version": "2.0.3", - "resolved": "http://registry.npmjs.org/xolvio-fiber-utils/-/xolvio-fiber-utils-2.0.3.tgz", + "resolved": "https://registry.npmjs.org/xolvio-fiber-utils/-/xolvio-fiber-utils-2.0.3.tgz", "integrity": "sha1-vsjXDHQGGjFjFbun0w0lyz6C3FA=", "dev": true, "requires": { @@ -28687,7 +28951,7 @@ }, "xolvio-jasmine-expect": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/xolvio-jasmine-expect/-/xolvio-jasmine-expect-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/xolvio-jasmine-expect/-/xolvio-jasmine-expect-1.1.0.tgz", "integrity": "sha1-vCud1ghCMR8EV59agtzqaisxnH0=", "dev": true, "requires": { @@ -28737,6 +29001,15 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "^0.2.2" + } + }, "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", @@ -28754,7 +29027,7 @@ }, "yargs": { "version": "3.32.0", - "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", "requires": { "camelcase": "^2.0.1", diff --git a/package.json b/package.json index b89d9c8a938e48ce31333b20b84d9283f9b6f807..4ad88fa8a9981317647c2136690ab872d9e634f6 100644 --- a/package.json +++ b/package.json @@ -99,10 +99,13 @@ "@octokit/rest": "^16.1.0", "@rocket.chat/eslint-config": "^0.3.0", "@rocket.chat/livechat": "^1.2.5", - "@storybook/addon-actions": "^5.2.1", - "@storybook/addon-links": "^5.2.1", - "@storybook/addons": "^5.2.1", - "@storybook/react": "^5.2.1", + "@settlin/spacebars-loader": "^1.0.7", + "@storybook/addon-actions": "^5.2.4", + "@storybook/addon-knobs": "^5.2.4", + "@storybook/addon-links": "^5.2.4", + "@storybook/addon-viewport": "^5.2.4", + "@storybook/addons": "^5.2.4", + "@storybook/react": "^5.2.4", "acorn": "^6.0.7", "autoprefixer": "^9.6.1", "babel-eslint": "^10.0.1", @@ -131,6 +134,7 @@ "postcss-media-minmax": "^4.0.0", "postcss-nested": "^4.1.0", "postcss-selector-not": "^4.0.0", + "postcss-url": "^8.0.0", "progress": "^2.0.2", "proxyquire": "^2.1.0", "simple-git": "^1.107.0", @@ -147,8 +151,9 @@ "@google-cloud/storage": "^2.3.1", "@google-cloud/vision": "^0.23.0", "@rocket.chat/apps-engine": "^1.7.0", - "@rocket.chat/fuselage": "^0.2.0-alpha.4", - "@rocket.chat/icons": "^0.2.0-alpha.0", + "@rocket.chat/fuselage": "^0.2.0-dev.53", + "@rocket.chat/fuselage-hooks": "^0.2.0-dev.50", + "@rocket.chat/icons": "^0.2.0-dev.49", "@slack/client": "^4.8.0", "adm-zip": "^0.4.13", "archiver": "^3.0.0", diff --git a/public/fonts/RocketChat.eot b/public/fonts/RocketChat.eot deleted file mode 120000 index 25d326d7e00f764a00fd5bc312968713c2565da0..0000000000000000000000000000000000000000 --- a/public/fonts/RocketChat.eot +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/@rocket.chat/icons/dist/font/RocketChat.eot \ No newline at end of file diff --git a/public/fonts/RocketChat.svg b/public/fonts/RocketChat.svg deleted file mode 120000 index 6360397c7a6665cf23355edf1606af0ea2e1909b..0000000000000000000000000000000000000000 --- a/public/fonts/RocketChat.svg +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/@rocket.chat/icons/dist/font/RocketChat.svg \ No newline at end of file diff --git a/public/fonts/RocketChat.ttf b/public/fonts/RocketChat.ttf deleted file mode 120000 index 4a2797b73b608d185924ab41f9aa5122ecdb58f6..0000000000000000000000000000000000000000 --- a/public/fonts/RocketChat.ttf +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/@rocket.chat/icons/dist/font/RocketChat.ttf \ No newline at end of file diff --git a/public/fonts/RocketChat.woff b/public/fonts/RocketChat.woff deleted file mode 120000 index 5530527154cae2944c2079e2d23b81964bc16cfb..0000000000000000000000000000000000000000 --- a/public/fonts/RocketChat.woff +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/@rocket.chat/icons/dist/font/RocketChat.woff \ No newline at end of file diff --git a/public/fonts/RocketChat.woff2 b/public/fonts/RocketChat.woff2 deleted file mode 120000 index 85ba5007685169b8d2aaac7ddb37a7415f5b1e0f..0000000000000000000000000000000000000000 --- a/public/fonts/RocketChat.woff2 +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/@rocket.chat/icons/dist/font/RocketChat.woff2 \ No newline at end of file diff --git a/public/fonts/rocketchat.eot b/public/fonts/rocketchat.eot new file mode 120000 index 0000000000000000000000000000000000000000..7a5f9168dbbadf308bb201bcd233a964a3e0a551 --- /dev/null +++ b/public/fonts/rocketchat.eot @@ -0,0 +1 @@ +../../node_modules/@rocket.chat/icons/dist/font/rocketchat.eot \ No newline at end of file diff --git a/public/fonts/rocketchat.svg b/public/fonts/rocketchat.svg new file mode 120000 index 0000000000000000000000000000000000000000..593ff6fd9f450bc4dac07e212b72226cea58fe8d --- /dev/null +++ b/public/fonts/rocketchat.svg @@ -0,0 +1 @@ +../../node_modules/@rocket.chat/icons/dist/font/rocketchat.svg \ No newline at end of file diff --git a/public/fonts/rocketchat.ttf b/public/fonts/rocketchat.ttf new file mode 120000 index 0000000000000000000000000000000000000000..9597549fd452f859da20e00b6effc3701c587cd7 --- /dev/null +++ b/public/fonts/rocketchat.ttf @@ -0,0 +1 @@ +../../node_modules/@rocket.chat/icons/dist/font/rocketchat.ttf \ No newline at end of file diff --git a/public/fonts/rocketchat.woff b/public/fonts/rocketchat.woff new file mode 120000 index 0000000000000000000000000000000000000000..911157e471894e8fc642e16c9493004da2a01b40 --- /dev/null +++ b/public/fonts/rocketchat.woff @@ -0,0 +1 @@ +../../node_modules/@rocket.chat/icons/dist/font/rocketchat.woff \ No newline at end of file diff --git a/public/fonts/rocketchat.woff2 b/public/fonts/rocketchat.woff2 new file mode 120000 index 0000000000000000000000000000000000000000..1ef2c05eba19c911854e087577f4e32d52bcf4b5 --- /dev/null +++ b/public/fonts/rocketchat.woff2 @@ -0,0 +1 @@ +../../node_modules/@rocket.chat/icons/dist/font/rocketchat.woff2 \ No newline at end of file diff --git a/tests/end-to-end/ui/11-admin.js b/tests/end-to-end/ui/11-admin.js index 1e9e588173ef06ac8e288ddaee53532750294b2b..15dc2e4b5691ee939c1a71bd5e5a142d07676a6c 100644 --- a/tests/end-to-end/ui/11-admin.js +++ b/tests/end-to-end/ui/11-admin.js @@ -481,13 +481,14 @@ describe('[Administration]', () => { admin.generalLanguageReset.click(); }); - it('it should show invalid self signed certs checkboxes', () => { - admin.generalSelfSignedCertsFalse.isVisible().should.be.true; - admin.generalSelfSignedCertsTrue.isVisible().should.be.true; + it('it should show invalid self signed certs toggle', () => { + admin.generalSelfSignedCerts.$('..').isVisible().should.be.true; }); - it('it should change the invalid self signed certs checkboxes', () => { - admin.generalSelfSignedCertsTrue.click(); + it('it should change the invalid self signed certs toggle', () => { + if (!admin.generalSelfSignedCerts.isSelected()) { + admin.generalSelfSignedCerts.$('..').click(); + } }); it('it should show the reset button', () => { @@ -500,12 +501,13 @@ describe('[Administration]', () => { }); it('it should show favorite rooms checkboxes', () => { - admin.generalFavoriteRoomFalse.isVisible().should.be.true; - admin.generalFavoriteRoomTrue.isVisible().should.be.true; + admin.generalFavoriteRoom.$('..').isVisible().should.be.true; }); - it('it should change the favorite rooms checkboxes', () => { - admin.generalFavoriteRoomFalse.click(); + it('it should change the favorite rooms toggle', () => { + if (admin.generalFavoriteRoom.isSelected()) { + admin.generalFavoriteRoom.$('..').click(); + } }); it('it should show the reset button', () => { @@ -552,13 +554,14 @@ describe('[Administration]', () => { admin.generalCdnPrefixReset.click(); }); - it('it should show the force SSL checkboxes', () => { - admin.generalForceSSLTrue.isVisible().should.be.true; - admin.generalForceSSLFalse.isVisible().should.be.true; + it('it should show the force SSL toggle', () => { + admin.generalForceSSL.$('..').isVisible().should.be.true; }); - it('it should change the force ssl checkboxes', () => { - admin.generalForceSSLTrue.click(); + it('it should change the force ssl toggle', () => { + if (!admin.generalForceSSL.isSelected()) { + admin.generalForceSSL.$('..').click(); + } }); it('it should show the reset button', () => { @@ -607,24 +610,21 @@ describe('[Administration]', () => { describe('iframe:', () => { before(() => { - admin.generalButtonExpandIframe.waitForVisible(5000); - admin.generalButtonExpandIframe.click(); - admin.generalIframeSendTrue.waitForVisible(5000); - admin.generalIframeSendTrue.scroll(); + admin.generalSectionIframeIntegration.waitForVisible(5000); + admin.generalSectionIframeIntegration.$('[aria-expanded="false"]').click(); + admin.generalIframeSend.$('..').scroll(); }); - it('it should show iframe send checkboxes', () => { - admin.generalIframeSendTrue.isVisible().should.be.true; - admin.generalIframeSendFalse.isVisible().should.be.true; + it('it should show iframe send toggle', () => { + admin.generalIframeSend.$('..').isVisible().should.be.true; }); it('it should show send origin field', () => { admin.generalIframeSendTargetOrigin.isVisible().should.be.true; }); - it('it should show iframe send checkboxes', () => { - admin.generalIframeRecieveFalse.isVisible().should.be.true; - admin.generalIframeRecieveTrue.isVisible().should.be.true; + it('it should show iframe send toggle', () => { + admin.generalIframeRecieve.$('..').isVisible().should.be.true; }); it('it should show send origin field', () => { @@ -634,9 +634,8 @@ describe('[Administration]', () => { describe('notifications:', () => { before(() => { - admin.generalButtonExpandNotifications.waitForVisible(5000); - admin.generalButtonExpandNotifications.click(); - admin.generalNotificationsMaxRoomMembers.waitForVisible(5000); + admin.generalSectionNotifications.waitForVisible(5000); + admin.generalSectionNotifications.$('[aria-expanded="false"]').click(); admin.generalNotificationsMaxRoomMembers.scroll(); }); @@ -647,8 +646,8 @@ describe('[Administration]', () => { describe('rest api:', () => { before(() => { - admin.generalButtonExpandRest.waitForVisible(5000); - admin.generalButtonExpandRest.click(); + admin.generalSectionRestApi.waitForVisible(5000); + admin.generalSectionRestApi.$('[aria-expanded="false"]').click(); admin.generalRestApiUserLimit.waitForVisible(5000); admin.generalRestApiUserLimit.scroll(); }); @@ -660,22 +659,20 @@ describe('[Administration]', () => { describe('reporting:', () => { before(() => { - admin.generalButtonExpandReporting.waitForVisible(5000); - admin.generalButtonExpandReporting.click(); - admin.generalReportingTrue.waitForVisible(5000); - admin.generalReportingTrue.scroll(); + admin.generalSectionReporting.waitForVisible(5000); + admin.generalSectionReporting.$('[aria-expanded="false"]').click(); + admin.generalReporting.$('..').scroll(); }); - it('it should show the report to rocket.chat checkboxes', () => { - admin.generalReportingTrue.isVisible().should.be.true; - admin.generalReportingFalse.isVisible().should.be.true; + it('it should show the report to rocket.chat toggle', () => { + admin.generalReporting.$('..').isVisible().should.be.true; }); }); describe('stream cast:', () => { before(() => { - admin.generalButtonExpandStreamCast.waitForVisible(5000); - admin.generalButtonExpandStreamCast.click(); + admin.generalSectionStreamCast.waitForVisible(5000); + admin.generalSectionStreamCast.$('[aria-expanded="false"]').click(); admin.generalStreamCastAdress.waitForVisible(5000); admin.generalStreamCastAdress.scroll(); }); @@ -685,10 +682,10 @@ describe('[Administration]', () => { }); }); - describe('stream cast:', () => { + describe('utf8:', () => { before(() => { - admin.generalButtonExpandUTF8.waitForVisible(5000); - admin.generalButtonExpandUTF8.click(); + admin.generalSectionUTF8.waitForVisible(5000); + admin.generalSectionUTF8.$('[aria-expanded="false"]').click(); admin.generalUTF8Regex.waitForVisible(5000); admin.generalUTF8Regex.scroll(); }); @@ -698,8 +695,7 @@ describe('[Administration]', () => { }); it('it should show the utf8 names slug checkboxes', () => { - admin.generalUTF8NamesSlugTrue.isVisible().should.be.true; - admin.generalUTF8NamesSlugFalse.isVisible().should.be.true; + admin.generalUTF8NamesSlug.$('..').isVisible().should.be.true; }); }); }); @@ -714,22 +710,20 @@ describe('[Administration]', () => { describe('default user preferences', () => { before(() => { - if (admin.accountsButtonCollapseDefaultUserPreferences.isVisible()) { - admin.accountsButtonCollapseDefaultUserPreferences.click(); + if (admin.accountsSectionDefaultUserPreferences.$('[aria-expanded="true"]').isVisible()) { + admin.accountsSectionDefaultUserPreferences.$('[aria-expanded="true"]').click(); } - admin.accountsButtonExpandDefaultUserPreferences.waitForVisible(5000); - admin.accountsButtonExpandDefaultUserPreferences.click(); + admin.accountsSectionDefaultUserPreferences.$('[aria-expanded="false"]').waitForVisible(5000); + admin.accountsSectionDefaultUserPreferences.$('[aria-expanded="false"]').click(); admin.accountsNotificationDuration.waitForVisible(5000); }); it('it should show the enable auto away field', () => { - admin.accountsEnableAutoAwayTrue.scroll(); - admin.accountsEnableAutoAwayTrue.isVisible().should.be.true; - admin.accountsEnableAutoAwayFalse.isVisible().should.be.true; + admin.accountsEnableAutoAway.$('..').scroll(); + admin.accountsEnableAutoAway.$('..').isVisible().should.be.true; }); it('the enable auto away field value should be true', () => { - admin.accountsEnableAutoAwayTrue.isSelected().should.be.true; - admin.accountsEnableAutoAwayFalse.isSelected().should.be.false; + admin.accountsEnableAutoAway.isSelected().should.be.true; }); it('it should show the idle timeout limit field', () => { @@ -773,103 +767,83 @@ describe('[Administration]', () => { }); it('it should show the unread tray icon alert field', () => { - admin.accountsUnreadAlertTrue.scroll(); - admin.accountsUnreadAlertTrue.isVisible().should.be.true; - admin.accountsUnreadAlertFalse.isVisible().should.be.true; + admin.accountsUnreadAlert.$('..').scroll(); + admin.accountsUnreadAlert.$('..').isVisible().should.be.true; }); it('the unread tray icon alert field value should be true', () => { - admin.accountsUnreadAlertTrue.isSelected().should.be.true; - admin.accountsUnreadAlertFalse.isSelected().should.be.false; + admin.accountsUnreadAlert.isSelected().should.be.true; }); it('it should show the use emojis field', () => { - admin.accountsUseEmojisTrue.scroll(); - admin.accountsUseEmojisTrue.isVisible().should.be.true; - admin.accountsUseEmojisFalse.isVisible().should.be.true; + admin.accountsUseEmojis.$('..').scroll(); + admin.accountsUseEmojis.$('..').isVisible().should.be.true; }); it('the use emojis field value should be true', () => { - admin.accountsUseEmojisTrue.isSelected().should.be.true; - admin.accountsUseEmojisFalse.isSelected().should.be.false; + admin.accountsUseEmojis.isSelected().should.be.true; }); it('it should show the convert ascii to emoji field', () => { - admin.accountsConvertAsciiEmojiTrue.scroll(); - admin.accountsConvertAsciiEmojiTrue.isVisible().should.be.true; - admin.accountsConvertAsciiEmojiFalse.isVisible().should.be.true; + admin.accountsConvertAsciiEmoji.$('..').scroll(); + admin.accountsConvertAsciiEmoji.$('..').isVisible().should.be.true; }); it('the convert ascii to emoji field value should be true', () => { - admin.accountsConvertAsciiEmojiTrue.isSelected().should.be.true; - admin.accountsConvertAsciiEmojiFalse.isSelected().should.be.false; + admin.accountsConvertAsciiEmoji.isSelected().should.be.true; }); it('it should show the auto load images field', () => { - admin.accountsAutoImageLoadTrue.scroll(); - admin.accountsAutoImageLoadTrue.isVisible().should.be.true; - admin.accountsAutoImageLoadFalse.isVisible().should.be.true; + admin.accountsAutoImageLoad.$('..').scroll(); + admin.accountsAutoImageLoad.$('..').isVisible().should.be.true; }); it('the auto load images field value should be true', () => { - admin.accountsAutoImageLoadTrue.isSelected().should.be.true; - admin.accountsAutoImageLoadFalse.isSelected().should.be.false; + admin.accountsAutoImageLoad.isSelected().should.be.true; }); it('it should show the save mobile bandwidth field', () => { - admin.accountsSaveMobileBandwidthTrue.scroll(); - admin.accountsSaveMobileBandwidthTrue.isVisible().should.be.true; - admin.accountsSaveMobileBandwidthFalse.isVisible().should.be.true; + admin.accountsSaveMobileBandwidth.$('..').scroll(); + admin.accountsSaveMobileBandwidth.$('..').isVisible().should.be.true; }); it('the save mobile bandwidth field value should be true', () => { - admin.accountsSaveMobileBandwidthTrue.isSelected().should.be.true; - admin.accountsSaveMobileBandwidthFalse.isSelected().should.be.false; + admin.accountsSaveMobileBandwidth.isSelected().should.be.true; }); it('it should show the collapse embedded media by default field', () => { - admin.accountsCollapseMediaByDefaultTrue.scroll(); - admin.accountsCollapseMediaByDefaultTrue.isVisible().should.be.true; - admin.accountsCollapseMediaByDefaultFalse.isVisible().should.be.true; + admin.accountsCollapseMediaByDefault.$('..').scroll(); + admin.accountsCollapseMediaByDefault.$('..').isVisible().should.be.true; }); it('the collapse embedded media by default field value should be false', () => { - admin.accountsCollapseMediaByDefaultTrue.isSelected().should.be.false; - admin.accountsCollapseMediaByDefaultFalse.isSelected().should.be.true; + admin.accountsCollapseMediaByDefault.isSelected().should.be.false; }); it('it should show the hide usernames field', () => { - admin.accountsHideUsernamesTrue.scroll(); - admin.accountsHideUsernamesTrue.isVisible().should.be.true; - admin.accountsHideUsernamesFalse.isVisible().should.be.true; + admin.accountsHideUsernames.$('..').scroll(); + admin.accountsHideUsernames.$('..').isVisible().should.be.true; }); it('the hide usernames field value should be false', () => { - admin.accountsHideUsernamesTrue.isSelected().should.be.false; - admin.accountsHideUsernamesFalse.isSelected().should.be.true; + admin.accountsHideUsernames.isSelected().should.be.false; }); it('it should show the hide roles field', () => { - admin.accountsHideRolesTrue.scroll(); - admin.accountsHideRolesTrue.isVisible().should.be.true; - admin.accountsHideRolesFalse.isVisible().should.be.true; + admin.accountsHideRoles.$('..').scroll(); + admin.accountsHideRoles.$('..').isVisible().should.be.true; }); it('the hide roles field value should be false', () => { - admin.accountsHideRolesTrue.isSelected().should.be.false; - admin.accountsHideRolesFalse.isSelected().should.be.true; + admin.accountsHideRoles.isSelected().should.be.false; }); it('it should show the hide right sidebar with click field', () => { - admin.accountsHideFlexTabTrue.scroll(); - admin.accountsHideFlexTabTrue.isVisible().should.be.true; - admin.accountsHideFlexTabFalse.isVisible().should.be.true; + admin.accountsHideFlexTab.$('..').scroll(); + admin.accountsHideFlexTab.$('..').isVisible().should.be.true; }); it('the hide right sidebar with click field value should be false', () => { - admin.accountsHideFlexTabTrue.isSelected().should.be.false; - admin.accountsHideFlexTabFalse.isSelected().should.be.true; + admin.accountsHideFlexTab.isSelected().should.be.false; }); it('it should show the hide avatars field', () => { - admin.accountsHideAvatarsTrue.scroll(); - admin.accountsHideAvatarsTrue.isVisible().should.be.true; - admin.accountsHideAvatarsFalse.isVisible().should.be.true; + admin.accountsHideAvatars.$('..').scroll(); + admin.accountsHideAvatars.$('..').isVisible().should.be.true; }); it('the hide avatars field value should be false', () => { - admin.accountsHideAvatarsTrue.isSelected().should.be.false; - admin.accountsHideAvatarsFalse.isSelected().should.be.true; + admin.accountsHideAvatars.isSelected().should.be.false; }); it('it should show the enter key behavior field', () => { @@ -899,13 +873,11 @@ describe('[Administration]', () => { }); it('it should show the room counter sidebar field', () => { - admin.accountsRoomCounterSidebarTrue.scroll(); - admin.accountsRoomCounterSidebarTrue.isVisible().should.be.true; - admin.accountsRoomCounterSidebarFalse.isVisible().should.be.true; + admin.accountsRoomCounterSidebar.$('..').scroll(); + admin.accountsRoomCounterSidebar.$('..').isVisible().should.be.true; }); it('the room counter sidebar field value should be false', () => { - admin.accountsRoomCounterSidebarTrue.isSelected().should.be.false; - admin.accountsRoomCounterSidebarFalse.isSelected().should.be.true; + admin.accountsRoomCounterSidebar.isSelected().should.be.false; }); it('it should show the new room notification field', () => { diff --git a/tests/pageobjects/administration.page.js b/tests/pageobjects/administration.page.js index a2b9461a5ecb762ffcb6fd6997b07f984829f930..45f5700cf5abd6f035f874febebdf414d31425aa 100644 --- a/tests/pageobjects/administration.page.js +++ b/tests/pageobjects/administration.page.js @@ -126,262 +126,208 @@ class Administration extends Page { // settings get buttonSave() { return browser.element('button.save'); } - get generalButtonExpandIframe() { return browser.element('.section:nth-of-type(3) .expand'); } + get generalSectionIframeIntegration() { return browser.element('[data-qa-section="Iframe_Integration"]'); } - get generalButtonExpandNotifications() { return browser.element('.section:nth-of-type(4) .expand'); } + get generalSectionNotifications() { return browser.element('[data-qa-section="Notifications"]'); } - get generalButtonExpandRest() { return browser.element('.section:nth-of-type(5) .expand'); } + get generalSectionRestApi() { return browser.element('[data-qa-section="REST API"]'); } - get generalButtonExpandReporting() { return browser.element('.section:nth-of-type(6) .expand'); } + get generalSectionReporting() { return browser.element('[data-qa-section="Reporting"]'); } - get generalButtonExpandStreamCast() { return browser.element('.section:nth-of-type(7) .expand'); } + get generalSectionStreamCast() { return browser.element('[data-qa-section="Stream_Cast"]'); } - get generalButtonExpandTranslations() { return browser.element('.section:nth-of-type(8) .expand'); } + get generalSectionUTF8() { return browser.element('[data-qa-section="UTF8"]'); } - get generalButtonExpandUTF8() { return browser.element('.section:nth-of-type(9) .expand'); } + get generalSiteUrl() { return browser.element('[data-qa-setting-id="Site_Url"]'); } - get generalSiteUrl() { return browser.element('[name="Site_Url"]'); } + get generalSiteUrlReset() { return browser.element('[data-qa-reset-setting-id="Site_Url"]'); } - get generalSiteUrlReset() { return browser.element('.reset-setting[data-setting="Site_Url"]'); } + get generalSiteName() { return browser.element('[data-qa-setting-id="Site_Name"]'); } - get generalSiteName() { return browser.element('[name="Site_Name"]'); } + get generalSiteNameReset() { return browser.element('[data-qa-reset-setting-id="Site_Name"]'); } - get generalSiteNameReset() { return browser.element('.reset-setting[data-setting="Site_Name"]'); } - - get generalLanguage() { return browser.element('[name="Language"]'); } + get generalLanguage() { return browser.element('[data-qa-setting-id="Language"]'); } get generalLanguagePtOption() { return browser.element('[value="pt"]'); } - get generalLanguageReset() { return browser.element('.reset-setting[data-setting="Language"]'); } - - get generalSelfSignedCertsTrue() { return browser.element('label:nth-of-type(1) [name="Allow_Invalid_SelfSigned_Certs"]'); } - - get generalSelfSignedCertsFalse() { return browser.element('label:nth-of-type(2) [name="Allow_Invalid_SelfSigned_Certs"]'); } - - get generalSelfSignedCertsReset() { return browser.element('.reset-setting[data-setting="Allow_Invalid_SelfSigned_Certs"]'); } - - get generalFavoriteRoomTrue() { return browser.element('label:nth-of-type(1) [name="Favorite_Rooms"]'); } - - get generalFavoriteRoomFalse() { return browser.element('label:nth-of-type(2) [name="Favorite_Rooms"]'); } - - get generalFavoriteRoomReset() { return browser.element('.reset-setting[data-setting="Favorite_Rooms"]'); } + get generalLanguageReset() { return browser.element('[data-qa-reset-setting-id="Language"]'); } - get generalOpenFirstChannel() { return browser.element('[name="First_Channel_After_Login"]'); } + get generalSelfSignedCerts() { return browser.element('[data-qa-setting-id="Allow_Invalid_SelfSigned_Certs"]'); } - get generalOpenFirstChannelReset() { return browser.element('.reset-setting[data-setting="First_Channel_After_Login"]'); } + get generalSelfSignedCertsReset() { return browser.element('[data-qa-reset-setting-id="Allow_Invalid_SelfSigned_Certs"]'); } - get generalCdnPrefix() { return browser.element('[name="CDN_PREFIX"]'); } + get generalFavoriteRoom() { return browser.element('[data-qa-setting-id="Favorite_Rooms"]'); } - get generalCdnPrefixReset() { return browser.element('.reset-setting[data-setting="CDN_PREFIX"]'); } + get generalFavoriteRoomReset() { return browser.element('[data-qa-reset-setting-id="Favorite_Rooms"]'); } - get generalForceSSLTrue() { return browser.element('label:nth-of-type(1) [name="Force_SSL"]'); } + get generalOpenFirstChannel() { return browser.element('[data-qa-setting-id="First_Channel_After_Login"]'); } - get generalForceSSLFalse() { return browser.element('label:nth-of-type(2) [name="Force_SSL"]'); } + get generalOpenFirstChannelReset() { return browser.element('[data-qa-reset-setting-id="First_Channel_After_Login"]'); } - get generalForceSSLReset() { return browser.element('.reset-setting[data-setting="Force_SSL"]'); } + get generalCdnPrefix() { return browser.element('[data-qa-setting-id="CDN_PREFIX"]'); } - get generalGoogleTagId() { return browser.element('[name="GoogleTagManager_id"]'); } + get generalCdnPrefixReset() { return browser.element('[data-qa-reset-setting-id="CDN_PREFIX"]'); } - get generalGoogleTagIdReset() { return browser.element('.reset-setting[data-setting="GoogleTagManager_id"]'); } + get generalForceSSL() { return browser.element('[data-qa-setting-id="Force_SSL"]'); } - get generalBugsnagKey() { return browser.element('[name="Bugsnag_api_key"]'); } + get generalForceSSLReset() { return browser.element('[data-qa-reset-setting-id="Force_SSL"]'); } - get generalBugsnagKeyReset() { return browser.element('.reset-setting[data-setting="Bugsnag_api_key"]'); } + get generalGoogleTagId() { return browser.element('[data-qa-setting-id="GoogleTagManager_id"]'); } - get generalIframeSendTrue() { return browser.element('label:nth-of-type(1) [name="Iframe_Integration_send_enable"]'); } + get generalGoogleTagIdReset() { return browser.element('[data-qa-reset-setting-id="GoogleTagManager_id"]'); } - get generalIframeSendFalse() { return browser.element('label:nth-of-type(2) [name="Iframe_Integration_send_enable"]'); } + get generalBugsnagKey() { return browser.element('[data-qa-setting-id="Bugsnag_api_key"]'); } - get generalIframeSendReset() { return browser.element('.reset-setting[data-setting="Iframe_Integration_send_enable"]'); } + get generalBugsnagKeyReset() { return browser.element('[data-qa-reset-setting-id="Bugsnag_api_key"]'); } - get generalIframeSendTargetOrigin() { return browser.element('[name="Iframe_Integration_send_target_origin"]'); } + get generalIframeSend() { return browser.element('[data-qa-setting-id="Iframe_Integration_send_enable"]'); } - get generalIframeSendTargetOriginReset() { return browser.element('.reset-setting[data-setting="Iframe_Integration_send_target_origin"]'); } + get generalIframeSendReset() { return browser.element('[data-qa-reset-setting-id="Iframe_Integration_send_enable"]'); } - get generalIframeRecieveTrue() { return browser.element('label:nth-of-type(1) [name="Iframe_Integration_receive_enable"]'); } + get generalIframeSendTargetOrigin() { return browser.element('[data-qa-setting-id="Iframe_Integration_send_target_origin"]'); } - get generalIframeRecieveFalse() { return browser.element('label:nth-of-type(2) [name="Iframe_Integration_receive_enable"]'); } + get generalIframeSendTargetOriginReset() { return browser.element('[data-qa-reset-setting-id="Iframe_Integration_send_target_origin"]'); } - get generalIframeRecieveFalseReset() { return browser.element('.reset-setting[data-setting="Iframe_Integration_receive_enable"]'); } + get generalIframeRecieve() { return browser.element('[data-qa-setting-id="Iframe_Integration_receive_enable"]'); } - get generalIframeRecieveOrigin() { return browser.element('[name="Iframe_Integration_receive_origin"]'); } + get generalIframeRecieveOrigin() { return browser.element('[data-qa-setting-id="Iframe_Integration_receive_origin"]'); } - get generalIframeRecieveOriginReset() { return browser.element('.reset-setting[data-setting="Iframe_Integration_receive_origin"]'); } + get generalIframeRecieveOriginReset() { return browser.element('[data-qa-reset-setting-id="Iframe_Integration_receive_origin"]'); } - get generalNotificationsMaxRoomMembers() { return browser.element('[name="Notifications_Max_Room_Members"]'); } + get generalNotificationsMaxRoomMembers() { return browser.element('[data-qa-setting-id="Notifications_Max_Room_Members"]'); } - get generalNotificationsMaxRoomMembersReset() { return browser.element('.reset-setting[data-setting="Notifications_Max_Room_Members"]'); } + get generalNotificationsMaxRoomMembersReset() { return browser.element('[data-qa-reset-setting-id="Notifications_Max_Room_Members"]'); } - get generalRestApiUserLimit() { return browser.element('[name="API_User_Limit"]'); } + get generalRestApiUserLimit() { return browser.element('[data-qa-setting-id="API_User_Limit"]'); } - get generalRestApiUserLimitReset() { return browser.element('.reset-setting[data-setting="API_User_Limit"]'); } + get generalRestApiUserLimitReset() { return browser.element('[data-qa-reset-setting-id="API_User_Limit"]'); } - get generalReportingTrue() { return browser.element('label:nth-of-type(1) [name="Statistics_reporting"]'); } + get generalReporting() { return browser.element('[data-qa-setting-id="Statistics_reporting"]'); } - get generalReportingFalse() { return browser.element('label:nth-of-type(2) [name="Statistics_reporting"]'); } + get generalReportingReset() { return browser.element('[data-qa-reset-setting-id="Statistics_reporting"]'); } - get generalReportingReset() { return browser.element('.reset-setting[data-setting="Statistics_reporting"]'); } + get generalStreamCastAdress() { return browser.element('[data-qa-setting-id="Stream_Cast_Address"]'); } - get generalStreamCastAdress() { return browser.element('[name="Stream_Cast_Address"]'); } + get generalStreamCastAdressReset() { return browser.element('[data-qa-reset-setting-id="Stream_Cast_Address"]'); } - get generalStreamCastAdressReset() { return browser.element('.reset-setting[data-setting="Stream_Cast_Address"]'); } + get generalUTF8Regex() { return browser.element('[data-qa-setting-id="UTF8_Names_Validation"]'); } - get generalUTF8Regex() { return browser.element('[name="UTF8_Names_Validation"]'); } + get generalUTF8RegexReset() { return browser.element('[data-qa-reset-setting-id="UTF8_Names_Validation"]'); } - get generalUTF8RegexReset() { return browser.element('.reset-setting[data-setting="UTF8_Names_Validation"]'); } + get generalUTF8NamesSlug() { return browser.element('[data-qa-setting-id="UTF8_Names_Slugify"]'); } - get generalUTF8NamesSlugTrue() { return browser.element('label:nth-of-type(1) [name="UTF8_Names_Slugify"]'); } + get generalUTF8NamesSlugReset() { return browser.element('[data-qa-reset-setting-id="UTF8_Names_Slugify"]'); } - get generalUTF8NamesSlugFalse() { return browser.element('label:nth-of-type(2) [name="UTF8_Names_Slugify"]'); } - - get generalUTF8NamesSlugReset() { return browser.element('.reset-setting[data-setting="UTF8_Names_Slugify"]'); } - - get generalLayoutTitle() { return browser.element('[name="Layout_Home_Title"]'); } + get generalLayoutTitle() { return browser.element('[data-qa-setting-id="Layout_Home_Title"]'); } // accounts - get accountsButtonExpandDefaultUserPreferences() { return browser.element('.section:nth-of-type(2) .expand'); } - - get accountsButtonCollapseDefaultUserPreferences() { return browser.element('.section:nth-of-type(2) .collapse'); } - - get accountsEnableAutoAwayTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_enableAutoAway"]'); } - - get accountsEnableAutoAwayFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_enableAutoAway"]'); } - - get accountsEnableAutoAwayReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_enableAutoAway"]'); } - - get accountsidleTimeLimit() { return browser.element('[name="Accounts_Default_User_Preferences_idleTimeLimit"]'); } - - get accountsidleTimeLimitReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_idleTimeLimit"]'); } - - get accountsNotificationDuration() { return browser.element('[name="Accounts_Default_User_Preferences_desktopNotificationDuration"]'); } - - get accountsNotificationDurationReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_desktopNotificationDuration"]'); } - - get accountsAudioNotifications() { return browser.element('[name="Accounts_Default_User_Preferences_audioNotifications"]'); } - - get accountsAudioNotificationsReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_audioNotifications"]'); } - - get accountsDesktopNotifications() { return browser.element('[name="Accounts_Default_User_Preferences_desktopNotifications"]'); } - - get accountsDesktopNotificationsReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_desktopNotifications"]'); } - - get accountsMobileNotifications() { return browser.element('[name="Accounts_Default_User_Preferences_mobileNotifications"]'); } - - get accountsMobileNotificationsReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_mobileNotifications"]'); } - - get accountsUnreadAlertTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_unreadAlert"]'); } - - get accountsUnreadAlertFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_unreadAlert"]'); } - - get accountsUnreadAlertReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_unreadAlert"]'); } - - get accountsUseEmojisTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_useEmojis"]'); } + get accountsSectionDefaultUserPreferences() { return browser.element('[data-qa-section="Accounts_Default_User_Preferences"]'); } - get accountsUseEmojisFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_useEmojis"]'); } + get accountsEnableAutoAway() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_enableAutoAway"]'); } - get accountsUseEmojisReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_useEmojis"]'); } + get accountsEnableAutoAwayReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_enableAutoAway"]'); } - get accountsConvertAsciiEmojiTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_convertAsciiEmoji"]'); } + get accountsidleTimeLimit() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_idleTimeLimit"]'); } - get accountsConvertAsciiEmojiFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_convertAsciiEmoji"]'); } + get accountsidleTimeLimitReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_idleTimeLimit"]'); } - get accountsConvertAsciiEmojiReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_convertAsciiEmoji"]'); } + get accountsNotificationDuration() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_desktopNotificationDuration"]'); } - get accountsAutoImageLoadTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_autoImageLoad"]'); } + get accountsNotificationDurationReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_desktopNotificationDuration"]'); } - get accountsAutoImageLoadFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_autoImageLoad"]'); } + get accountsAudioNotifications() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_audioNotifications"]'); } - get accountsAutoImageLoadReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_autoImageLoad"]'); } + get accountsAudioNotificationsReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_audioNotifications"]'); } - get accountsSaveMobileBandwidthTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_saveMobileBandwidth"]'); } + get accountsDesktopNotifications() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_desktopNotifications"]'); } - get accountsSaveMobileBandwidthFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_saveMobileBandwidth"]'); } + get accountsDesktopNotificationsReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_desktopNotifications"]'); } - get accountsSaveMobileBandwidthReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_saveMobileBandwidth"]'); } + get accountsMobileNotifications() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_mobileNotifications"]'); } - get accountsCollapseMediaByDefaultTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_collapseMediaByDefault"]'); } + get accountsMobileNotificationsReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_mobileNotifications"]'); } - get accountsCollapseMediaByDefaultFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_collapseMediaByDefault"]'); } + get accountsUnreadAlert() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_unreadAlert"]'); } - get accountsCollapseMediaByDefaultReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_collapseMediaByDefault"]'); } + get accountsUnreadAlertReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_unreadAlert"]'); } - get accountsHideUsernamesTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_hideUsernames"]'); } + get accountsUseEmojis() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_useEmojis"]'); } - get accountsHideUsernamesFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_hideUsernames"]'); } + get accountsUseEmojisReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_useEmojis"]'); } - get accountsHideUsernamesReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_hideUsernames"]'); } + get accountsConvertAsciiEmoji() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_convertAsciiEmoji"]'); } - get accountsHideRolesTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_hideRoles"]'); } + get accountsConvertAsciiEmojiReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_convertAsciiEmoji"]'); } - get accountsHideRolesFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_hideRoles"]'); } + get accountsAutoImageLoad() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_autoImageLoad"]'); } - get accountsHideRolesReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_hideRoles"]'); } + get accountsAutoImageLoadReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_autoImageLoad"]'); } - get accountsHideFlexTabTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_hideFlexTab"]'); } + get accountsSaveMobileBandwidth() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_saveMobileBandwidth"]'); } - get accountsHideFlexTabFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_hideFlexTab"]'); } + get accountsSaveMobileBandwidthReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_saveMobileBandwidth"]'); } - get accountsHideFlexTabReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_hideFlexTab"]'); } + get accountsCollapseMediaByDefault() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_collapseMediaByDefault"]'); } - get accountsHideAvatarsTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_hideAvatars"]'); } + get accountsCollapseMediaByDefaultReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_collapseMediaByDefault"]'); } - get accountsHideAvatarsFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_hideAvatars"]'); } + get accountsHideUsernames() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_hideUsernames"]'); } - get accountsHideAvatarsReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_hideAvatars"]'); } + get accountsHideUsernamesReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_hideUsernames"]'); } - get accountsMergeChannelsTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_mergeChannels"]'); } + get accountsHideRoles() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_hideRoles"]'); } - get accountsMergeChannelsFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_mergeChannels"]'); } + get accountsHideRolesReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_hideRoles"]'); } - get accountsMergeChannelsReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_mergeChannels"]'); } + get accountsHideFlexTab() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_hideFlexTab"]'); } - get accountsSendOnEnter() { return browser.element('[name="Accounts_Default_User_Preferences_sendOnEnter"]'); } + get accountsHideFlexTabReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_hideFlexTab"]'); } - get accountsSendOnEnterReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_sendOnEnter"]'); } + get accountsHideAvatars() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_hideAvatars"]'); } - get accountsMessageViewMode() { return browser.element('[name="Accounts_Default_User_Preferences_messageViewMode"]'); } + get accountsHideAvatarsReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_hideAvatars"]'); } - get accountsMessageViewModeReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_messageViewMode"]'); } + get accountsMergeChannels() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_mergeChannels"]'); } - get accountsEmailNotificationMode() { return browser.element('[name="Accounts_Default_User_Preferences_emailNotificationMode"]'); } + get accountsMergeChannelsReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_mergeChannels"]'); } - get accountsEmailNotificationModeReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_emailNotificationMode"]'); } + get accountsSendOnEnter() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_sendOnEnter"]'); } - get accountsRoomCounterSidebarTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_roomCounterSidebar"]'); } + get accountsSendOnEnterReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_sendOnEnter"]'); } - get accountsRoomCounterSidebarFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_roomCounterSidebar"]'); } + get accountsMessageViewMode() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_messageViewMode"]'); } - get accountsRoomCounterSidebarReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_roomCounterSidebar"]'); } + get accountsMessageViewModeReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_messageViewMode"]'); } - get accountsNewRoomNotification() { return browser.element('[name="Accounts_Default_User_Preferences_newRoomNotification"]'); } + get accountsEmailNotificationMode() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_emailNotificationMode"]'); } - get accountsNewRoomNotificationReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_newRoomNotification"]'); } + get accountsEmailNotificationModeReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_emailNotificationMode"]'); } - get accountsNewMessageNotification() { return browser.element('[name="Accounts_Default_User_Preferences_newMessageNotification"]'); } + get accountsRoomCounterSidebar() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_roomCounterSidebar"]'); } - get accountsNewMessageNotificationReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_newMessageNotification"]'); } + get accountsRoomCounterSidebarReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_roomCounterSidebar"]'); } - get accountsMuteFocusedConversationsTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_Default_User_Preferences_muteFocusedConversations"]'); } + get accountsNewRoomNotification() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_newRoomNotification"]'); } - get accountsMuteFocusedConversationsFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_Default_User_Preferences_muteFocusedConversations"]'); } + get accountsNewRoomNotificationReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_newRoomNotification"]'); } - get accountsMuteFocusedConversationsReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_muteFocusedConversations"]'); } + get accountsNewMessageNotification() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_newMessageNotification"]'); } - get accountsNotificationsSoundVolume() { return browser.element('[name="Accounts_Default_User_Preferences_notificationsSoundVolume"]'); } + get accountsNewMessageNotificationReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_newMessageNotification"]'); } - get accountsNotificationsSoundVolumeReset() { return browser.element('.reset-setting[data-setting="Accounts_Default_User_Preferences_notificationsSoundVolume"]'); } + get accountsMuteFocusedConversations() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_muteFocusedConversations"]'); } - get accountsRealNameChangeTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_AllowRealNameChange"]'); } + get accountsMuteFocusedConversationsReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_muteFocusedConversations"]'); } - get accountsRealNameChangeFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_AllowRealNameChange"]'); } + get accountsNotificationsSoundVolume() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_notificationsSoundVolume"]'); } - get accountsUserStatusMessageChangeTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_AllowUserStatusMessageChange"]'); } + get accountsNotificationsSoundVolumeReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_notificationsSoundVolume"]'); } - get accountsUserStatusMessageChangeFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_AllowUserStatusMessageChange"]'); } + get accountsRealNameChange() { return browser.element('[data-qa-setting-id="Accounts_AllowRealNameChange"]'); } - get accountsUsernameChangeTrue() { return browser.element('label:nth-of-type(1) [name="Accounts_AllowUsernameChange"]'); } + get accountsUserStatusMessageChange() { return browser.element('[data-qa-setting-id="Accounts_AllowUserStatusMessageChange"]'); } - get accountsUsernameChangeFalse() { return browser.element('label:nth-of-type(2) [name="Accounts_AllowUsernameChange"]'); } + get accountsUsernameChange() { return browser.element('[data-qa-setting-id="Accounts_AllowUsernameChange"]'); } get layoutButtonExpandContent() { return browser.element('.section:nth-of-type(2) .rc-button.rc-button--nude'); }