change(ui): projects revamp - progress avatar of samplerate, scroll etc.,

This commit is contained in:
Shekar Siri 2025-01-07 17:43:12 +01:00
parent 1b1287515b
commit 40ff41f97d
6 changed files with 80 additions and 74 deletions

View file

@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';
import { NoContent } from 'UI';
import CustomFieldForm from './CustomFieldForm';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import { useModal } from 'App/components/Modal';
@ -8,6 +7,7 @@ import { observer } from 'mobx-react-lite';
import { List, Space, Typography, Button, Tooltip } from 'antd';
import { PencilIcon, PlusIcon, Tags } from 'lucide-react';
import usePageTitle from '@/hooks/usePageTitle';
import { Empty } from '.store/antd-virtual-7db13b4af6/package';
const CustomFields = () => {
usePageTitle('Metadata - OpenReplay Preferences');
@ -59,36 +59,26 @@ const CustomFields = () => {
</Typography.Text>
</Space>
<NoContent
title={
<div className="flex flex-col items-center justify-center">
<AnimatedSVG name={ICONS.NO_METADATA} size={60} />
<div className="text-center my-4">None added yet</div>
</div>
}
size="small"
show={fields.length === 0}
>
<List
loading={loading}
dataSource={fields}
renderItem={(field: any) => (
<List.Item
// disabled={deletingItem !== null && deletingItem === field.index}
onClick={() => handleInit(field)}
className="cursor-pointer group hover:bg-active-blue !px-4"
actions={[
<Button className="opacity-0 group-hover:!opacity-100" icon={<PencilIcon size={14} />} />
]}
>
<List.Item.Meta
title={field.key}
avatar={<Tags size={20} />}
/>
</List.Item>
)} />
</NoContent>
<List
locale={{
emptyText: <Empty description="None added yet" image={<AnimatedSVG name={ICONS.NO_METADATA} size={60} />} />
}}
loading={loading}
dataSource={fields}
renderItem={(field: any) => (
<List.Item
onClick={() => handleInit(field)}
className="cursor-pointer group hover:bg-active-blue !px-4"
actions={[
<Button className="opacity-0 group-hover:!opacity-100" icon={<PencilIcon size={14} />} />
]}
>
<List.Item.Meta
title={field.key}
avatar={<Tags size={20} />}
/>
</List.Item>
)} />
</div>
);
};

View file

@ -1,5 +1,5 @@
import React from 'react';
import { Avatar, Input, Menu, List, Typography } from 'antd';
import { Avatar, Input, Menu, Progress } from 'antd';
import { useStore } from '@/mstore';
import Project from '@/mstore/types/project';
import { observer } from 'mobx-react-lite';
@ -21,30 +21,65 @@ function ProjectList() {
return (
<div className="h-full flex flex-col gap-4">
<div className="p-4">
<div className="px-4 mt-4">
<Input.Search
placeholder="Search"
onSearch={onSearch}
onClear={() => setSearch('')}
allowClear
// className="m-4"
/>
</div>
<Menu
mode="inline"
selectedKeys={[config.pid + '']}
className="h-full w-full ml-0 pl-0 !bg-white !border-r-0"
items={list.filter((item: Project) => item.name.toLowerCase().includes(search.toLowerCase())).map((project) => ({
key: project.id,
label: project.name,
onClick: () => onProjectClick(project),
icon: <Avatar className="bg-tealx-light"
icon={project.platform === 'web' ? <AppWindowMac size={18} color="teal" /> :
<Smartphone size={18} color="teal" />} />
})) as any}
/>
<div
style={{
height: 'calc(100vh - 250px)'
}}
className="overflow-y-auto"
>
<Menu
mode="inline"
selectedKeys={[config.pid + '']}
className="w-full ml-0 pl-0 !bg-white !border-r-0"
items={list.filter((item: Project) => item.name.toLowerCase().includes(search.toLowerCase())).map((project) => ({
key: project.id,
label: project.name,
onClick: () => onProjectClick(project),
icon: <ProjectIconWithProgress platform={project.platform} progress={project.sampleRate} />
})) as any}
/>
</div>
</div>
);
}
export default observer(ProjectList);
const ProjectIconWithProgress: React.FC<{
platform: string; progress: number
}> = ({ platform, progress }) => {
return (
<div className="relative flex items-center justify-center mr-2 leading-none">
<Progress
type="circle"
percent={progress}
size={28}
format={() => ''}
strokeWidth={4}
strokeColor="#23959a"
/>
<div className="absolute">
<Avatar
className="bg-tealx-light"
size={26}
icon={
platform === 'web' ? (
<AppWindowMac size={16} color="teal" />
) : (
<Smartphone size={16} color="teal" />
)
}
/>
</div>
</div>
);
};

View file

@ -1,10 +1,11 @@
import React, { useEffect } from 'react';
import { useStore } from '@/mstore';
import { List, Button, Typography, Space } from 'antd';
import { List, Button, Typography, Space, Empty } from 'antd';
import { observer } from 'mobx-react-lite';
import { PencilIcon, ScanSearch } from 'lucide-react';
import { useModal } from 'Components/ModalContext';
import TagForm from 'Components/Client/Projects/TagForm';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
function ProjectTags() {
const { tagWatchStore, projectsStore } = useStore();
@ -36,6 +37,9 @@ function ProjectTags() {
</ul>
</Space>
<List
locale={{
emptyText: <Empty description="No tags found" image={<AnimatedSVG name={ICONS.NO_METADATA} size={60} />} />
}}
loading={tagWatchStore.isLoading}
dataSource={list}
renderItem={(item) => (

View file

@ -58,7 +58,8 @@ function Projects() {
]}
>
<Layout>
<Layout.Sider width={300} trigger={null} className="!bg-white border-r">
<Layout.Sider width={300} trigger={null}
className="!bg-white border-r">
<ProjectList />
</Layout.Sider>

View file

@ -9,11 +9,7 @@ import * as routes from 'App/routes';
import {
CLIENT_DEFAULT_TAB,
CLIENT_TABS,
bookmarks,
client,
fflags,
notes,
sessions,
withSiteId
} from 'App/routes';
import { MODULES } from 'Components/Client/Modules';
@ -33,13 +29,6 @@ import { useStore } from 'App/mstore';
const { Text } = Typography;
const TabToUrlMap = {
all: sessions() as '/sessions',
bookmark: bookmarks() as '/bookmarks',
notes: notes() as '/notes',
flags: fflags() as '/feature-flags'
};
interface Props extends RouteComponentProps {
siteId?: string;
isCollapsed?: boolean;
@ -135,16 +124,6 @@ function SideMenu(props: Props) {
});
}, [isAdmin, isEnterprise, isPreferencesActive, modules, spotOnly, siteId]);
React.useEffect(() => {
const currentLocation = location.pathname;
// const tab = Object.keys(TabToUrlMap).find((tab: keyof typeof TabToUrlMap) =>
// currentLocation.includes(TabToUrlMap[tab])
// );
// if (tab && tab !== searchStore.activeTab && siteId) {
// searchStore.setActiveTab({ type: tab });
// }
}, [location.pathname]);
const menuRoutes: any = {
[MENU.EXIT]: () =>
props.history.push(withSiteId(routes.sessions(), siteId)),
@ -164,7 +143,6 @@ function SideMenu(props: Props) {
[PREFERENCES_MENU.SESSION_LISTING]: () =>
client(CLIENT_TABS.SESSIONS_LISTING),
[PREFERENCES_MENU.INTEGRATIONS]: () => client(CLIENT_TABS.INTEGRATIONS),
[PREFERENCES_MENU.METADATA]: () => client(CLIENT_TABS.CUSTOM_FIELDS),
[PREFERENCES_MENU.WEBHOOKS]: () => client(CLIENT_TABS.WEBHOOKS),
[PREFERENCES_MENU.PROJECTS]: () => client(CLIENT_TABS.SITES),
[PREFERENCES_MENU.ROLES_ACCESS]: () => client(CLIENT_TABS.MANAGE_ROLES),

View file

@ -24,7 +24,6 @@ export const enum PREFERENCES_MENU {
ACCOUNT = 'account',
SESSION_LISTING = 'session-listing',
INTEGRATIONS = 'integrations',
METADATA = 'metadata',
WEBHOOKS = 'webhooks',
MODULES = 'modules',
PROJECTS = 'projects',
@ -131,7 +130,6 @@ export const preferences: Category[] = [
{ label: 'Account', key: PREFERENCES_MENU.ACCOUNT, icon: 'person' },
{ label: 'Sessions Listing', key: PREFERENCES_MENU.SESSION_LISTING, icon: 'card-list' },
{ label: 'Integrations', key: PREFERENCES_MENU.INTEGRATIONS, icon: 'plug' },
{ label: 'Metadata', key: PREFERENCES_MENU.METADATA, icon: 'tags' },
{ label: 'Webhooks', key: PREFERENCES_MENU.WEBHOOKS, icon: 'link-45deg' },
{ label: 'Modules', key: PREFERENCES_MENU.MODULES, icon: 'puzzle' },
{ label: 'Projects', key: PREFERENCES_MENU.PROJECTS, icon: 'folder2' },
@ -159,4 +157,4 @@ export const spotOnlyCats = [
MENU.PREFERENCES,
MENU.SUPPORT,
MENU.SPOTS,
]
]