Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 16 additions & 3 deletions apps/meteor/client/lib/createSidebarItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@ export type Item = {
externalUrl?: boolean;
badge?: () => ReactElement;
};
export type SidebarDivider = { divider: boolean; i18nLabel: string };

export type SidebarDivider = {
divider: boolean;
i18nLabel: string;
};

export type SidebarItem = Item | SidebarDivider;

export const isSidebarItem = (item: SidebarItem): item is Item => !('divider' in item);

export const isGoRocketChatLink = (link: string): link is `${typeof GO_ROCKET_CHAT_PREFIX}${string}` =>
export const isGoRocketChatLink = (
link: string,
): link is `${typeof GO_ROCKET_CHAT_PREFIX}${string}` =>
link.startsWith(GO_ROCKET_CHAT_PREFIX);

export const createSidebarItems = (
Expand Down Expand Up @@ -49,7 +57,12 @@ export const createSidebarItems = (

const unregisterSidebarItem = (i18nLabel: SidebarItem['i18nLabel']): void => {
const index = items.findIndex((item) => item.i18nLabel === i18nLabel);
delete items[index];

if (index === -1) {
return;
}

items.splice(index, 1);
updateCb();
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { FC } from 'react';
import { Box, Skeleton } from '@rocket.chat/fuselage';

type ContextualListSkeletonProps = {
items?: number;
};

const ContextualListSkeleton: FC<ContextualListSkeletonProps> = ({ items = 6 }) => (
<Box p='x24'>
{Array.from({ length: items }).map((_, i) => (
<Box key={i} display='flex' alignItems='center' mb='x12'>
<Skeleton variant='rect' width='x40' height='x40' borderRadius='x4' />
<Box mi='x8' flexGrow={1}>
<Skeleton variant='text' width='100%' />
<Skeleton variant='text' width='60%' />
</Box>
</Box>
))}
</Box>
);

export default ContextualListSkeleton;
25 changes: 15 additions & 10 deletions apps/meteor/packages/rocketchat-mongo-config/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import { PassThrough } from 'stream';
import { Email } from 'meteor/email';
import { Mongo } from 'meteor/mongo';

const shouldUseNativeOplog = ['yes', 'true'].includes(String(process.env.USE_NATIVE_OPLOG).toLowerCase());
const shouldUseNativeOplog = ['yes', 'true'].includes(
String(process.env.USE_NATIVE_OPLOG).toLowerCase(),
);

if (!shouldUseNativeOplog) {
Package['disable-oplog'] = {};
}

// FIX For TLS error see more here https://github.com/RocketChat/Rocket.Chat/issues/9316
// TODO: Remove after NodeJS fix it, more information
// https://github.com/nodejs/node/issues/16196
// https://github.com/nodejs/node/pull/16853
// This is fixed in Node 10, but this supports LTS versions
// FIX For TLS error
// https://github.com/RocketChat/Rocket.Chat/issues/9316
// TODO: Remove after NodeJS fix
tls.DEFAULT_ECDH_CURVE = 'auto';

const mongoConnectionOptions = {
Expand All @@ -22,10 +23,13 @@ const mongoConnectionOptions = {
ignoreUndefined: false,

// TODO ideally we should call isTracingEnabled(), but since this is a Meteor package we can't :/
monitorCommands: ['yes', 'true'].includes(String(process.env.TRACING_ENABLED).toLowerCase()),
monitorCommands: ['yes', 'true'].includes(
String(process.env.TRACING_ENABLED).toLowerCase(),
),
};

const mongoOptionStr = process.env.MONGO_OPTIONS;

if (typeof mongoOptionStr !== 'undefined') {
try {
const mongoOptions = JSON.parse(mongoOptionStr);
Expand All @@ -39,15 +43,16 @@ if (Object.keys(mongoConnectionOptions).length > 0) {
Mongo.setConnectionOptions(mongoConnectionOptions);
}

process.env.HTTP_FORWARDED_COUNT = process.env.HTTP_FORWARDED_COUNT || '1';
process.env.HTTP_FORWARDED_COUNT =
process.env.HTTP_FORWARDED_COUNT || '1';

// Just print to logs if in TEST_MODE due to a bug in Meteor 2.5: TypeError: Cannot read property '_syncSendMail' of null
// Just print to logs if in TEST_MODE due to a bug in Meteor 2.5
if (process.env.TEST_MODE === 'true') {
Email.sendAsync = async function _sendAsync(options) {
console.log('Email.sendAsync', options);
};
} else if (process.env.NODE_ENV !== 'development') {
// Send emails to a "fake" stream instead of print them in console in case MAIL_URL or SMTP is not configured
// Send emails to a "fake" stream instead of printing them to console
const stream = new PassThrough();
stream.on('data', () => {});
stream.on('end', () => {});
Expand Down
86 changes: 68 additions & 18 deletions packages/livechat/src/components/Menu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
import { Component, type ComponentChildren } from 'preact';
import { forwardRef } from 'preact/compat';
import type { HTMLAttributes, TargetedEvent } from 'preact/compat';

import { createClassName } from '../../helpers/createClassName';
import { normalizeDOMRect } from '../../helpers/normalizeDOMRect';
import { PopoverTrigger } from '../Popover';
import styles from './styles.scss';

/* ------------------------------------------------------------------ */
/* Menu */
/* ------------------------------------------------------------------ */

type MenuProps = {
hidden?: boolean;
placement?: string;
ref?: any; // FIXME: remove this
} & Omit<HTMLAttributes<HTMLDivElement>, 'ref'>;
} & HTMLAttributes<HTMLDivElement>;

export const Menu = ({ children, hidden, placement = '', ...props }: MenuProps) => (
<div className={createClassName(styles, 'menu', { hidden, placement })} {...props}>
{children}
</div>
export const Menu = forwardRef<HTMLDivElement, MenuProps>(
({ children, hidden, placement = '', ...props }, ref) => (
<div
ref={ref}
className={createClassName(styles, 'menu', { hidden, placement })}
{...props}
>
{children}
</div>
)
);

Menu.displayName = 'Menu';

/* ------------------------------------------------------------------ */
/* Group */
/* ------------------------------------------------------------------ */

type GroupProps = {
title?: string;
} & HTMLAttributes<HTMLDivElement>;
Expand All @@ -29,20 +45,39 @@ export const Group = ({ children, title = '', ...props }: GroupProps) => (
</div>
);

/* ------------------------------------------------------------------ */
/* Item */
/* ------------------------------------------------------------------ */

type ItemProps = {
primary?: boolean;
danger?: boolean;
disabled?: boolean;
icon?: () => ComponentChildren;
} & HTMLAttributes<HTMLButtonElement>;

export const Item = ({ children, primary = false, danger = false, disabled = false, icon = undefined, ...props }: ItemProps) => (
<button className={createClassName(styles, 'menu__item', { primary, danger, disabled })} disabled={disabled} {...props}>
export const Item = ({
children,
primary = false,
danger = false,
disabled = false,
icon,
...props
}: ItemProps) => (
<button
className={createClassName(styles, 'menu__item', { primary, danger, disabled })}
disabled={disabled}
{...props}
>
{icon && <div className={createClassName(styles, 'menu__item__icon')}>{icon()}</div>}
{children}
</button>
);

/* ------------------------------------------------------------------ */
/* PopoverMenuWrapper */
/* ------------------------------------------------------------------ */

type PopoverMenuWrapperProps = {
children?: ComponentChildren;
dismiss: () => void;
Expand All @@ -60,27 +95,31 @@ type PopoverMenuWrapperState = {
placement?: string;
};

class PopoverMenuWrapper extends Component<PopoverMenuWrapperProps, PopoverMenuWrapperState> {
class PopoverMenuWrapper extends Component<
PopoverMenuWrapperProps,
PopoverMenuWrapperState
> {
override state: PopoverMenuWrapperState = {};

menuRef: (Component & { base: Element }) | null = null;
menuRef: HTMLDivElement | null = null;

handleRef = (ref: (Component & { base: Element }) | null) => {
this.menuRef = ref;
handleRef = (el: HTMLDivElement | null) => {
this.menuRef = el;
};

handleClick = ({ target }: TargetedEvent<HTMLElement, MouseEvent>) => {
if (!(target as HTMLElement)?.closest(`.${styles.menu__item}`)) {
return;
}

const { dismiss } = this.props;
dismiss();
this.props.dismiss();
};

override componentDidMount() {
const { triggerBounds, overlayBounds } = this.props;
const menuBounds = normalizeDOMRect(this.menuRef?.base?.getBoundingClientRect());

const menuBounds = normalizeDOMRect(
this.menuRef?.getBoundingClientRect()
);

const menuWidth = menuBounds.right - menuBounds.left;
const menuHeight = menuBounds.bottom - menuBounds.top;
Expand All @@ -96,7 +135,6 @@ class PopoverMenuWrapper extends Component<PopoverMenuWrapperProps, PopoverMenuW

const placement = `${menuWidth < rightSpace ? 'right' : 'left'}-${menuHeight < bottomSpace ? 'bottom' : 'top'}`;

// eslint-disable-next-line react/no-did-mount-set-state
this.setState({
position: { left, right, top, bottom },
placement,
Expand All @@ -115,6 +153,10 @@ class PopoverMenuWrapper extends Component<PopoverMenuWrapperProps, PopoverMenuW
);
}

/* ------------------------------------------------------------------ */
/* PopoverMenu */
/* ------------------------------------------------------------------ */

type PopoverMenuProps = {
children?: ComponentChildren;
trigger: (contextValue: { pop: () => void }) => void;
Expand All @@ -129,13 +171,21 @@ export const PopoverMenu = ({ children = null, trigger, overlayed }: PopoverMenu
>
{trigger}
{({ dismiss, triggerBounds, overlayBounds }) => (
<PopoverMenuWrapper dismiss={dismiss} triggerBounds={triggerBounds} overlayBounds={overlayBounds}>
<PopoverMenuWrapper
dismiss={dismiss}
triggerBounds={triggerBounds}
overlayBounds={overlayBounds}
>
{children}
</PopoverMenuWrapper>
)}
</PopoverTrigger>
);

/* ------------------------------------------------------------------ */
/* Static bindings */
/* ------------------------------------------------------------------ */

Menu.Group = Group;
Menu.Item = Item;
Menu.Popover = PopoverMenu;
Expand Down
Loading