change(ui): sessions settings moved to preferences (#1380)
* change(ui): sessions settings * dev merge
This commit is contained in:
parent
d3a411f852
commit
ee1a775379
23 changed files with 363 additions and 374 deletions
|
|
@ -15,6 +15,7 @@ import cn from 'classnames';
|
|||
import PreferencesMenu from './PreferencesMenu';
|
||||
import Notifications from './Notifications';
|
||||
import Roles from './Roles';
|
||||
import SessionsListingSettings from 'Components/Client/SessionsListingSettings';
|
||||
|
||||
@withRouter
|
||||
export default class Client extends React.PureComponent {
|
||||
|
|
@ -29,6 +30,7 @@ export default class Client extends React.PureComponent {
|
|||
renderActiveTab = () => (
|
||||
<Switch>
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.PROFILE)} component={ProfileSettings} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.SESSIONS_LISTING)} component={SessionsListingSettings} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.INTEGRATIONS)} component={Integrations} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.MANAGE_USERS)} component={UserView} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.SITES)} component={Sites} />
|
||||
|
|
|
|||
|
|
@ -1,132 +0,0 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import cn from 'classnames';
|
||||
import { SideMenuitem } from 'UI';
|
||||
import stl from './preferencesMenu.module.css';
|
||||
import { CLIENT_TABS, client as clientRoute } from 'App/routes';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
function PreferencesMenu({ account, activeTab, history, isEnterprise }) {
|
||||
const isAdmin = account.admin || account.superAdmin;
|
||||
const setTab = (tab) => {
|
||||
history.push(clientRoute(tab));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn(stl.wrapper, 'h-full overflow-y-auto pb-24')}>
|
||||
<div className={cn(stl.header, 'flex items-end')}>
|
||||
<div className={stl.label}>
|
||||
<span>Preferences</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.PROFILE}
|
||||
title="Account"
|
||||
iconName="user-circle"
|
||||
onClick={() => setTab(CLIENT_TABS.PROFILE)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.INTEGRATIONS}
|
||||
title="Integrations"
|
||||
iconName="puzzle-piece"
|
||||
onClick={() => setTab(CLIENT_TABS.INTEGRATIONS)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
iconName="tags"
|
||||
active={activeTab === CLIENT_TABS.CUSTOM_FIELDS}
|
||||
onClick={() => setTab(CLIENT_TABS.CUSTOM_FIELDS)}
|
||||
title="Metadata"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.WEBHOOKS}
|
||||
title="Webhooks"
|
||||
iconName="anchor"
|
||||
onClick={() => setTab(CLIENT_TABS.WEBHOOKS)}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.SITES}
|
||||
title="Projects"
|
||||
iconName="window-restore"
|
||||
onClick={() => setTab(CLIENT_TABS.SITES)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isEnterprise && isAdmin && (
|
||||
<div className="mb-2 relative">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.MANAGE_ROLES}
|
||||
title="Roles & Access"
|
||||
iconName="diagram-3"
|
||||
onClick={() => setTab(CLIENT_TABS.MANAGE_ROLES)}
|
||||
leading={<AdminOnlyBadge />}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isEnterprise && isAdmin && (
|
||||
<div className="mb-2 relative">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.AUDIT}
|
||||
title="Audit"
|
||||
iconName="list-ul"
|
||||
onClick={() => setTab(CLIENT_TABS.AUDIT)}
|
||||
leading={<AdminOnlyBadge />}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isAdmin && (
|
||||
<div className="mb-2 relative">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.MANAGE_USERS}
|
||||
title="Team"
|
||||
iconName="users"
|
||||
onClick={() => setTab(CLIENT_TABS.MANAGE_USERS)}
|
||||
leading={<AdminOnlyBadge />}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.NOTIFICATIONS}
|
||||
title="Notifications"
|
||||
iconName="bell"
|
||||
onClick={() => setTab(CLIENT_TABS.NOTIFICATIONS)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect((state) => ({
|
||||
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',
|
||||
account: state.getIn(['user', 'account']),
|
||||
}))(withRouter(PreferencesMenu));
|
||||
|
||||
function AdminOnlyBadge() {
|
||||
return (
|
||||
<div
|
||||
className="ml-1 rounded-full bg-gray-light text-xs flex items-center px-2 color-gray-medium"
|
||||
style={{ marginTop: '', height: '20px', whiteSpace: 'nowrap' }}
|
||||
>
|
||||
Admin Only
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import React from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import cn from 'classnames';
|
||||
import { SideMenuitem } from 'UI';
|
||||
import stl from './preferencesMenu.module.css';
|
||||
import { CLIENT_TABS, client as clientRoute } from 'App/routes';
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',
|
||||
account: state.getIn(['user', 'account'])
|
||||
});
|
||||
|
||||
const connector = connect(mapStateToProps);
|
||||
|
||||
type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||
|
||||
type Props = PropsFromRedux & RouteComponentProps & {
|
||||
activeTab: string;
|
||||
};
|
||||
|
||||
function PreferencesMenu({ account, activeTab, history, isEnterprise }: Props) {
|
||||
const isAdmin = account.admin || account.superAdmin;
|
||||
|
||||
const setTab = (tab: string) => {
|
||||
history.push(clientRoute(tab));
|
||||
};
|
||||
|
||||
const AdminOnlyBadge = () => (
|
||||
<div
|
||||
className='ml-1 rounded-full bg-gray-light text-xs flex items-center px-2 color-gray-medium'
|
||||
style={{ marginTop: '', height: '20px', whiteSpace: 'nowrap' }}
|
||||
>
|
||||
Admin Only
|
||||
</div>
|
||||
);
|
||||
|
||||
const menuItems = React.useMemo(() => {
|
||||
return [
|
||||
{ title: 'Account', iconName: 'user-circle', tab: CLIENT_TABS.PROFILE },
|
||||
{ title: 'Sessions Listing', iconName: 'play', tab: CLIENT_TABS.SESSIONS_LISTING },
|
||||
{ title: 'Integrations', iconName: 'puzzle-piece', tab: CLIENT_TABS.INTEGRATIONS },
|
||||
{ title: 'Metadata', iconName: 'tags', tab: CLIENT_TABS.CUSTOM_FIELDS },
|
||||
{ title: 'Webhooks', iconName: 'anchor', tab: CLIENT_TABS.WEBHOOKS },
|
||||
{ title: 'Projects', iconName: 'window-restore', tab: CLIENT_TABS.SITES },
|
||||
{
|
||||
title: 'Roles & Access',
|
||||
iconName: 'diagram-3',
|
||||
tab: CLIENT_TABS.MANAGE_ROLES,
|
||||
isAdminOnly: true,
|
||||
isEnterpriseOnly: true
|
||||
},
|
||||
{
|
||||
title: 'Audit',
|
||||
iconName: 'list-ul',
|
||||
tab: CLIENT_TABS.AUDIT,
|
||||
isAdminOnly: true,
|
||||
isEnterpriseOnly: true
|
||||
},
|
||||
{ title: 'Team', iconName: 'users', tab: CLIENT_TABS.MANAGE_USERS, isAdminOnly: true },
|
||||
{ title: 'Notifications', iconName: 'bell', tab: CLIENT_TABS.NOTIFICATIONS }
|
||||
].reduce((acc, item) => {
|
||||
if (item.isAdminOnly && !isAdmin) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (item.isEnterpriseOnly && !isEnterprise) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return [...acc, item];
|
||||
}, []);
|
||||
}, [isAdmin, isEnterprise]);
|
||||
|
||||
// @ts-ignore
|
||||
return (
|
||||
<div className={cn(stl.wrapper, 'h-full overflow-y-auto pb-24')}>
|
||||
<div className={cn(stl.header, 'flex items-end')}>
|
||||
<div className={stl.label}>
|
||||
<span>Preferences</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{menuItems.map((menuItem) => (
|
||||
<div className='mb-2' key={menuItem.title}>
|
||||
<SideMenuitem
|
||||
active={activeTab === menuItem.tab}
|
||||
title={menuItem.title}
|
||||
// @ts-ignore
|
||||
iconName={menuItem.iconName}
|
||||
onClick={() => setTab(menuItem.tab)}
|
||||
leading={menuItem.isAdminOnly ? <AdminOnlyBadge /> : undefined}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connector(withRouter(PreferencesMenu));
|
||||
55
frontend/app/components/Client/SessionsListingSettings.tsx
Normal file
55
frontend/app/components/Client/SessionsListingSettings.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { PageTitle, Divider } from 'UI';
|
||||
import ListingVisibility from 'Shared/SessionSettings/components/ListingVisibility';
|
||||
import DefaultPlaying from 'Shared/SessionSettings/components/DefaultPlaying';
|
||||
import DefaultTimezone from 'Shared/SessionSettings/components/DefaultTimezone';
|
||||
import withPageTitle from 'HOCs/withPageTitle';
|
||||
import MouseTrailSettings from 'Shared/SessionSettings/components/MouseTrailSettings';
|
||||
|
||||
|
||||
type Props = {}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',
|
||||
account: state.getIn(['user', 'account'])
|
||||
});
|
||||
|
||||
const connector = connect(mapStateToProps);
|
||||
|
||||
function SessionsListingSettings(props: Props) {
|
||||
return (
|
||||
<div className='p-5'>
|
||||
<PageTitle title={<div>Sessions Listings</div>} />
|
||||
|
||||
<div className='flex flex-col mt-4'>
|
||||
<div className='max-w-lg'>
|
||||
<ListingVisibility />
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
|
||||
<div>
|
||||
<DefaultPlaying />
|
||||
</div>
|
||||
<Divider />
|
||||
|
||||
|
||||
<div>
|
||||
<DefaultTimezone />
|
||||
</div>
|
||||
<Divider />
|
||||
|
||||
<div>
|
||||
<MouseTrailSettings />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connector(
|
||||
withPageTitle('Sessions Listings - OpenReplay Preferences')(SessionsListingSettings)
|
||||
);
|
||||
|
|
@ -1,32 +1,31 @@
|
|||
import React from 'react';
|
||||
import { Toggler } from 'UI';
|
||||
import { Switch } from 'UI';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { useObserver } from 'mobx-react-lite';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
function DefaultPlaying(props) {
|
||||
const { settingsStore } = useStore();
|
||||
const sessionSettings = useObserver(() => settingsStore.sessionSettings)
|
||||
function DefaultPlaying() {
|
||||
const { settingsStore } = useStore();
|
||||
const sessionSettings = useObserver(() => settingsStore.sessionSettings);
|
||||
|
||||
const toggleSkipToIssue = () => {
|
||||
sessionSettings.updateKey('skipToIssue', !sessionSettings.skipToIssue)
|
||||
toast.success("Default playing option saved successfully");
|
||||
}
|
||||
const toggleSkipToIssue = () => {
|
||||
sessionSettings.updateKey('skipToIssue', !sessionSettings.skipToIssue);
|
||||
toast.success('Default playing option saved successfully');
|
||||
};
|
||||
|
||||
|
||||
return useObserver(() => (
|
||||
<>
|
||||
<h3 className="text-lg">Default Playing Option</h3>
|
||||
<div className="my-1">Always start playing the session from the first issue</div>
|
||||
<div className="mt-2">
|
||||
<Toggler
|
||||
checked={sessionSettings.skipToIssue}
|
||||
name="test"
|
||||
onChange={toggleSkipToIssue}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
));
|
||||
return useObserver(() => (
|
||||
<>
|
||||
<h3 className='text-lg'>Default Playing Option</h3>
|
||||
<div className='my-1'>Always start playing the session from the first issue</div>
|
||||
<div className='mt-2'>
|
||||
<Switch
|
||||
checked={sessionSettings.skipToIssue}
|
||||
onChange={toggleSkipToIssue}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
));
|
||||
}
|
||||
|
||||
export default DefaultPlaying;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import React from 'react';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Switch } from 'UI';
|
||||
|
||||
function MouseTrailSettings() {
|
||||
const { settingsStore } = useStore();
|
||||
const sessionSettings = settingsStore.sessionSettings;
|
||||
const mouseTrail = sessionSettings.mouseTrail;
|
||||
|
||||
const updateSettings = (checked: boolean) => {
|
||||
settingsStore.sessionSettings.updateKey('mouseTrail', !mouseTrail);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className='text-lg'>Mouse Trail</h3>
|
||||
<div className='my-1'>See mouse trail to easily spot user activity.</div>
|
||||
<div className='mt-2'>
|
||||
<Switch onChange={updateSettings} checked={mouseTrail} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(MouseTrailSettings);
|
||||
13
frontend/app/components/ui/Divider.tsx
Normal file
13
frontend/app/components/ui/Divider.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { Divider as AntdDivider, DividerProps as AntdDividerProps } from 'antd';
|
||||
|
||||
|
||||
interface DividerProps extends AntdDividerProps {
|
||||
customProp?: boolean;
|
||||
}
|
||||
|
||||
const Divider: React.FC<DividerProps> = ({ customProp, ...restProps }) => {
|
||||
return <AntdDivider {...restProps} />;
|
||||
};
|
||||
|
||||
export default Divider;
|
||||
81
frontend/app/components/ui/SideMenuItem/SideMenuItem.tsx
Normal file
81
frontend/app/components/ui/SideMenuItem/SideMenuItem.tsx
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import React from 'react';
|
||||
import { Icon, Tooltip } from 'UI';
|
||||
import cn from 'classnames';
|
||||
import stl from './sideMenuItem.module.css';
|
||||
import { IconNames } from 'UI/SVG';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
iconName?: IconNames;
|
||||
iconBg?: boolean;
|
||||
iconColor?: string;
|
||||
iconSize?: number;
|
||||
className?: string;
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
tooltipTitle?: string;
|
||||
onClick?: () => void;
|
||||
deleteHandler?: () => void;
|
||||
leading?: React.ReactNode;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
function SideMenuItem({
|
||||
iconBg = false,
|
||||
iconColor = 'gray-dark',
|
||||
iconSize = 18,
|
||||
className = '',
|
||||
iconName,
|
||||
title,
|
||||
active = false,
|
||||
disabled = false,
|
||||
tooltipTitle = '',
|
||||
onClick,
|
||||
deleteHandler,
|
||||
leading = null,
|
||||
...props
|
||||
}: Props) {
|
||||
const handleClick = () => {
|
||||
if (disabled) return;
|
||||
if (onClick) onClick();
|
||||
};
|
||||
|
||||
const handleDeleteClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
if (deleteHandler) deleteHandler();
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip disabled={!disabled} title={tooltipTitle} placement='top'>
|
||||
<div
|
||||
className={cn(
|
||||
className,
|
||||
stl.menuItem,
|
||||
'flex items-center py-2 justify-between shrink-0',
|
||||
{ [stl.active]: active, [stl.disabled]: disabled }
|
||||
)}
|
||||
onClick={handleClick}
|
||||
{...props}
|
||||
>
|
||||
<div className={cn('flex items-center w-full', stl.iconLabel)}>
|
||||
{iconName && (
|
||||
<div className='flex items-center justify-center w-8 h-8 mr-2'>
|
||||
{iconBg &&
|
||||
<div className={cn('w-8 h-8 rounded-full relative opacity-20', iconBg)} style={{ opacity: 0.2 }} />}
|
||||
<Icon name={iconName} size={iconSize} color={active ? 'teal' : iconColor} className='absolute' />
|
||||
</div>
|
||||
)}
|
||||
<span className={cn(stl.title, 'capitalize-first')}>{title}</span>
|
||||
</div>
|
||||
{leading && leading}
|
||||
{deleteHandler && (
|
||||
<div onClick={handleDeleteClick} className={stl.actions}>
|
||||
<Icon name='trash' size={14} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
export default SideMenuItem;
|
||||
1
frontend/app/components/ui/SideMenuItem/index.js
Normal file
1
frontend/app/components/ui/SideMenuItem/index.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './SideMenuItem';
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Icon, Tooltip } from 'UI';
|
||||
import cn from 'classnames';
|
||||
import stl from './sideMenuItem.module.css';
|
||||
import { IconNames } from 'UI/SVG';
|
||||
|
||||
function SideMenuitem({
|
||||
iconBg = false,
|
||||
iconColor = "gray-dark",
|
||||
iconSize = 18,
|
||||
className = '',
|
||||
iconName,
|
||||
title,
|
||||
active = false,
|
||||
disabled = false,
|
||||
tooltipTitle = '',
|
||||
onClick,
|
||||
deleteHandler,
|
||||
leading = null,
|
||||
...props
|
||||
}: {
|
||||
title: string;
|
||||
iconName?: IconNames;
|
||||
iconBg?: boolean;
|
||||
iconColor?: string;
|
||||
iconSize?: number;
|
||||
className?: string;
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
tooltipTitle?: string;
|
||||
onClick?: () => void;
|
||||
deleteHandler?: () => void;
|
||||
leading?: React.ReactNode;
|
||||
id?: string;
|
||||
}) {
|
||||
return (
|
||||
<Tooltip
|
||||
disabled={ !disabled }
|
||||
title={ tooltipTitle }
|
||||
placement="top"
|
||||
>
|
||||
<div
|
||||
className={ cn(
|
||||
className,
|
||||
stl.menuItem,
|
||||
"flex items-center py-2 justify-between shrink-0",
|
||||
{ [stl.active] : active }
|
||||
)}
|
||||
onClick={disabled ? null : onClick}
|
||||
{...props}
|
||||
>
|
||||
<div className={ cn('flex items-center w-full', { [stl.disabled] : disabled })}>
|
||||
<div className={cn("flex items-center", stl.iconLabel)}>
|
||||
{ iconName && (
|
||||
<div className="flex items-center justify-center w-8 h-8 mr-2">
|
||||
<div className={cn({ "w-8 h-8 rounded-full relative opacity-20" : iconBg }, iconBg)} style={{ opacity: '0.2'}} />
|
||||
<Icon name={ iconName } size={ iconSize } color={active ? 'teal' : iconColor} className="absolute" />
|
||||
</div>
|
||||
)}
|
||||
<span className={cn(stl.title, 'capitalize-first')}>{ title }</span>
|
||||
</div>
|
||||
{ leading && leading }
|
||||
</div>
|
||||
{deleteHandler &&
|
||||
<div onClick={deleteHandler} className={stl.actions}><Icon name="trash" size="14" /></div>
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export default SideMenuitem
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from './SideMenuitem';
|
||||
13
frontend/app/components/ui/Switch.tsx
Normal file
13
frontend/app/components/ui/Switch.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { Switch as AntdSwitch, SwitchProps as AntdSwitchProps } from 'antd';
|
||||
|
||||
interface SwitchProps extends AntdSwitchProps {
|
||||
customProp?: boolean;
|
||||
// Add any additional custom props here
|
||||
}
|
||||
|
||||
const Switch: React.FC<SwitchProps> = ({ customProp, ...restProps }) => {
|
||||
return <AntdSwitch {...restProps} />;
|
||||
};
|
||||
|
||||
export default Switch;
|
||||
|
|
@ -31,7 +31,7 @@ export { default as CountryFlag } from './CountryFlag';
|
|||
export { default as RandomElement } from './RandomElement';
|
||||
export { default as SplitButton } from './SplitButton';
|
||||
export { default as confirm } from './Confirmation';
|
||||
export { default as SideMenuitem } from './SideMenuitem';
|
||||
export { default as SideMenuitem } from './SideMenuItem';
|
||||
export { default as Avatar } from './Avatar';
|
||||
export { default as TimezoneDropdown } from './TimezoneDropdown';
|
||||
export { default as ErrorItem } from './ErrorItem';
|
||||
|
|
@ -57,3 +57,5 @@ export { default as Form } from './Form';
|
|||
export { default as Modal } from './Modal';
|
||||
export { default as Message } from './Message';
|
||||
export { default as Popover } from './Popover';
|
||||
export { default as Switch } from './Switch';
|
||||
export { default as Divider } from './Divider';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import SideMenuitem from './SideMenuitem';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
import { Avatar, ErrorItem, ErrorFrame, ErrorDetails, TimelinePointer } from 'UI';
|
||||
import Error from 'Types/session/error';
|
||||
import ErrorStackModel from 'Types/session/errorStack';
|
||||
|
|
@ -65,10 +65,10 @@ const errors = [
|
|||
|
||||
storiesOf('UI Components', module)
|
||||
.add('SideMenuItem', () => (
|
||||
<SideMenuitem title="Menu Label" />
|
||||
<SideMenuItem title="Menu Label" />
|
||||
))
|
||||
.add('SideMenuItem active', () => (
|
||||
<SideMenuitem title="Menu Label" active />
|
||||
<SideMenuItem title="Menu Label" active />
|
||||
))
|
||||
.add('Avatar', () => (
|
||||
<Avatar />
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@ export const SESSION_FILTER = "__$session-filter$__"
|
|||
export const GLOBAL_DESTINATION_PATH = "__$global-destinationPath$__"
|
||||
export const GLOBAL_HAS_NO_RECORDINGS = "__$global-hasNoRecordings$__"
|
||||
export const SITE_ID_STORAGE_KEY = "__$user-siteId$__"
|
||||
export const GETTING_STARTED = "__$user-gettingStarted$__"
|
||||
export const GETTING_STARTED = "__$user-gettingStarted$__"
|
||||
export const MOUSE_TRAIL = "__$session-mouseTrail$__"
|
||||
|
|
@ -9,6 +9,7 @@ import { StoreProvider, RootStore } from './mstore';
|
|||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
window.getCommitHash = () => console.log(window.env.COMMIT_HASH)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { makeAutoObservable, runInAction } from 'mobx';
|
||||
import moment from 'moment';
|
||||
import { SKIP_TO_ISSUE, TIMEZONE, DURATION_FILTER } from 'App/constants/storageKeys';
|
||||
import { SKIP_TO_ISSUE, TIMEZONE, DURATION_FILTER, MOUSE_TRAIL } from 'App/constants/storageKeys';
|
||||
|
||||
export type Timezone = {
|
||||
label: string;
|
||||
|
|
@ -69,6 +69,8 @@ export default class SessionSettings {
|
|||
durationFilter: any = JSON.parse(localStorage.getItem(DURATION_FILTER) || JSON.stringify(defaultDurationFilter));
|
||||
captureRate: string = '0';
|
||||
captureAll: boolean = false;
|
||||
mouseTrail: boolean = localStorage.getItem(MOUSE_TRAIL) === 'true';
|
||||
|
||||
|
||||
constructor() {
|
||||
// compatibility fix for old timezone storage
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ export const forgotPassword = () => '/reset-password';
|
|||
export const CLIENT_TABS = {
|
||||
INTEGRATIONS: 'integrations',
|
||||
PROFILE: 'account',
|
||||
SESSIONS_LISTING: 'sessions-listing',
|
||||
MANAGE_USERS: 'team',
|
||||
MANAGE_ROLES: 'roles',
|
||||
SITES: 'projects',
|
||||
|
|
|
|||
|
|
@ -22,3 +22,7 @@ input.no-focus:focus {
|
|||
@apply inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.border-b {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
|
|
|||
1
frontend/app/styles/import.css
vendored
1
frontend/app/styles/import.css
vendored
|
|
@ -6,6 +6,7 @@
|
|||
@import 'react-tippy/dist/tippy.css';
|
||||
@import 'react-daterange-picker.css';
|
||||
@import 'rc-time-picker.css';
|
||||
@import 'antd/dist/reset.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@
|
|||
@import "./toastify.css";
|
||||
@import "./flags.css";
|
||||
@import "./general.css";
|
||||
@import "./recharts.css";
|
||||
@import "./recharts.css";
|
||||
|
|
@ -1,155 +1,47 @@
|
|||
const colors = require('./app/theme/colors');
|
||||
const defaultColors = require('tailwindcss/colors')
|
||||
const defaultColors = require('tailwindcss/colors');
|
||||
|
||||
console.log(defaultColors);
|
||||
module.exports = {
|
||||
// important: true,
|
||||
content: [
|
||||
'./app/**/*.tsx',
|
||||
'./app/**/*.js',
|
||||
],
|
||||
// corePlugins: [
|
||||
// 'preflight',
|
||||
// 'container',
|
||||
// // 'accessibility',
|
||||
// // 'alignContent',
|
||||
// 'alignItems',
|
||||
// 'alignSelf',
|
||||
// //'appearance',
|
||||
// // 'backgroundAttachment',
|
||||
// 'backgroundColor',
|
||||
// 'backgroundOpacity',
|
||||
// // 'backgroundPosition',
|
||||
// // 'backgroundRepeat',
|
||||
// // 'backgroundSize',
|
||||
// // 'borderCollapse',
|
||||
// 'borderColor',
|
||||
// 'borderOpacity',
|
||||
// 'borderRadius',
|
||||
// // 'borderStyle',
|
||||
// 'borderWidth',
|
||||
// // 'boxSizing',
|
||||
// // 'boxShadow',
|
||||
// // 'clear',
|
||||
// 'cursor',
|
||||
// 'display',
|
||||
// // 'divideColor',
|
||||
// // 'divideWidth',
|
||||
// // 'fill',
|
||||
// 'flex',
|
||||
// 'flexDirection',
|
||||
// // 'flexGrow',
|
||||
// 'flexShrink',
|
||||
// 'flexWrap',
|
||||
// // 'float',
|
||||
// 'gap',
|
||||
// 'gridAutoFlow',
|
||||
// 'gridColumn',
|
||||
// 'gridColumnStart',
|
||||
// 'gridColumnEnd',
|
||||
// 'gridRow',
|
||||
// 'gridRowStart',
|
||||
// 'gridRowEnd',
|
||||
// 'gridTemplateColumns',
|
||||
// 'gridTemplateRows',
|
||||
// 'fontFamily',
|
||||
// 'fontSize',
|
||||
// //'fontSmoothing',
|
||||
// 'fontStyle',
|
||||
// 'fontWeight',
|
||||
// 'height',
|
||||
// 'inset',
|
||||
// 'justifyContent',
|
||||
// 'justifySelf',
|
||||
// 'letterSpacing',
|
||||
// 'lineHeight',
|
||||
// // 'listStylePosition',
|
||||
// // 'listStyleType',
|
||||
// 'margin',
|
||||
// // 'maxHeight',
|
||||
// // 'maxWidth',
|
||||
// // 'minHeight',
|
||||
// // 'minWidth',
|
||||
// // 'objectFit',
|
||||
// // 'objectPosition',
|
||||
// 'opacity',
|
||||
// // 'order',
|
||||
// 'outline',
|
||||
// 'overflow',
|
||||
// 'padding',
|
||||
// // 'placeholderColor',
|
||||
// // 'placeholderOpacity',
|
||||
// 'pointerEvents',
|
||||
// 'position',
|
||||
// // 'resize',
|
||||
// // 'rotate',
|
||||
// // 'scale',
|
||||
// // 'skew',
|
||||
// // 'space',
|
||||
// // 'stroke',
|
||||
// // 'strokeWidth',
|
||||
// // 'tableLayout',
|
||||
// 'textAlign',
|
||||
// // 'textColor',
|
||||
// // 'textOpacity',
|
||||
// 'textDecoration',
|
||||
// 'textTransform',
|
||||
// // 'transform',
|
||||
// // 'transitionDuration',
|
||||
// // 'transitionProperty',
|
||||
// // 'transitionTimingFunction',
|
||||
// // 'translate',
|
||||
// 'userSelect',
|
||||
// // 'verticalAlign',
|
||||
// 'visibility',
|
||||
// 'whitespace',
|
||||
// 'width',
|
||||
// 'wordBreak',
|
||||
// 'zIndex'
|
||||
// ],
|
||||
theme: {
|
||||
colors: {
|
||||
...defaultColors,
|
||||
...colors,
|
||||
},
|
||||
// borderColor: {
|
||||
// default: '#DDDDDD',
|
||||
// "gray-light-shade": colors["gray-light-shade"],
|
||||
// "blue": colors["active-blue-border"],
|
||||
// },
|
||||
extend: {
|
||||
boxShadow: {
|
||||
'border-blue': `0 0 0 1px ${colors['active-blue-border']}`,
|
||||
'border-main': `0 0 0 1px ${colors['main']}`,
|
||||
'border-gray': '0 0 0 1px #999',
|
||||
},
|
||||
keyframes: {
|
||||
'fade-in': {
|
||||
'0%': {
|
||||
opacity: '0',
|
||||
// transform: 'translateY(-10px)'
|
||||
},
|
||||
'100%': {
|
||||
opacity: '1',
|
||||
// transform: 'translateY(0)'
|
||||
},
|
||||
content: [
|
||||
'./app/**/*.tsx',
|
||||
'./app/**/*.js'
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
...defaultColors,
|
||||
...colors
|
||||
},
|
||||
extend: {
|
||||
keyframes: {
|
||||
'fade-in': {
|
||||
'0%': {
|
||||
opacity: '0'
|
||||
// transform: 'translateY(-10px)'
|
||||
},
|
||||
'100%': {
|
||||
opacity: '1'
|
||||
// transform: 'translateY(0)'
|
||||
}
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
'fade-in': 'fade-in 0.2s ease-out'
|
||||
'fade-in': 'fade-in 0.2s ease-out'
|
||||
},
|
||||
colors: {
|
||||
'disabled-text': 'rgba(0,0,0, 0.38)',
|
||||
'disabled-text': 'rgba(0,0,0, 0.38)'
|
||||
},
|
||||
boxShadow: {
|
||||
'border-blue': `0 0 0 1px ${colors['active-blue-border']}`,
|
||||
'border-main': `0 0 0 1px ${colors['main']}`,
|
||||
'border-gray': '0 0 0 1px #999',
|
||||
}
|
||||
},
|
||||
'border-gray': '0 0 0 1px #999'
|
||||
},
|
||||
}
|
||||
},
|
||||
variants: {
|
||||
visibility: ['responsive', 'hover', 'focus', 'group-hover']
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
visibility: ['responsive', 'hover', 'focus', 'group-hover']
|
||||
},
|
||||
plugins: [],
|
||||
corePlugins: {
|
||||
preflight: false
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue