various ui improvements

This commit is contained in:
Sudheer Salavadi 2024-07-02 15:04:05 +05:30
parent b38eda8821
commit b75e008471
17 changed files with 105 additions and 85 deletions

View file

@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import { Popover, Icon } from 'UI'; import { Popover, Icon } from 'UI';
import IssuesModal from './IssuesModal'; import IssuesModal from './IssuesModal';
import { fetchProjects, fetchMeta } from 'Duck/assignments'; import { fetchProjects, fetchMeta } from 'Duck/assignments';
import { Popover as AntPopover, Button } from 'antd'; import { Tooltip, Button } from 'antd';
@connect( @connect(
(state) => ({ (state) => ({
@ -67,11 +67,11 @@ class Issues extends React.Component {
)} )}
> >
<div> <div>
<AntPopover content={'Create Issue'}> <Tooltip title={'Create Issue'} placement='bottom'>
<Button size={'small'} className={'flex items-center justify-center'}> <Button size={'small'} className={'flex items-center justify-center'}>
<Icon name={`integrations/${provider === 'jira' ? 'jira' : 'github'}`} /> <Icon name={`integrations/${provider === 'jira' ? 'jira' : 'github'}`} />
</Button> </Button>
</AntPopover> </Tooltip>
</div> </div>
</Popover> </Popover>
); );

View file

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { Icon } from 'UI'; import { Icon } from 'UI';
import { Popover, Button } from 'antd'; import {Keyboard} from 'lucide-react'
import { Button, Tooltip } from 'antd';
import { useModal } from "../../../../Modal"; import { useModal } from "../../../../Modal";
const Key = ({ label }: { label: string }) => <div style={{ minWidth: 52 }} className="whitespace-nowrap font-bold bg-gray-lightest rounded shadow px-2 py-1 text-figmaColors-text-primary text-center">{label}</div>; const Key = ({ label }: { label: string }) => <div style={{ minWidth: 52 }} className="whitespace-nowrap font-bold bg-gray-lightest rounded shadow px-2 py-1 text-figmaColors-text-primary text-center">{label}</div>;
@ -35,7 +36,7 @@ function ShortcutGrid() {
return ( return (
<div className={'p-4 overflow-y-auto h-screen'}> <div className={'p-4 overflow-y-auto h-screen'}>
<div className={'mb-4 font-semibold text-xl'}>Keyboard Shortcuts</div> <div className={'mb-4 font-semibold text-xl'}>Keyboard Shortcuts</div>
<div className=" grid grid-cols-2 grid-flow-row-dense auto-cols-max gap-4 justify-items-start"> <div className=" grid grid-cols-1 grid-flow-row-dense auto-cols-max gap-4 justify-items-start">
<Cell shortcut="⇧ + C" text="Launch Console" /> <Cell shortcut="⇧ + C" text="Launch Console" />
<Cell shortcut="⇧ + N" text="Launch Network" /> <Cell shortcut="⇧ + N" text="Launch Network" />
<Cell shortcut="⇧ + P" text="Launch Performance" /> <Cell shortcut="⇧ + P" text="Launch Performance" />
@ -61,6 +62,7 @@ function ShortcutGrid() {
function KeyboardHelp() { function KeyboardHelp() {
const { showModal } = useModal(); const { showModal } = useModal();
return ( return (
<Tooltip placement='bottom' title='Keyboard Shortcuts'>
<Button <Button
size={'small'} size={'small'}
className={'flex items-center justify-center'} className={'flex items-center justify-center'}
@ -68,8 +70,9 @@ function KeyboardHelp() {
showModal(<ShortcutGrid />, { right: true, width: 420 }) showModal(<ShortcutGrid />, { right: true, width: 420 })
}} }}
> >
<Icon name={'keyboard'} size={21} color={'black'} /> <Keyboard size={18}/>
</Button> </Button>
</Tooltip>
); );
} }

View file

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import { Icon } from 'UI'; import { Icon } from 'UI';
import { Button, Tag } from 'antd';
import { PlayCircleOutlined } from '@ant-design/icons';
import { tagProps, Note } from 'App/services/NotesService'; import { tagProps, Note } from 'App/services/NotesService';
import { formatTimeOrDate } from 'App/date'; import { formatTimeOrDate } from 'App/date';
import { useStore } from 'App/mstore'; import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { TeamBadge } from 'Shared/SessionsTabOverview/components/Notes'; import { TeamBadge } from 'Shared/SessionsTabOverview/components/Notes';
import { Tag } from 'antd'
interface Props { interface Props {
note?: Note; note?: Note;
@ -21,7 +22,7 @@ function ReadNote(props: Props) {
return ( return (
<div style={{ position: 'absolute', top: '45%', left: 'calc(50% - 200px)' }}> <div style={{ position: 'absolute', top: '45%', left: 'calc(50% - 200px)' }}>
<div <div
className="flex items-start flex-col p-4 border gap-2 rounded" className="flex items-start flex-col p-4 border gap-2 rounded-lg"
style={{ background: '#FFFEF5', width: 400 }} style={{ background: '#FFFEF5', width: 400 }}
> >
<div className="flex items-start font-semibold w-full text-xl"> <div className="flex items-start font-semibold w-full text-xl">
@ -50,8 +51,8 @@ function ReadNote(props: Props) {
className="flex items-center justify-center" className="flex items-center justify-center"
> >
<div <div
className="flex items-start !text-lg flex-col p-4 border gap-2 rounded" className="flex items-start !text-lg flex-col p-4 border gap-2 rounded-lg bg-amber-50"
style={{ background: '#FFFEF5', width: 500 }} style={{ width: 500 }}
> >
<div className="flex items-center w-full"> <div className="flex items-center w-full">
<div className="p-2 bg-gray-light rounded-full"> <div className="p-2 bg-gray-light rounded-full">
@ -71,23 +72,32 @@ function ReadNote(props: Props) {
{props.note.message} {props.note.message}
</div> </div>
<div className="w-full"> <div className="w-full">
<div className="flex items-center gap-2 flex-wrap w-full"> <div className="flex items-center justify-between w-full">
<div className='flex gap-1 items-center'>
{props.note.tag ? ( {props.note.tag ? (
<Tag <Tag
color={tagProps[props.note.tag]} color={tagProps[props.note.tag]}
className='border-0 rounded-lg'
> >
{props.note.tag} {props.note.tag}
</Tag> </Tag>
) : null} ) : null}
<Tag bordered={false} >
{!props.note.isPublic ? null : <TeamBadge />} {!props.note.isPublic ? null : <TeamBadge />}
</Tag>
<div
onClick={props.onClose}
className="ml-auto rounded py-2 px-4 flex items-center text-blue gap-2 cursor-pointer hover:bg-active-blue"
>
<Icon size={20} name="play-fill" color="main" />
<span>Play Session</span>
</div> </div>
<Button
onClick={props.onClose}
icon={<PlayCircleOutlined />}
type='default'
>
Play Session
</Button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,7 +1,7 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useStore } from 'App/mstore'; import { useStore } from 'App/mstore';
import KeyboardHelp from 'Components/Session_/Player/Controls/components/KeyboardHelp'; import KeyboardHelp from 'Components/Session_/Player/Controls/components/KeyboardHelp';
import { Icon, Tooltip } from 'UI'; import { Icon } from 'UI';
import QueueControls from './QueueControls'; import QueueControls from './QueueControls';
import Bookmark from 'Shared/Bookmark'; import Bookmark from 'Shared/Bookmark';
import SharePopup from '../shared/SharePopup/SharePopup'; import SharePopup from '../shared/SharePopup/SharePopup';
@ -13,7 +13,7 @@ import { connect } from 'react-redux';
import SessionTabs from 'Components/Session/Player/SharedComponents/SessionTabs'; import SessionTabs from 'Components/Session/Player/SharedComponents/SessionTabs';
import { IFRAME } from 'App/constants/storageKeys'; import { IFRAME } from 'App/constants/storageKeys';
import cn from 'classnames'; import cn from 'classnames';
import { Switch, Button as AntButton, Popover } from 'antd'; import { Switch, Button as AntButton, Popover, Tooltip } from 'antd';
import { ShareAltOutlined } from '@ant-design/icons'; import { ShareAltOutlined } from '@ant-design/icons';
const localhostWarn = (project) => project + '_localhost_warn'; const localhostWarn = (project) => project + '_localhost_warn';
@ -96,6 +96,7 @@ function SubHeader(props) {
)} )}
style={{ width: 'max-content' }} style={{ width: 'max-content' }}
> >
<KeyboardHelp /> <KeyboardHelp />
<Bookmark sessionId={props.sessionId} /> <Bookmark sessionId={props.sessionId} />
<NotePopup /> <NotePopup />
@ -104,11 +105,11 @@ function SubHeader(props) {
showCopyLink={true} showCopyLink={true}
trigger={ trigger={
<div className="relative"> <div className="relative">
<Popover content={'Share Session'}> <Tooltip title='Share Session' placement='bottom'>
<AntButton size={'small'} className="flex items-center justify-center"> <AntButton size={'small'} className="flex items-center justify-center">
<ShareAltOutlined /> <ShareAltOutlined />
</AntButton> </AntButton>
</Popover> </Tooltip>
</div> </div>
} }
/> />

View file

@ -2,7 +2,7 @@ import CreateNote from 'Components/Session_/Player/Controls/components/CreateNot
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { PlayerContext } from 'App/components/Session/playerContext'; import { PlayerContext } from 'App/components/Session/playerContext';
import { Button, Popover } from 'antd'; import { Button, Tooltip } from 'antd';
import { MessageOutlined } from '@ant-design/icons'; import { MessageOutlined } from '@ant-design/icons';
import { useModal } from 'App/components/Modal'; import { useModal } from 'App/components/Modal';
@ -22,7 +22,7 @@ function NotePopup({ tooltipActive }: { tooltipActive: boolean }) {
}; };
return ( return (
<Popover content={'Add Note'}> <Tooltip title={'Add Note'} placement='bottom'>
<Button <Button
size={'small'} size={'small'}
className={'flex items-center justify-center'} className={'flex items-center justify-center'}
@ -31,7 +31,7 @@ function NotePopup({ tooltipActive }: { tooltipActive: boolean }) {
> >
<MessageOutlined /> <MessageOutlined />
</Button> </Button>
</Popover> </Tooltip>
); );
} }

View file

@ -1,4 +1,4 @@
import { Button, Popover } from 'antd'; import { Button, Tooltip } from 'antd';
import { BookmarkCheck, Bookmark as BookmarkIcn, Vault } from 'lucide-react'; import { BookmarkCheck, Bookmark as BookmarkIcn, Vault } from 'lucide-react';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
@ -13,6 +13,7 @@ interface Props {
isEnterprise: boolean; isEnterprise: boolean;
noMargin?: boolean; noMargin?: boolean;
} }
function Bookmark(props: Props) { function Bookmark(props: Props) {
const { sessionId, favorite, isEnterprise, noMargin } = props; const { sessionId, favorite, isEnterprise, noMargin } = props;
const [isFavorite, setIsFavorite] = useState(favorite); const [isFavorite, setIsFavorite] = useState(favorite);
@ -48,7 +49,7 @@ function Bookmark(props: Props) {
return ( return (
<div onClick={toggleFavorite} className="w-full"> <div onClick={toggleFavorite} className="w-full">
<Popover content={isFavorite ? TOOLTIP_TEXT_REMOVE : TOOLTIP_TEXT_ADD}> <Tooltip title={isFavorite ? TOOLTIP_TEXT_REMOVE : TOOLTIP_TEXT_ADD} placement='bottom'>
<Button <Button
type={isFavorite ? 'primary' : undefined} type={isFavorite ? 'primary' : undefined}
ghost={isFavorite} ghost={isFavorite}
@ -57,7 +58,7 @@ function Bookmark(props: Props) {
> >
{icon} {icon}
</Button> </Button>
</Popover> </Tooltip>
</div> </div>
); );
} }

View file

@ -41,7 +41,7 @@ function LiveSessionList(props: Props) {
var timeoutId: any; var timeoutId: any;
const { filters } = filter; const { filters } = filter;
const hasUserFilter = filters.map((i: any) => i.key).includes(KEYS.USERID); const hasUserFilter = filters.map((i: any) => i.key).includes(KEYS.USERID);
const sortOptions = [{ label: 'Newest', value: 'timestamp' }].concat( const sortOptions = [{ label: 'Freshness', value: 'timestamp' }].concat(
metaList metaList
.map((i: any) => ({ .map((i: any) => ({
label: capitalize(i), label: capitalize(i),
@ -105,6 +105,7 @@ function LiveSessionList(props: Props) {
onChange={onSortChange} onChange={onSortChange}
value={sortOptions.find((i: any) => i.value === filter.sort) || sortOptions[0]} value={sortOptions.find((i: any) => i.value === filter.sort) || sortOptions[0]}
/> />
<div className="mx-2" /> <div className="mx-2" />
<SortOrderButton <SortOrderButton
onChange={(state: any) => props.applyFilter({ order: state })} onChange={(state: any) => props.applyFilter({ order: state })}
@ -204,3 +205,4 @@ export default withPermissions(['ASSIST_LIVE'])(
} }
)(LiveSessionList) )(LiveSessionList)
); );

View file

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { CircularLoader, Icon, Tooltip, Button } from 'UI'; import {Button, Tooltip} from 'antd';
import { ListRestart } from 'lucide-react';
import cn from 'classnames'; import cn from 'classnames';
interface Props { interface Props {
@ -12,8 +13,9 @@ interface Props {
export default function ReloadButton(props: Props) { export default function ReloadButton(props: Props) {
const { loading, onClick, iconSize = '20', iconName = 'arrow-repeat', className = '' } = props; const { loading, onClick, iconSize = '20', iconName = 'arrow-repeat', className = '' } = props;
return ( return (
<Tooltip title="Refresh"> <Tooltip title="Refresh" placement='right'>
<Button icon={iconName} variant="text" onClick={onClick}> <Button type="default" onClick={onClick}>
<ListRestart size={18} />
</Button> </Button>
</Tooltip> </Tooltip>
); );

View file

@ -35,35 +35,43 @@ function NoteItem(props: Props) {
}); });
}; };
const menuItems = [ const menuItems = [
{ icon: 'link-45deg', text: 'Copy Note URL', onClick: onCopy }, { icon: 'link-45deg', text: 'Copy Link', onClick: onCopy },
{ icon: 'trash', text: 'Delete', onClick: onDelete }, { icon: 'trash', text: 'Delete', onClick: onDelete },
]; ];
const safeStrMessage = const safeStrMessage =
props.note.message.length > 150 ? props.note.message.slice(0, 150) + '...' : props.note.message; props.note.message.length > 150 ? props.note.message.slice(0, 150) + '...' : props.note.message;
return ( return (
<div className="flex items-center p-2 border-b"> <div className="flex items-center px-2 border-b">
<Link <Link
style={{ width: '90%' }} style={{ width: '90%' }}
to={ to={
session(props.note.sessionId) + session(props.note.sessionId) +
(props.note.timestamp > 0 (props.note.timestamp > 0
? `?jumpto=${props.note.timestamp}&note=${props.note.noteId}` ? `?jumpto=${props.note.timestamp}&note=${props.note.noteId}`
: `?note=${props.note.noteId}`) : `?note=${props.note.noteId}`)
} }
> >
<div className="flex flex-col gap-1 p-2 rounded cursor-pointer note-hover"> <div className="flex flex-col p-2 rounded cursor-pointer">
<div className="py-1 capitalize-first text-lg">{safeStrMessage}</div> <div className="flex py-1 text-base">
<div className="flex items-center">
{props.note.tag ? ( {props.note.tag ? (
<Tag <Tag
color={tagProps[props.note.tag]} color={tagProps[props.note.tag]}
className='border-0 rounded-lg hover:inherit gap-2 w-14 text-center'
> >
{props.note.tag} {props.note.tag}
</Tag> </Tag>
) : null} ) : null}
<div className="text-disabled-text flex items-center text-sm">
<span className="color-gray-darkest mr-1">By </span> <div className='cap-first'>
{safeStrMessage}
</div>
</div>
<div className="flex items-center">
<div className="flex items-center text-sm">
<span className="text-gray-600 mr-1 capitalize">By </span>
{props.note.userName},{' '} {props.note.userName},{' '}
{formatTimeOrDate(props.note.createdAt as unknown as number, timezone)} {formatTimeOrDate(props.note.createdAt as unknown as number, timezone)}
<div className="mx-2" /> <div className="mx-2" />

View file

@ -5,7 +5,7 @@ export default function TeamBadge() {
return ( return (
<div className="flex items-center ml-2"> <div className="flex items-center ml-2">
<Icon name="user-friends" className="mr-1" color="gray-darkest" /> <Icon name="user-friends" className="mr-1" color="gray-darkest" />
<span className="text-disabled-text text-sm">Team</span> <span className="text-sm">Team</span>
</div> </div>
) )
} }

View file

@ -215,7 +215,7 @@ function SessionList(props: Props) {
<div className='flex items-center justify-center flex-col'> <div className='flex items-center justify-center flex-col'>
<AnimatedSVG name={NO_CONTENT.icon} size={180} /> <AnimatedSVG name={NO_CONTENT.icon} size={180} />
<div className='mt-4' /> <div className='mt-4' />
<div className='text-center relative'> <div className='text-center relative text-lg'>
{NO_CONTENT.message} {NO_CONTENT.message}
</div> </div>
</div> </div>

View file

@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { Button, Icon } from 'UI'; import { Button } from 'antd';
import { LinkOutlined } from '@ant-design/icons';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
function SessionCopyLink({ time }: { time: number }) { function SessionCopyLink({ time }: { time: number }) {
@ -20,11 +22,8 @@ function SessionCopyLink({ time }: { time: number }) {
return ( return (
<div className="flex justify-between items-center w-full mt-2"> <div className="flex justify-between items-center w-full mt-2">
<Button variant="text-primary" onClick={copyHandler}> <Button type="text" onClick={copyHandler} icon={<LinkOutlined />}>
<> Copy URL at Current Time
<Icon name="link-45deg" className="mr-2" color="teal" size="18" />
<span>Copy URL at current time</span>
</>
</Button> </Button>
{copied && <div className="color-gray-medium">Copied</div>} {copied && <div className="color-gray-medium">Copied</div>}
</div> </div>

View file

@ -175,7 +175,7 @@ function ShareModalComp({
<div> <div>
<div className={'flex flex-col gap-4'}> <div className={'flex flex-col gap-4'}>
<div> <div>
<div className={'font-semibold flex items-center'}> <div className={'font-medium flex items-center'}>
Share via Share via
</div> </div>
{hasBoth ? ( {hasBoth ? (
@ -214,7 +214,7 @@ function ShareModalComp({
</div> </div>
<div> <div>
<div className={'font-semibold'}>Select a channel or individual</div> <div className={'font-medium'}>Select a channel or individual</div>
{shareTo === 'slack' ? ( {shareTo === 'slack' ? (
<Select <Select
options={slackOptions} options={slackOptions}
@ -233,7 +233,7 @@ function ShareModalComp({
</div> </div>
<div> <div>
<div className={'font-semibold'}>Message</div> <div className={'font-medium'}>Message</div>
<textarea <textarea
name="message" name="message"
id="message" id="message"

View file

@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { Icon, Tooltip } from 'UI'; import { Icon, Tooltip } from 'UI';
import { Segmented } from 'antd';
import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
import cn from 'classnames'; import cn from 'classnames';
interface Props { interface Props {
@ -11,30 +13,22 @@ export default React.memo(function SortOrderButton(props: Props) {
const isAscending = sortOrder === 'asc'; const isAscending = sortOrder === 'asc';
return ( return (
<div className="flex items-center border"> <div className="rounded-full">
<Tooltip title={'Ascending'}>
<div
className={cn('p-2 hover:bg-active-blue', {
'cursor-pointer bg-white': !isAscending,
'bg-active-blue pointer-events-none': isAscending,
})}
onClick={() => onChange('asc')}
>
<Icon name="arrow-up" size="14" color={isAscending ? 'teal' : 'gray-medium'} />
</div>
</Tooltip>
<Tooltip title={'Descending'}> <Segmented
<div size='small'
className={cn('p-2 hover:bg-active-blue border-l', { options={[
'cursor-pointer bg-white': isAscending, { label: 'Ascending', value: 'Ascending', icon: <ArrowUpOutlined /> },
'bg-active-blue pointer-events-none': !isAscending, { label: 'Descending', value: 'Descending', icon: <ArrowDownOutlined /> },
})} ]}
onClick={() => onChange('desc')} onChange={(value) => {
> if (value === 'Ascending') {
<Icon name="arrow-down" size="14" color={!isAscending ? 'teal' : 'gray-medium'} /> onChange('asc');
</div> } else if (value === 'Descending') {
</Tooltip> onChange('desc');
}
}}
/>
</div> </div>
); );
}); });

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { Icon, Popover, Tooltip } from "UI"; import { Icon, Popover, Tooltip } from "UI";
import { Dropdown, Menu, Button } from "antd"; import { Dropdown, Menu, Button } from "antd";
import { MoreOutlined } from "@ant-design/icons"; import {EllipsisVertical} from 'lucide-react';
import styles from "./itemMenu.module.css"; import styles from "./itemMenu.module.css";
import cn from "classnames"; import cn from "classnames";
@ -99,7 +99,7 @@ export default class ItemMenu extends React.PureComponent<Props> {
<Button <Button
className={cn("select-none", !this.props.flat ? parentStyles : "", { className={cn("select-none", !this.props.flat ? parentStyles : "", {
"": !this.props.flat && displayed && label, "": !this.props.flat && displayed && label,
})} }, 'border-0 shadow-one')}
> >
{label && ( {label && (
<span className={cn("font-medium")}> <span className={cn("font-medium")}>
@ -114,7 +114,7 @@ export default class ItemMenu extends React.PureComponent<Props> {
className={cn("rounded-full flex items-center justify-center")} className={cn("rounded-full flex items-center justify-center")}
role="button" role="button"
> >
<MoreOutlined /> <EllipsisVertical size={16} />
</div> </div>
)} )}
</Button> </Button>

View file

@ -8,7 +8,7 @@ import styles from './link.module.css';
const OpenReplayLink = ({ siteId, to, className="", dispatch, ...other }) => ( const OpenReplayLink = ({ siteId, to, className="", dispatch, ...other }) => (
<Link <Link
{ ...other } { ...other }
className={ cn(className, styles.link) } className={ cn(className, styles.link , 'px-2', 'rounded-lg', 'hover:text-inherit', 'hover:bg-amber-50', 'hover:shadow-sm') }
to={ withSiteId(to, siteId) } to={ withSiteId(to, siteId) }
/> />
); );

View file

@ -4,8 +4,8 @@ import APIClient from 'App/api_client';
export const tagProps = { export const tagProps = {
'ISSUE': 'red', 'ISSUE': 'red',
'QUERY': 'geekblue', 'QUERY': 'geekblue',
'TASK': 'cyan', 'TASK': 'purple',
'OTHER': 'rgba(0, 0, 0, 0.6)', 'OTHER': '',
} }
export type iTag = keyof typeof tagProps | "ALL" export type iTag = keyof typeof tagProps | "ALL"