Prototype decoupling between template component and its hooks

alpha/blocketchat
Tasso Evangelista 6 years ago
parent c5afec2d44
commit cb1b468dbf
  1. 11
      .storybook/.babelrc
  2. 2
      .storybook/addons.js
  3. 23
      .storybook/config.js
  4. 1
      .storybook/empty.js
  5. 68
      .storybook/meteor.js
  6. 31
      .storybook/webpack.config.js
  7. 10
      client/components/admin/hooks.js
  8. 78
      client/components/admin/info/InformationPage.js
  9. 148
      client/components/admin/info/InformationPage.stories.js
  10. 6
      client/components/admin/info/RocketChatSection.js
  11. 4
      client/components/admin/info/RuntimeEnvironmentSection.js
  12. 6
      client/components/admin/info/UsageSection.js
  13. 104
      client/components/header/BurgerMenuButton.js
  14. 25
      client/components/header/BurgerMenuButton.stories.js
  15. 16
      client/components/header/Header.js
  16. 19
      client/components/header/Header.stories.js
  17. 53
      client/components/header/hooks.js
  18. 13
      client/hooks/useMethod.js
  19. 3
      client/hooks/useRocketChatInformation.js
  20. 7
      client/routes.js
  21. 254
      package-lock.json
  22. 3
      package.json

@ -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"
]
}
}

@ -1,2 +1,4 @@
import '@storybook/addon-actions/register';
import '@storybook/addon-knobs/register';
import '@storybook/addon-links/register';
import '@storybook/addon-viewport/register';

@ -1,16 +1,27 @@
import { action } from '@storybook/addon-actions';
import { addDecorator, configure } from '@storybook/react';
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';
addDecorator(function RocketChatDecorator(fn) {
require('@rocket.chat/icons/dist/font/RocketChat.minimal.css');
require('../app/theme/client/main.css');
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('@rocket.chat/icons/dist/font/RocketChat.minimal.css');
require('../app/theme/client/main.css');
linkElement.setAttribute('id', 'theme-styles');
linkElement.setAttribute('rel', 'stylesheet');
linkElement.setAttribute('href', 'https://open.rocket.chat/theme.css');
@ -25,7 +36,7 @@ addDecorator(function RocketChatDecorator(fn) {
}
`}</style>
<div className='rc-old'>
<div dangerouslySetInnerHTML={{__html: require('!!raw-loader!../private/public/icons.svg').default}} />
<div dangerouslySetInnerHTML={{ __html: require('!!raw-loader!../private/public/icons.svg').default }} />
<div className='global-font-family color-primary-font-color'>
{fn()}
</div>
@ -34,4 +45,6 @@ addDecorator(function RocketChatDecorator(fn) {
</ConnectionStatusProvider>;
});
addDecorator(withKnobs);
configure(require.context('../client', true, /\.stories\.js$/), module);

@ -0,0 +1 @@
export default {};

@ -0,0 +1,68 @@
export const Meteor = {
isClient: true,
isServer: false,
_localStorage: window.localStorage,
userId: () => {},
Streamer: () => {},
startup: () => {},
methods: () => {},
call: () => {},
};
export const Tracker = {
autorun: () => {},
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: () => {},
};

@ -1,8 +1,10 @@
'use strict';
module.exports = async ({ config, mode }) => {
const webpack = require('webpack');
module.exports = async ({ config }) => {
const cssRule = config.module.rules.find(({ test }) => test.test('index.css'));
cssRule.use[1].options.url = (url, resourcePath) => {
cssRule.use[1].options.url = (url) => {
if (/^(\.\/)?images\//.test(url)) {
return false;
}
@ -18,5 +20,28 @@ module.exports = async ({ config, mode }) => {
require('autoprefixer')(),
];
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;
};

@ -0,0 +1,10 @@
import { useEffect } from 'react';
import { SideNav } from '../../../app/ui-utils/client';
export const useAdminSideNav = () => {
useEffect(() => {
SideNav.setFlex('adminFlex');
SideNav.openFlex();
}, []);
};

@ -1,15 +1,14 @@
import { Button, Icon } from '@rocket.chat/fuselage';
import React, { useEffect, useState } from 'react';
import { call } from '../../../../app/ui-utils/client/lib/callMethod';
import { useMethod } from '../../../hooks/useMethod';
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 { useRocketChatInformation } from '../../../hooks/useRocketChatInformation';
import { useTranslation } from '../../../hooks/useTranslation';
import { Header } from '../../header/Header';
import { Link } from '../../basic/Link';
import { ErrorAlert } from '../../basic/ErrorAlert';
import { useTranslation } from '../../../hooks/useTranslation';
import { useAdminSideNav } from '../hooks';
import { RocketChatSection } from './RocketChatSection';
import { CommitSection } from './CommitSection';
import { RuntimeEnvironmentSection } from './RuntimeEnvironmentSection';
@ -17,11 +16,17 @@ import { BuildEnvironmentSection } from './BuildEnvironmentSection';
import { UsageSection } from './UsageSection';
import { InstancesSection } from './InstancesSection';
const useStatistics = (canViewStatistics) => {
export const useInformationPage = () => {
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;
@ -37,8 +42,8 @@ const useStatistics = (canViewStatistics) => {
try {
const [statistics, instances] = await Promise.all([
call('getStatistics'),
call('instances/get'),
getStatistics(),
getInstances(),
]);
if (didCancel) {
@ -61,40 +66,39 @@ const useStatistics = (canViewStatistics) => {
};
}, [canViewStatistics]);
const info = useRocketChatInformation();
const handleClickRefreshButton = () => {
if (isLoading) {
return;
}
fetchStatistics();
};
return {
canViewStatistics,
isLoading,
info,
statistics,
instances,
fetchStatistics,
onClickRefreshButton: handleClickRefreshButton,
};
};
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;
@ -102,7 +106,7 @@ export function InformationPage() {
<Header rawSectionName={t('Info')} hideHelp>
{canViewStatistics
&& <div className='rc-header__block rc-header__block-action'>
<Button primary type='button' onClick={handleRefreshClick}>
<Button disabled={isLoading} primary type='button' onClick={onClickRefreshButton}>
<Icon iconName='reload' /> {t('Refresh')}
</Button>
</div>}
@ -121,11 +125,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>;

@ -0,0 +1,148 @@
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,
};
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')}
/>;

@ -10,11 +10,7 @@ export function RocketChatSection({ info, statistics, isLoading }) {
const s = (fn) => (isLoading ? <SkeletonText /> : fn());
const t = useTranslation();
const appsEngineVersion = info.marketplaceApiVersion;
if (!statistics) {
return null;
}
const appsEngineVersion = info && info.marketplaceApiVersion;
return <>
<h3>{t('Rocket.Chat')}</h3>

@ -10,10 +10,6 @@ export function RuntimeEnvironmentSection({ statistics, isLoading }) {
const s = (fn) => (isLoading ? <SkeletonText /> : fn());
const t = useTranslation();
if (!statistics) {
return null;
}
return <>
<h3>{t('Runtime_Environment')}</h3>
<InformationList>

@ -10,10 +10,6 @@ export function UsageSection({ statistics, isLoading }) {
const s = (fn) => (isLoading ? <SkeletonText /> : fn());
const t = useTranslation();
if (!statistics) {
return null;
}
return <>
<h3>{t('Usage')}</h3>
<InformationList>
@ -38,7 +34,7 @@ export function UsageSection({ statistics, isLoading }) {
<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 && <>
{statistics && statistics.apps && <>
<InformationEntry label={t('Stats_Total_Installed_Apps')}>{statistics.apps.totalInstalled}</InformationEntry>
<InformationEntry label={t('Stats_Total_Active_Apps')}>{statistics.apps.totalActive}</InformationEntry>
</>}

@ -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>;

@ -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' />;

@ -2,6 +2,8 @@ import React from 'react';
import { useTranslation } from '../../hooks/useTranslation';
import { BurgerMenuButton } from './BurgerMenuButton';
import { useSidebarState, useUnreadMessagesBadge } from './hooks';
import { useEmbeddedLayout } from '../../hooks/useEmbeddedLayout';
export function Header({
children,
@ -9,12 +11,24 @@ 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>

@ -0,0 +1,19 @@
import { boolean, text } from '@storybook/addon-knobs/react';
import React from 'react';
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' />;

@ -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]);
};

@ -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]);

@ -0,0 +1,3 @@
import { Info } from '../../app/utils';
export const useRocketChatInformation = () => Info;

@ -35,6 +35,7 @@ BlazeLayout.setRoot('body');
const createTemplateForComponent = async (
component,
hook = () => ({}),
props = {},
// eslint-disable-next-line new-cap
renderContainerView = () => HTML.DIV()
@ -59,7 +60,7 @@ const createTemplateForComponent = async (
ReactDOM.render(
React.createElement(MeteorProvider, {
children: React.createElement(component, props),
children: React.createElement(() => React.createElement(component, { ...props, ...hook() })),
}), Template.instance().firstNode);
});
});
@ -268,8 +269,8 @@ FlowRouter.route('/admin/:group?', {
action: async ({ group = 'info' } = {}) => {
switch (group) {
case 'info': {
const { InformationPage } = await import('./components/admin/info/InformationPage');
BlazeLayout.render('main', { center: await createTemplateForComponent(InformationPage) });
const { InformationPage, useInformationPage } = await import('./components/admin/info/InformationPage');
BlazeLayout.render('main', { center: await createTemplateForComponent(InformationPage, useInformationPage) });
break;
}

254
package-lock.json generated

@ -2204,6 +2204,12 @@
"protobufjs": "^6.8.6"
}
},
"@icons/material": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
"dev": true
},
"@kossnocorp/desvg": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@kossnocorp/desvg/-/desvg-0.2.0.tgz",
@ -2469,6 +2475,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",
@ -2529,6 +2570,46 @@
}
}
},
"@storybook/addon-knobs": {
"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",
"fast-deep-equal": "^2.0.1",
"global": "^4.3.2",
"lodash": "^4.17.11",
"prop-types": "^15.7.2",
"qs": "^6.6.0",
"react-color": "^2.17.0",
"react-lifecycles-compat": "^3.0.4",
"react-select": "^3.0.0"
},
"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
},
"qs": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz",
"integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==",
"dev": true
}
}
},
"@storybook/addon-links": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-5.2.4.tgz",
@ -2559,6 +2640,33 @@
}
}
},
"@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.4",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-5.2.4.tgz",
@ -5295,6 +5403,15 @@
"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",
@ -12387,6 +12504,15 @@
"utila": "~0.4"
}
},
"dom-helpers": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.1.2"
}
},
"dom-serializer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
@ -19399,6 +19525,12 @@
"resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.1.tgz",
"integrity": "sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q=="
},
"material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==",
"dev": true
},
"math-interval-parser": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-1.1.0.tgz",
@ -19705,6 +19837,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",
@ -19881,6 +20047,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",
@ -23281,6 +23458,20 @@
"@babel/runtime": "^7.0.0"
}
},
"react-color": {
"version": "2.17.3",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.17.3.tgz",
"integrity": "sha512-1dtO8LqAVotPIChlmo6kLtFS1FP89ll8/OiA8EcFRDR+ntcK+0ukJgByuIQHRtzvigf26dV5HklnxDIvhON9VQ==",
"dev": true,
"requires": {
"@icons/material": "^0.2.4",
"lodash": "^4.17.11",
"material-colors": "^1.2.1",
"prop-types": "^15.5.10",
"reactcss": "^1.2.0",
"tinycolor2": "^1.4.1"
}
},
"react-dev-utils": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.1.0.tgz",
@ -23736,6 +23927,15 @@
"prop-types": "^15.6.1"
}
},
"react-input-autosize": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.2.tgz",
"integrity": "sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==",
"dev": true,
"requires": {
"prop-types": "^15.5.8"
}
},
"react-inspector": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-3.0.2.tgz",
@ -23820,6 +24020,39 @@
}
}
},
"react-select": {
"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",
"memoize-one": "^5.0.0",
"prop-types": "^15.6.0",
"react-input-autosize": "^2.2.2",
"react-transition-group": "^2.2.1"
},
"dependencies": {
"@babel/runtime": {
"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"
}
},
"regenerator-runtime": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==",
"dev": true
}
}
},
"react-sizeme": {
"version": "2.6.8",
"resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-2.6.8.tgz",
@ -23863,6 +24096,27 @@
"prop-types": "^15.6.0"
}
},
"react-transition-group": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
"dev": true,
"requires": {
"dom-helpers": "^3.4.0",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
}
},
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
"dev": true,
"requires": {
"lodash": "^4.0.1"
}
},
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

@ -99,8 +99,11 @@
"@octokit/rest": "^16.1.0",
"@rocket.chat/eslint-config": "^0.3.0",
"@rocket.chat/livechat": "^1.2.5",
"@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",

Loading…
Cancel
Save