Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
09abe69
WIP
gabriellsh May 29, 2020
a894a4b
Ready for review
gabriellsh Jun 1, 2020
1b301b4
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into new/…
gabriellsh Jun 1, 2020
541ba80
lint
gabriellsh Jun 1, 2020
a259ed8
Review semi-complete
gabriellsh Jun 1, 2020
147908f
Fix scroll + added loading
gabriellsh Jun 4, 2020
2a8f351
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into new/…
gabriellsh Jun 4, 2020
b50b435
Merge branch 'develop' into new/rewrite_admin_sidebar
tassoevan Jun 8, 2020
b6f4e83
Use ghost close button
tassoevan Jun 8, 2020
86f6921
Merge branch 'develop' into new/rewrite_admin_sidebar
tassoevan Jun 9, 2020
a3184a8
Merge branch 'develop' into new/rewrite_admin_sidebar
tassoevan Jun 9, 2020
0aefa52
Fix safari shrinking items.
gabriellsh Jun 9, 2020
18e48c8
Remove unused webpack loader
tassoevan Jun 9, 2020
206c114
Rename "PrivateSettings" as "PrivilegedSettings"
tassoevan Jun 9, 2020
97fd3d6
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into new/…
tassoevan Jun 9, 2020
109b477
Uplift PrivilegedSettingsProvider
tassoevan Jun 9, 2020
808a2cd
Replace adminFlex template
tassoevan Jun 10, 2020
8d6f8eb
Merge hook for sidebar into PrivilegedSettingsContext
tassoevan Jun 10, 2020
c15d840
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into new/…
tassoevan Jun 10, 2020
0f49120
Use PrivateSettingsCachedCollection as a singleton
tassoevan Jun 10, 2020
3a2efa2
Merge branch 'develop' into new/rewrite_admin_sidebar
tassoevan Jun 10, 2020
12b250f
Replace callback invalidations
tassoevan Jun 10, 2020
b21cbe4
Add ReactDOM types
tassoevan Jun 10, 2020
42063ee
Add scaffolding of AdministrationLayout
tassoevan Jun 10, 2020
54fd0cd
Remove LegacyRoute
tassoevan Jun 11, 2020
d27ac40
Wait for React route destruction before replace room's DOM node
tassoevan Jun 11, 2020
0a08bc5
Auto Close Sidebar and focus status
ggazzo Jun 11, 2020
f6cbe6d
Merge branch 'develop' into new/rewrite_admin_sidebar
tassoevan Jun 11, 2020
8ab38b7
placeholder
ggazzo Jun 11, 2020
a17473d
Paddings
ggazzo Jun 11, 2020
d94ade6
Merge branch 'new/rewrite_admin_sidebar' of github.com:RocketChat/Roc…
ggazzo Jun 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ module.exports = async ({ config }) => {
},
},
},
'react-docgen-typescript-loader',
],
});

Expand Down
4 changes: 3 additions & 1 deletion client/admin/AdministrationRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import React, { lazy, useMemo, Suspense, useEffect } from 'react';

import { SideNav } from '../../app/ui-utils/client';
import PageSkeleton from './PageSkeleton';
import { createTemplateForComponent } from '../reactAdapters';

function AdministrationRouter({ lazyRouteComponent, ...props }) {
useEffect(() => {
SideNav.setFlex('adminFlex');
const templateName = createTemplateForComponent('AdminSidebar', () => import('./sidebar/AdminSidebar'));
SideNav.setFlex(templateName);
SideNav.openFlex();
}, []);

Expand Down
128 changes: 128 additions & 0 deletions client/admin/sidebar/AdminSidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { useCallback, useState, useMemo } from 'react';
import { Box, Button, Icon, SearchInput, Scrollable, Skeleton } from '@rocket.chat/fuselage';
import { css } from '@rocket.chat/css-in-js';

import { menu, SideNav, Layout } from '../../../app/ui-utils/client';
import { useReactiveValue } from '../../hooks/useReactiveValue';
import { useTranslation } from '../../contexts/TranslationContext';
import { useRoutePath, useCurrentRoute } from '../../contexts/RouterContext';
import { useAtLeastOnePermission } from '../../contexts/AuthorizationContext';
import { sidebarItems } from '../sidebarItems';
import { useSettingsGroupsFiltered } from './useSettingsGroupsFiltered';

const SidebarItem = ({ permissionGranted, pathGroup, href, icon, label, currentPath }) => {
if (permissionGranted && !permissionGranted()) { return null; }
const params = useMemo(() => ({ group: pathGroup }), [pathGroup]);
const path = useRoutePath(href, params);
const isActive = path === currentPath || false;
return useMemo(() => <Box
Comment thread
gabriellsh marked this conversation as resolved.
Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not React.memo?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ggazzo React.memo() returns a new component, which should be declared outside this component scope.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure I know , but why not wrap the component as a memoized component instead if this approach?

is='a'
color='default'
pb='x8'
pi='x24'
key={path}
href={path}
display='flex'
flexDirection='row'
alignItems='center'
className={[
isActive && 'active',
css`
&:hover,
&.active:hover {
background-color: var(--sidebar-background-light-hover);
}

&.active {
background-color: var(--sidebar-background-light-active);
}
`,
].filter(Boolean)}
>
{icon && <Icon name={icon} size='x16' mi='x2'/>}
<Box withTruncatedText fontScale='p1' mi='x4'>{label}</Box>
</Box>, [path, label, name, icon, isActive]);
};

const SidebarItemsAssembler = ({ items, currentPath }) => {
const t = useTranslation();
return items.map(({
href,
i18nLabel,
name,
icon,
permissionGranted,
pathGroup,
}) => <SidebarItem
permissionGranted={permissionGranted}
pathGroup={pathGroup}
href={href}
icon={icon}
label={t(i18nLabel || name)}
key={i18nLabel || name}
currentPath={currentPath}
/>);
};

const AdminSidebarPages = ({ currentPath }) => {
const items = useReactiveValue(() => sidebarItems.get());

return <Box is='ul' display='flex' flexDirection='column' flexShrink={0}>
{useMemo(() => <SidebarItemsAssembler items={items} currentPath={currentPath}/>, [items, currentPath])}
</Box>;
};

const AdminSidebarSettings = ({ currentPath }) => {
const t = useTranslation();
const [filter, setFilter] = useState('');
const handleChange = useCallback((e) => setFilter(e.currentTarget.value), []);

const [groups, loading] = useSettingsGroupsFiltered(filter);

const showGroups = !!groups.length;

return <Box is='section' display='flex' flexDirection='column' flexShrink={0}>
<Box mi='x24' mb='x16' fontScale='p2' color='hint'>{t('Settings')}</Box>
<Box pi='x24' mb='x8' display='flex'>
<Box is={SearchInput} border='0' value={filter} onChange={handleChange} addon={<Icon name='magnifier' size='x20'/>}/>
</Box>
<Box is='ul' display='flex' flexDirection='column'>
{loading && <Skeleton/>}
{!loading && showGroups && <SidebarItemsAssembler items={groups} currentPath={currentPath}/>}
{!loading && !showGroups && <Box pi='x28' mb='x4' color='hint'>{t('Nothing_found')}</Box>}
</Box>
</Box>;
};

export default function AdminSidebar() {
const t = useTranslation();

const canViewSettings = useAtLeastOnePermission(['view-privileged-setting', 'edit-privileged-setting', 'manage-selected-settings']);

const closeAdminFlex = useCallback(() => {
if (Layout.isEmbedded()) {
menu.close();
return;
}

SideNav.closeFlex();
}, []);

const currentRoute = useCurrentRoute();
const currentPath = useRoutePath(...currentRoute);

return <Box display='flex' flexDirection='column' h='100vh'>
<Box is='header' padding='x24' display='flex' flexDirection='row' justifyContent='space-between'>
<Box fontScale='s1'>{t('Administration')}</Box>
<Button square small ghost onClick={closeAdminFlex}>
<Icon name='cross' size='x16'/>
</Button>
</Box>
<Scrollable>
<Box display='flex' flexDirection='column' h='full'>
<AdminSidebarPages currentPath={currentPath}/>
{canViewSettings && <AdminSidebarSettings currentPath={currentPath}/>}
</Box>
</Scrollable>
</Box>;
}
64 changes: 64 additions & 0 deletions client/admin/sidebar/useSettingsGroupsFiltered.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useMemo, useState, useEffect } from 'react';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';

import { settings } from '../../../app/settings';
import { useTranslation } from '../../contexts/TranslationContext';
import { PrivateSettingsCachedCollection } from '../PrivateSettingsCachedCollection';

export const useSettingsGroupsFiltered = (textFilter) => {
Comment thread
tassoevan marked this conversation as resolved.
Outdated
const t = useTranslation();

const [collection, setCollection] = useState(settings.collectionPrivate);

const [loading, setLoading] = useState(true);

const filter = useDebouncedValue(textFilter, 400);

useEffect(() => {
(async function getCollection() {
if (!settings.cachedCollectionPrivate) {
settings.cachedCollectionPrivate = new PrivateSettingsCachedCollection();
settings.collectionPrivate = settings.cachedCollectionPrivate.collection;
await settings.cachedCollectionPrivate.init();
}
setCollection(settings.collectionPrivate);
setLoading(false);
}());
}, []);

return useMemo(() => {
if (loading) { return [[], loading]; }

const query = {
type: 'group',
};

const groups = [];
if (filter) {
const filterRegex = new RegExp(filter, 'i');
const records = collection.find().fetch();
records.forEach(function(record) {
if (filterRegex.test(t(record.i18nLabel || record._id))) {
!groups.includes(record.group || record._id) && groups.push(record.group || record._id);
}
});

if (groups.length > 0) {
query._id = {
$in: groups,
};
}
}

if (filter && groups.length === 0) {
return [[], loading];
}

const result = collection.find(query)
.fetch()
.map((item) => ({ name: t(item.i18nLabel || item._id), href: 'admin', pathGroup: item._id }))
.sort(({ name: a }, { name: b }) => (a.toLowerCase() >= b.toLowerCase() ? 1 : -1));

return [result, loading];
}, [filter, collection, loading]);
};
Loading