UI improvements in New Cards (#2864)
This commit is contained in:
parent
c1283c7f20
commit
f3561e55fb
18 changed files with 108 additions and 103 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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 }}>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ function WidgetPreview(props: Props) {
|
|||
<WidgetOptions />
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-0">
|
||||
<div className="py-4">
|
||||
<WidgetWrapper
|
||||
widget={metric}
|
||||
isPreview={true}
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue