UI improvements in New Cards (#2864)

This commit is contained in:
Sudheer Salavadi 2024-12-12 04:54:16 -05:00 committed by GitHub
parent c1283c7f20
commit f3561e55fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 108 additions and 103 deletions

View file

@ -50,7 +50,7 @@ function BigNum({ color, series, value, label, compData, valueLabel }: {
}, [value, compData])
return (
<div className={'flex flex-col gap-2 py-8 items-center'}>
<div className={'flex items-center gap-2 font-semibold text-gray-darkest'}>
<div className={'flex items-center gap-2 font-medium text-gray-darkest'}>
<div className={'rounded w-4 h-4'} style={{ background: color }} />
<div>{series}</div>
</div>

View file

@ -54,7 +54,7 @@ function CustomTooltip({ active, payload, label }: Props) {
>
<div className={'invert text-sm'}>{index + 1}</div>
</div>
<div className={'font-semibold'}>{p.name}</div>
<div className={'font-medium'}>{p.name}</div>
</div>
<div
style={{ borderLeft: `2px solid ${p.color}` }}
@ -64,7 +64,7 @@ function CustomTooltip({ active, payload, label }: Props) {
{label}, {formatTimeOrDate(p.payload.timestamp)}
</div>
<div className={'flex items-center gap-2'}>
<div className={'font-semibold'}>{p.value}</div>
<div className={'font-medium'}>{p.value}</div>
{p.prevValue !== null ? (
<CompareTag
isHigher={isHigher(p)}

View file

@ -1,6 +1,6 @@
import React from 'react';
import { FolderOutlined } from '@ant-design/icons';
import { Segmented } from 'antd';
import { Segmented, Button } from 'antd';
import {
LineChart,
AlignStartVertical,
@ -185,19 +185,19 @@ function CategoryTab({ tab, inCards }: { tab: string; inCards?: boolean }) {
}
};
return (
<div className={'flex flex-col'}>
<div className={'flex flex-col gap-3'}>
{items.map((item, index) => (
<div
onClick={() => handleCardSelection(item.type)}
key={index}
className={
'flex items-start gap-2 p-2 hover:bg-active-blue rounded-xl hover:text-blue group cursor-pointer'
'flex items-start gap-2 p-2 hover:bg-active-blue rounded-xl hover:text-teal group cursor-pointer'
}
>
{item.icon}
<div className={'leading-none'}>
<div>{item.title}</div>
<div className={'text-disabled-text group-hover:text-blue text-sm'}>
<div className={'text-disabled-text group-hover:text-teal/60 text-sm'}>
{item.description}
</div>
</div>
@ -235,20 +235,11 @@ const AddCardSection = observer(
);
};
return (
<div
className={
'py-8 px-8 rounded-xl bg-white border border-gray-lighter flex flex-col gap-4'
}
style={{ width: fit ? 390 : 520, height: 400 }}
>
<div
className={'flex justify-between border-b border-b-gray-lighter p-2'}
>
<div className={'font-semibold text-lg'}>Add a card to dashboard</div>
<div className={'pt-4 pb-6 px-6 rounded-xl bg-white border border-gray-lighter flex flex-col gap-2'}>
<div className={'flex justify-between p-2'}>
<div className={'text-xl font-medium mb-1'}>What do you want to visualize?</div>
{isSaas ? (
<div
className={'font-semibold flex items-center gap-2 cursor-pointer'}
>
<div className={'font-medium flex items-center gap-2 cursor-pointer'}>
<Sparkles color={'#3C00FFD8'} size={16} />
<div className={'ai-gradient'}>Ask AI</div>
</div>
@ -261,16 +252,14 @@ const AddCardSection = observer(
onChange={(value) => setTab(value)}
/>
</div>
<div className='py-2'>
<CategoryTab tab={tab} inCards={inCards} />
<div
className={
'w-full flex items-center justify-center border-t mt-auto border-t-gray-lighter gap-2 pt-2 cursor-pointer'
}
>
<FolderOutlined />
<div className={'font-semibold'} onClick={onExistingClick}>
Add existing card
</div>
</div>
<div className={'w-full flex items-center justify-center border-t mt-auto border-t-gray-lighter gap-2 pt-2 cursor-pointer'}>
<Button className='w-full mt-4 hover:bg-active-blue hover:text-teal' type='text' variant='text' onClick={onExistingClick}>
<FolderOutlined /> Add existing card
</Button>
</div>
</div>
);

View file

@ -60,8 +60,8 @@ function AlertsList({ siteId }: Props) {
<div className='w-full flex items-center justify-between pt-4 px-6'>
<div className=''>
Showing <span className='font-semibold'>{Math.min(list.length, pageSize)}</span> out of{' '}
<span className='font-semibold'>{list.length}</span> Alerts
Showing <span className='font-medium'>{Math.min(list.length, pageSize)}</span> out of{' '}
<span className='font-medium'>{list.length}</span> Alerts
</div>
<Pagination
page={page}

View file

@ -59,8 +59,8 @@ function CardUserList(props: RouteComponentProps<Props>) {
<div className="w-full flex items-center justify-between pt-4">
<div className="text-disabled-text">
Showing <span className="font-semibold">{Math.min(data.length, pageSize)}</span> out of{' '}
<span className="font-semibold">{data.length}</span> Issues
Showing <span className="font-medium">{Math.min(data.length, pageSize)}</span> out of{' '}
<span className="font-medium">{data.length}</span> Issues
</div>
<Pagination
page={metricStore.sessionsPage}

View file

@ -41,7 +41,7 @@ const InputBox = observer(({ inModal }: { inModal?: boolean }) => {
<>
{!inModal ? <div className={"flex items-center mb-2 gap-2"}>
<Icon name={"sparkles"} size={16} />
<div className={"font-semibold"}>What would you like to visualize?</div>
<div className={"font-medium"}>What would you like to visualize?</div>
</div> : null}
<div style={gradientBox}>
<Input
@ -114,7 +114,7 @@ function Loader() {
return (
<div
className={
'flex items-center justify-center flex-col font-semibold text-xl min-h-80'
'flex items-center justify-center flex-col font-medium text-xl min-h-80'
}
>
<div style={{ width: 150, height: 150 }}>

View file

@ -96,9 +96,9 @@ function AddMetric({ history, siteId, title, description }: IProps) {
<div className="py-4 border-t px-8 bg-white w-full flex items-center justify-between">
<div>
{'Selected '}
<span className="font-semibold">{selectedWidgetIds.length}</span>
<span className="font-medium">{selectedWidgetIds.length}</span>
{' out of '}
<span className="font-semibold">{metrics ? metrics.length : 0}</span>
<span className="font-medium">{metrics ? metrics.length : 0}</span>
</div>
<Button variant="primary" disabled={selectedWidgetIds.length === 0} onClick={onSave}>
Add Selected

View file

@ -141,9 +141,9 @@ function AddPredefinedMetric({ history, siteId, title, description }: IProps) {
<div className="py-4 border-t px-8 bg-white w-full flex items-center justify-between">
<div>
{'Selected '}
<span className="font-semibold">{selectedWidgetIds.length}</span>
<span className="font-medium">{selectedWidgetIds.length}</span>
{' out of '}
<span className="font-semibold">{totalMetricCount}</span>
<span className="font-medium">{totalMetricCount}</span>
</div>
<Button variant="primary" disabled={selectedWidgetIds.length === 0} onClick={onSave}>
Add Selected

View file

@ -64,8 +64,8 @@ function SessionsModal(props: Props) {
<div className='w-full flex items-center justify-between p-4 absolute bottom-0 bg-white'>
<div className='text-disabled-text'>
Showing <span
className='font-semibold'>{Math.min(length, 10)}</span> out of{' '}
<span className='font-semibold'>{total}</span> Issues
className='font-medium'>{Math.min(length, 10)}</span> out of{' '}
<span className='font-medium'>{total}</span> Issues
</div>
<Pagination
page={page}

View file

@ -8,14 +8,14 @@ import { TableExporter } from "../../../Funnels/FunnelWidget/FunnelTable";
const initTableProps = [
{
title: 'Series',
title: <span className="font-medium">Series</span>,
dataIndex: 'seriesName',
key: 'seriesName',
sorter: (a, b) => a.seriesName.localeCompare(b.seriesName),
fixed: 'left',
},
{
title: 'Avg.',
title: <span className="font-medium">Avg.</span>,
dataIndex: 'average',
key: 'average',
sorter: (a, b) => a.average - b.average,
@ -57,7 +57,7 @@ function WidgetDatatable(props: Props) {
setTableProps(initTableProps);
columnNames.clear();
data.chart.forEach((p: any) => {
columnNames.add(p.time);
columnNames.add(p.time);
}); // for example: mon, tue, wed, thu, fri, sat, sun
const avg: any = {}; // { seriesName: {itemsCount: 0, total: 0} }
const items: Record<string, any>[] = []; // as many items (rows) as we have series in filter

View file

@ -1,6 +1,7 @@
import React from 'react'
import AntlikeDropdown from "Shared/Dropdown";
import { DownOutlined } from "@ant-design/icons";
import { Button, Dropdown, MenuProps } from 'antd';
function RangeGranularity({
period,
@ -19,9 +20,9 @@ function RangeGranularity({
}, [period]);
const menuProps = {
const menuProps: MenuProps = {
items: granularityOptions,
onClick: (item: any) => onDensityChange(item.key),
onClick: (item: any) => onDensityChange(Number(item.key)),
}
const selected = React.useMemo(() => {
let selected = 'Custom';
@ -41,12 +42,12 @@ function RangeGranularity({
}, [period, granularityOptions.length]);
return (
<AntlikeDropdown
useButtonStyle
label={selected}
rightIcon={<DownOutlined />}
menuProps={menuProps}
/>
<Dropdown menu={menuProps} trigger={['click']}>
<Button type='text' variant='text' size='small'>
<span>{selected}</span>
<DownOutlined />
</Button>
</Dropdown>
)
}

View file

@ -59,15 +59,22 @@ function WidgetOptions() {
{(metric.metricType === FUNNEL || metric.metricType === TABLE) &&
metric.metricOf != FilterKey.USERID &&
metric.metricOf != FilterKey.ERRORS && (
<Select
defaultValue={metric.metricFormat}
onChange={handleChange}
variant="borderless"
options={[
{ value: 'sessionCount', label: 'All Sessions' },
{ value: 'userCount', label: 'Unique Users' },
]}
/>
<Dropdown
trigger={['click']}
menu={{
selectable: true,
items: [
{ key: 'sessionCount', label: 'All Sessions' },
{ key: 'userCount', label: 'Unique Users' },
],
onClick: (info: { key: string }) => handleChange(info.key)
}}
>
<Button type='text' variant='text' size='small'>
{metric.metricFormat === 'sessionCount' ? 'All Sessions' : 'Unique Users'}
<DownOutlined className='text-sm' />
</Button>
</Dropdown>
)}
{hasViewTypes ? <WidgetViewTypeOptions metric={metric} /> : null}
@ -88,7 +95,9 @@ const SeriesTypeOptions = observer(({ metric }: { metric: any }) => {
return (
<Dropdown
trigger={['click']}
menu={{
selectable: true,
items: Object.entries(items).map(([key, name]) => ({
key,
label: (
@ -103,11 +112,11 @@ const SeriesTypeOptions = observer(({ metric }: { metric: any }) => {
},
}}
>
<Button>
<Button type='text' variant='text' size='small'>
<Space>
{chartIcons[metric.metricOf]}
<div>{items[metric.metricOf] || 'Total Sessions'}</div>
<DownOutlined />
<DownOutlined className='text-sm' />
</Space>
</Button>
</Dropdown>
@ -152,11 +161,13 @@ const WidgetViewTypeOptions = observer(({ metric }: { metric: any }) => {
};
return (
<Dropdown
trigger={['click']}
menu={{
selectable: true,
items: allowedTypes[metric.metricType].map((key) => ({
key,
label: (
<div className={'flex items-center gap-2'}>
<div className='flex gap-2 items-center'>
{chartIcons[key]}
<div>{chartTypes[key]}</div>
</div>
@ -166,12 +177,13 @@ const WidgetViewTypeOptions = observer(({ metric }: { metric: any }) => {
metric.updateKey('viewType', key);
},
}}
>
<Button>
<Button type='text' variant='text' size='small'>
<Space>
{chartIcons[metric.viewType]}
<div>{chartTypes[metric.viewType]}</div>
<DownOutlined />
<DownOutlined className='text-sm ' />
</Space>
</Button>
</Dropdown>

View file

@ -38,7 +38,7 @@ function WidgetPreview(props: Props) {
<WidgetOptions />
</div>
</div>
<div className="pt-0">
<div className="py-4">
<WidgetWrapper
widget={metric}
isPreview={true}

View file

@ -116,7 +116,7 @@ function WidgetSessions(props: Props) {
};
return (
<div className={cn(className, 'bg-white p-3 pb-0 rounded-lg shadow-sm border mt-3')}>
<div className={cn(className, 'bg-white p-3 pb-0 rounded-xl shadow-sm border mt-3')}>
<div className="flex items-center justify-between">
<div>
<div className="flex items-baseline">

View file

@ -103,7 +103,7 @@ function WidgetWrapper(props: Props & RouteComponentProps) {
return (
<div
className={cn(
'relative rounded bg-white border group rounded-lg',
'relative bg-white border group rounded-lg',
'col-span-' + widget.config.col,
{ 'hover:shadow-border-gray': !isTemplate && isSaved },
{ 'hover:shadow-border-main': isTemplate }

View file

@ -177,7 +177,7 @@ export const EventsList = observer((props: Props) => {
const eventsNum = filters.filter((i: any) => i.isEvent).length;
return (
<div
className={'border-b border-b-gray-lighter py-2 px-4 rounded-xl bg-white border border-gray-lighter'}
className={'border-b border-b-gray-lighter py-2 px-4 rounded-xl bg-white border border-gray-lighter overflow-hidden'}
style={{
borderBottomLeftRadius: props.mergeDown ? 0 : undefined,
borderBottomRightRadius: props.mergeDown ? 0 : undefined,

View file

@ -21,7 +21,7 @@ interface Props<Value extends ValueObject> {
onChange: (newValue: { name: string, value: Value }) => void;
name?: string;
placeholder?: string;
className?: string;
[x: string]: any;
}
@ -37,6 +37,7 @@ export default function <Value extends ValueObject>({
styles = {},
defaultValue = '',
controlStyle = {},
className = '',
...rest
}: Props<Value>) {
@ -143,6 +144,7 @@ export default function <Value extends ValueObject>({
return (
<Select
className={className}
options={options}
isSearchable={isSearchable}
defaultValue={defaultSelected}

View file

@ -1,6 +1,6 @@
import { DownOutlined, CloseOutlined } from '@ant-design/icons';
import { DownOutlined, SyncOutlined } from '@ant-design/icons';
import Period from 'Types/app/period';
import { Dropdown } from 'antd';
import { Dropdown, Button, Tooltip } from 'antd';
import cn from 'classnames';
import { observer } from 'mobx-react-lite';
import React from 'react';
@ -24,7 +24,7 @@ interface Props {
timezone?: string;
isAnt?: boolean;
small?: boolean;
useButtonStyle?: boolean; // New prop to control button style
useButtonStyle?: boolean;
compPeriod?: any | null;
onChangeComparison?: (data: any) => void;
comparison?: boolean;
@ -125,7 +125,7 @@ function SelectDateRange(props: Props) {
}}
period={period}
right={true}
style={{ width: '100%' }}
style={{ width: '100%', }}
/>
{isCustom && (
<OutsideClickDetectingDiv
@ -196,36 +196,37 @@ function AndDateRange({
<div className={'relative'}>
{comparison ? (
<div className={'flex items-center gap-0'}>
<Dropdown menu={menuProps} className={'px-2 py-1'}>
<div
className={
'cursor-pointer flex items-center gap-2 border-l border-t border-b border-gray-light rounded-l !border-r-0'
}
>
<span>
{`Compare to ${comparisonValue || ''}`}
</span>
<DownOutlined />
</div>
<Dropdown menu={menuProps} trigger={['click']} className={'px-2 py-1 gap-1'}>
<Button type='text' variant='text' className='flex items-center' size='small'>
<span>{`Compare to ${comparisonValue || ''}`}</span>
{selectedValue && (
<Tooltip title='Reset'>
<SyncOutlined
className='cursor-pointer p-2 py-1.5 hover:bg-neutral-200/50 text-sm'
onClick={(e) => {
e.stopPropagation();
onChange(null);
}}
/>
</Tooltip>
)}
<DownOutlined className='ms-1' />
</Button>
</Dropdown>
<div
className={
'flex items-center justify-center border border-gray-light p-2 hover:border-main rounded-r'
}
style={{ height: 30 }}
onClick={() => onChange(null)}
>
<CloseOutlined />
</div>
</div>
) : (
<AntlikeDropdown
label={isCustomRange ? customRange : selectedValue?.label}
menuProps={menuProps}
useButtonStyle={useButtonStyle}
leftIcon={useButtonStyle ? <Calendar size={16} /> : null}
rightIcon={<DownOutlined />}
/>
<Dropdown menu={menuProps} trigger={['click']}>
<Button
type="text"
size='small'
className="flex items-center"
icon={useButtonStyle ? <Calendar size={16} /> : null}
>
{isCustomRange ? customRange : selectedValue?.label}
<DownOutlined />
</Button>
</Dropdown>
)}
{isCustom && (
<OutsideClickDetectingDiv