Merge branch 'dashboards-redesign' of https://github.com/openreplay/openreplay into dashboards-redesign

This commit is contained in:
Sudheer Salavadi 2024-06-26 17:47:57 +05:30
commit a7c3c68bcd
7 changed files with 148 additions and 81 deletions

View file

@ -0,0 +1,60 @@
import React from 'react';
import {List, Progress, Typography} from "antd";
import cn from "classnames";
interface Props {
list: any;
selected: any;
onClickHandler: (event: any, data: any) => void;
}
function CardSessionsByList({list, selected, onClickHandler}: Props) {
return (
<List
dataSource={list}
split={false}
renderItem={(row: any) => (
<List.Item
key={row.name}
onClick={(e) => onClickHandler(e, row)}
style={{
borderBottom: '1px dotted rgba(0, 0, 0, 0.05)',
padding: '4px 10px',
lineHeight: '1px'
}}
className={cn('rounded hover:bg-active-blue cursor-pointer', selected === row.name ? 'bg-active-blue' : '')}
>
<List.Item.Meta
className="m-0"
avatar={row.icon ? row.icon : null}
title={(
<div className="m-0">
<div className="flex justify-between m-0 p-0">
<Typography.Text strong>{row.name}</Typography.Text>
<Typography.Text type="secondary"> {row.sessionCount}</Typography.Text>
</div>
<Progress
percent={row.progress}
showInfo={false}
strokeColor={{
'0%': '#394EFF',
'100%': '#394EFF',
}}
size={['small', 2]}
style={{
padding: '0 0px',
margin: '0 0px',
height: 4
}}
/>
</div>
)}
/>
</List.Item>
)}
/>
);
}
export default CardSessionsByList;

View file

@ -1,9 +1,11 @@
import React from 'react';
import {List, Typography} from 'antd';
import {Button, Space} from 'antd';
import {filtersMap} from 'Types/filter/newFilter';
import {Icon} from 'UI';
import {Progress, Empty} from 'antd';
import cn from "classnames";
import {Empty} from 'antd';
import {ArrowRight} from "lucide-react";
import CardSessionsByList from "Components/Dashboard/Widgets/CardSessionsByList";
import {useModal} from "Components/ModalContext";
interface Props {
metric?: any;
@ -15,6 +17,8 @@ interface Props {
function SessionsBy(props: Props) {
const {metric = {}, data = {values: []}, onClick = () => null, isTemplate} = props;
const [selected, setSelected] = React.useState<any>(null);
const total = data.values.length
const {openModal, closeModal} = useModal();
const onClickHandler = (event: any, data: any) => {
const filters = Array<any>();
@ -34,8 +38,19 @@ function SessionsBy(props: Props) {
onClick(filters);
}
const showMore = () => {
openModal(
<CardSessionsByList list={data.values} onClickHandler={(e, item) => {
closeModal();
onClickHandler(null, item)
}} selected={selected}/>, {
title: metric.name,
width: 600,
})
}
return (
<div style={{height: 240, overflowY: 'scroll', margin: '0 -16px', padding: '0 16px'}}>
<div>
{data.values && data.values.length === 0 ? (
<Empty
style={{minHeight: 220}}
@ -49,45 +64,21 @@ function SessionsBy(props: Props) {
}
/>
) : (
<List
dataSource={data.values}
split={false}
renderItem={(row: any) => (
<List.Item
key={row.name}
onClick={(e) => onClickHandler(e, row)}
// actions={[row.sessionCount]}
style={{borderBottom: '1px dotted rgba(0, 0, 0, 0.05)', padding: '6px 0'}}
className={cn('hover:bg-active-blue cursor-pointer', selected === row.name ? 'bg-gray-100' : '')}
>
<List.Item.Meta
avatar={row.icon ? row.icon : null}
title={(
<div className="flex justify-between">
<Typography.Text strong>{row.name}</Typography.Text>
<Typography.Text type="secondary"> {row.sessionCount}</Typography.Text>
</div>
)}
description={
<Progress
percent={row.progress}
showInfo={false}
strokeColor={{
'0%': '#394EFF',
'100%': '#394EFF',
}}
size={['small', 2]}
style={{
padding: '0 0px',
margin: '0 0px',
}}
/>
}
/>
{/*<div className="min-w-8">{row.value}</div>*/}
</List.Item>
<div className="flex flex-col justify-between w-full" style={{height: 220}}>
<CardSessionsByList list={data.values.slice(0, 3)}
selected={selected}
onClickHandler={onClickHandler}/>
{total > 3 && (
<div className="flex">
<Button type="link" onClick={showMore}>
<Space>
{total - 3} more
<ArrowRight size={16}/>
</Space>
</Button>
</div>
)}
/>
</div>
)}
</div>
);

View file

@ -1,5 +1,6 @@
import ExCard from '../ExCard'
import React from 'react'
import CardSessionsByList from "Components/Dashboard/Widgets/CardSessionsByList";
function ByComponent({title, rows, lineWidth, onCard, type}: {
title: string
@ -13,6 +14,11 @@ function ByComponent({title, rows, lineWidth, onCard, type}: {
type: string
lineWidth: number
}) {
const _rows = rows.map((r) => ({
...r,
name: r.label,
sessionCount: r.value,
})).slice(0, 4)
return (
<ExCard
title={title}
@ -20,37 +26,39 @@ function ByComponent({title, rows, lineWidth, onCard, type}: {
type={type}
>
<div className={'flex gap-1 flex-col'}>
{rows.map((r) => (
<div
className={
'flex items-center gap-2 border-b border-dotted py-2 last:border-0 first:pt-0 last:pb-0'
}
>
<div>{r.icon}</div>
<div>{r.label}</div>
<div
style={{marginLeft: 'auto', marginRight: 20, display: 'flex'}}
>
<div
style={{
height: 2,
width: lineWidth * (0.01 * r.progress),
background: '#394EFF',
}}
className={'rounded-l'}
/>
<div
style={{
height: 2,
width: lineWidth - lineWidth * (0.01 * r.progress),
background: '#E2E4F6',
}}
className={'rounded-r'}
/>
</div>
<div className={'min-w-8'}>{r.value}</div>
</div>
))}
<CardSessionsByList list={_rows} selected={''} onClickHandler={() => null}/>
{/*{rows.map((r) => (*/}
{/* <div*/}
{/* className={*/}
{/* 'flex items-center gap-2 border-b border-dotted py-2 last:border-0 first:pt-0 last:pb-0'*/}
{/* }*/}
{/* >*/}
{/* <div>{r.icon}</div>*/}
{/* <div>{r.label}</div>*/}
{/* <div*/}
{/* style={{marginLeft: 'auto', marginRight: 20, display: 'flex'}}*/}
{/* >*/}
{/* <div*/}
{/* style={{*/}
{/* height: 2,*/}
{/* width: lineWidth * (0.01 * r.progress),*/}
{/* background: '#394EFF',*/}
{/* }}*/}
{/* className={'rounded-l'}*/}
{/* />*/}
{/* <div*/}
{/* style={{*/}
{/* height: 2,*/}
{/* width: lineWidth - lineWidth * (0.01 * r.progress),*/}
{/* background: '#E2E4F6',*/}
{/* }}*/}
{/* className={'rounded-r'}*/}
{/* />*/}
{/* </div>*/}
{/* <div className={'min-w-8'}>{r.value}</div>*/}
{/* </div>*/}
{/*))}*/}
</div>
</ExCard>
)

View file

@ -15,6 +15,7 @@ const NewDashboardModal: React.FC<NewDashboardModalProps> = ({
isAddingFromLibrary = false,
}) => {
const [step, setStep] = React.useState<number>(0);
const [selectedCategory, setSelectedCategory] = React.useState<string>('product-analytics');
useEffect(() => {
return () => {
@ -28,6 +29,8 @@ const NewDashboardModal: React.FC<NewDashboardModalProps> = ({
<div>
<div className="flex flex-col gap-4">
{step === 0 && <SelectCard onClose={onClose}
selected={selectedCategory}
setSelectedCategory={setSelectedCategory}
onCard={() => setStep(step + 1)}
isLibrary={isAddingFromLibrary}/>}
{step === 1 && <CreateCard onBack={() => setStep(0)}/>}

View file

@ -9,11 +9,12 @@ interface SelectCardProps {
onClose: (refresh?: boolean) => void;
onCard: () => void;
isLibrary?: boolean;
selected?: string;
setSelectedCategory?: React.Dispatch<React.SetStateAction<string>>;
}
const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
const {onCard, isLibrary = false} = props;
const [selected, setSelected] = React.useState<string>('product-analytics');
const {onCard, isLibrary = false, selected, setSelectedCategory} = props;
const [selectedCards, setSelectedCards] = React.useState<number[]>([]);
const {metricStore, dashboardStore} = useStore();
const dashboardId = window.location.pathname.split('/')[3];
@ -83,7 +84,7 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
)}
</Space>
{!isLibrary && <CategorySelector setSelected={setSelected}/>}
{!isLibrary && <CategorySelector setSelected={setSelectedCategory} selected={selected}/>}
{isLibrary ? <CardsLibrary query={libraryQuery} selectedList={selectedCards} category={selected}
onCard={onCardClick}/> :
<ExampleCardsGrid items={cardItems}/>}
@ -111,15 +112,17 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
// );
interface CategorySelectorProps {
setSelected: React.Dispatch<React.SetStateAction<string>>;
setSelected?: React.Dispatch<React.SetStateAction<string>>;
selected?: string;
}
const CategorySelector: React.FC<CategorySelectorProps> = ({setSelected}) => (
const CategorySelector: React.FC<CategorySelectorProps> = ({setSelected, selected}) => (
<Segmented
options={CARD_CATEGORIES.map(({key, label, icon}) => ({
label: <Option key={key} label={label} Icon={icon}/>,
value: key,
}))}
value={selected}
onChange={setSelected}
/>
);

View file

@ -296,8 +296,10 @@ const CardBuilder = observer((props: CardBuilderProps) => {
{/* metric={metric}*/}
{/* writeOption={writeOption}*/}
{/*/>*/}
<MetricTabs metric={metric}
writeOption={writeOption}/>
{/*<MetricTabs metric={metric}*/}
{/* writeOption={writeOption}/>*/}
{metric.metricType === USER_PATH && <PathAnalysisFilter metric={metric}/>}
{isPredefined && <PredefinedMessage/>}
{testingKey && (

View file

@ -126,7 +126,7 @@ function WidgetPreview(props: Props) {
{/*)}*/}
</div>
</div>
<div className="p-4 pt-0">
<div className="pt-0">
<WidgetWrapper widget={metric} isPreview={true} isWidget={false} hideName/>
</div>
</div>