List view time stamp improvements

Following functions needs to reviewed
- Rename & Delete functionality
- Drag & Drop in gird view
- Table Sorting
This commit is contained in:
Sudheer Salavadi 2024-07-05 11:05:28 +05:30
parent 03fe6c499c
commit 2100cc0412
3 changed files with 138 additions and 80 deletions

View file

@ -9,7 +9,6 @@ import cn from 'classnames';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { toast } from 'react-toastify';
import moment from 'moment'; // Import moment
interface Props extends RouteComponentProps {
metric: any;
@ -83,7 +82,7 @@ const MetricListItem: React.FC<Props> = ({
try {
console.log('Renaming metric:', metric);
console.log('New name:', newName);
metric.name = newName; // Directly update the name property
metric.name = newName;
// Add a toJson method if it doesn't exist
if (typeof metric.toJson !== 'function') {
@ -138,15 +137,38 @@ const MetricListItem: React.FC<Props> = ({
);
const parseDate = (dateString: string) => {
// Try to parse as ISO 8601 string first
let date = moment(dateString, moment.ISO_8601);
if (!date.isValid()) {
// Try to parse as a number (timestamp)
date = moment(Number(dateString));
let date = new Date(dateString);
if (isNaN(date.getTime())) {
date = new Date(parseInt(dateString, 10));
}
return date;
};
const formatDate = (date: Date) => {
const now = new Date();
const diffTime = Math.abs(now.getTime() - date.getTime());
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
const formatTime = (date: Date) => {
let hours = date.getHours();
const minutes = date.getMinutes().toString().padStart(2, '0');
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
return `${hours}:${minutes} ${ampm}`;
};
if (diffDays <= 1) {
return `Today at ${formatTime(date)}`;
} else if (diffDays <= 2) {
return `Yesterday at ${formatTime(date)}`;
} else if (diffDays <= 3) {
return `${diffDays} days ago at ${formatTime(date)}`;
} else {
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()} at ${formatTime(date)}`;
}
};
switch (renderColumn) {
case 'title':
return (
@ -170,7 +192,8 @@ const MetricListItem: React.FC<Props> = ({
</div>
);
case 'lastModified':
return parseDate(metric.lastModified).calendar(); // Use moment to return relative time
const date = parseDate(metric.lastModified);
return formatDate(date);
case 'options':
return (
<>

View file

@ -1,37 +1,41 @@
import React from 'react';
import {PageTitle, Toggler, Icon} from "UI";
import {Segmented, Button} from 'antd';
import React, { useEffect } from 'react';
import { PageTitle, Toggler, Icon } from "UI";
import { Segmented, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import MetricsSearch from '../MetricsSearch';
import Select from 'Shared/Select';
import {useStore} from 'App/mstore';
import {observer, useObserver} from 'mobx-react-lite';
import {DROPDOWN_OPTIONS} from 'App/constants/card';
import { useStore } from 'App/mstore';
import { observer, useObserver } from 'mobx-react-lite';
import { DROPDOWN_OPTIONS } from 'App/constants/card';
import AddCardModal from 'Components/Dashboard/components/AddCardModal';
import {useModal} from 'Components/Modal';
import { useModal } from 'Components/Modal';
import AddCardSelectionModal from "Components/Dashboard/components/AddCardSelectionModal";
import NewDashboardModal from "Components/Dashboard/components/DashboardList/NewDashModal";
function MetricViewHeader({siteId}: { siteId: string }) {
const {metricStore} = useStore();
function MetricViewHeader({ siteId }: { siteId: string }) {
const { metricStore } = useStore();
const filter = metricStore.filter;
const {showModal} = useModal();
const { showModal } = useModal();
const [showAddCardModal, setShowAddCardModal] = React.useState(false);
// Set the default sort order to 'desc'
useEffect(() => {
metricStore.updateKey('sort', { by: 'desc' });
}, [metricStore]);
return (
<div>
<div className='flex items-center justify-between px-6'>
<div className='flex items-baseline mr-3'>
<PageTitle title='Cards' className=''/>
<PageTitle title='Cards' className='' />
</div>
<div className='ml-auto flex items-center'>
<Button type='primary'
// onClick={() => showModal(<AddCardModal siteId={siteId}/>, {right: true})}
onClick={() => setShowAddCardModal(true)}
icon={<PlusOutlined />}
onClick={() => setShowAddCardModal(true)}
icon={<PlusOutlined />}
>Create Card</Button>
<div className='ml-4 w-1/4' style={{minWidth: 300}}>
<MetricsSearch/>
<div className='ml-4 w-1/4' style={{ minWidth: 300 }}>
<MetricsSearch />
</div>
</div>
</div>
@ -39,11 +43,11 @@ function MetricViewHeader({siteId}: { siteId: string }) {
<div className='border-y px-6 py-1 mt-2 flex items-center w-full justify-between'>
<div className='items-center flex gap-4'>
<Select
options={[{label: 'All Types', value: 'all'}, ...DROPDOWN_OPTIONS]}
options={[{ label: 'All Types', value: 'all' }, ...DROPDOWN_OPTIONS]}
name='type'
defaultValue={filter.type}
onChange={({value}) =>
metricStore.updateKey('filter', {...filter, type: value.value})
onChange={({ value }) =>
metricStore.updateKey('filter', { ...filter, type: value.value })
}
plain={true}
isSearchable={true}
@ -52,37 +56,25 @@ function MetricViewHeader({siteId}: { siteId: string }) {
<DashboardDropdown
plain={false}
onChange={(value: any) =>
metricStore.updateKey('filter', {...filter, dashboard: value})
metricStore.updateKey('filter', { ...filter, dashboard: value })
}
/>
</div>
<div className='flex items-center gap-2'>
<ListViewToggler/>
<div className='flex items-center gap-6'>
<ListViewToggler />
<Select
options={[
{label: 'Newest', value: 'desc'},
{label: 'Oldest', value: 'asc'}
]}
name='sort'
defaultValue={metricStore.sort.by}
onChange={({value}) => metricStore.updateKey('sort', {by: value.value})}
plain={true}
className='ml-4'
/>
<Toggler
label='My Cards'
checked={filter.showMine}
name='test'
className='font-medium mr-2'
onChange={() =>
metricStore.updateKey('filter', {...filter, showMine: !filter.showMine})
metricStore.updateKey('filter', { ...filter, showMine: !filter.showMine })
}
/>
</div>
{/*<AddCardSelectionModal open={showAddCardModal}/>*/}
<NewDashboardModal
onClose={() => setShowAddCardModal(false)}
open={showAddCardModal}
@ -95,8 +87,8 @@ function MetricViewHeader({siteId}: { siteId: string }) {
export default observer(MetricViewHeader);
function DashboardDropdown({onChange, plain = false}: { plain?: boolean; onChange: any }) {
const {dashboardStore, metricStore} = useStore();
function DashboardDropdown({ onChange, plain = false }: { plain?: boolean; onChange: any }) {
const { dashboardStore, metricStore } = useStore();
const dashboardOptions = dashboardStore.dashboards.map((i: any) => ({
key: i.id,
label: i.name,
@ -110,7 +102,7 @@ function DashboardDropdown({onChange, plain = false}: { plain?: boolean; onChang
plain={plain}
options={dashboardOptions}
value={metricStore.filter.dashboard}
onChange={({value}: any) => onChange(value)}
onChange={({ value }: any) => onChange(value)}
isMulti={true}
color='black'
/>
@ -118,23 +110,23 @@ function DashboardDropdown({onChange, plain = false}: { plain?: boolean; onChang
}
function ListViewToggler() {
const {metricStore} = useStore();
const { metricStore } = useStore();
const listView = useObserver(() => metricStore.listView);
return (
<div className='flex items-center'>
<Segmented
<Segmented
size='small'
options={[
{
label: <div className={'flex items-center gap-2'}>
<Icon name={'list-alt'} color={'inherit'}/>
<Icon name={'list-alt'} color={'inherit'} />
<div>List</div>
</div>,
value: 'list'
},
{
label: <div className={'flex items-center gap-2'}>
<Icon name={'grid'} color={'inherit'}/>
<Icon name={'grid'} color={'inherit'} />
<div>Grid</div>
</div>,
value: 'grid'

View file

@ -1,13 +1,21 @@
import React from 'react';
import React, { useState, useMemo } from 'react';
import { Checkbox, Table } from 'antd';
import MetricListItem from '../MetricListItem';
import classNames from 'classnames';
import { TablePaginationConfig, SorterResult } from 'antd/lib/table/interface';
interface Metric {
metricId: number;
name: string;
owner: string;
lastModified: string;
visibility: string;
}
interface Props {
list: any;
siteId: any;
selectedList: any;
toggleSelection?: (metricId: any) => void;
list: Metric[];
siteId: string;
selectedList: number[];
toggleSelection?: (metricId: number) => void;
toggleAll?: (e: any) => void;
disableSelection?: boolean;
allSelected?: boolean;
@ -16,6 +24,45 @@ interface Props {
const ListView: React.FC<Props> = (props: Props) => {
const { siteId, list, selectedList, toggleSelection, disableSelection = false, allSelected = false, toggleAll } = props;
const [sorter, setSorter] = useState<{ field: string; order: 'ascend' | 'descend' }>({
field: 'lastModified',
order: 'descend'
});
const [pagination, setPagination] = useState<TablePaginationConfig>({ current: 1, pageSize: 10 });
const sortedData = useMemo(() => {
return [...list].sort((a, b) => {
if (sorter.field === 'lastModified') {
return sorter.order === 'ascend'
? new Date(a.lastModified).getTime() - new Date(b.lastModified).getTime()
: new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime();
} else if (sorter.field === 'name') {
return sorter.order === 'ascend' ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name);
} else if (sorter.field === 'owner') {
return sorter.order === 'ascend' ? a.owner.localeCompare(b.owner) : b.owner.localeCompare(a.owner);
}
return 0;
});
}, [list, sorter]);
const paginatedData = useMemo(() => {
const start = (pagination.current! - 1) * pagination.pageSize!;
const end = start + pagination.pageSize!;
return sortedData.slice(start, end);
}, [sortedData, pagination]);
const handleTableChange = (
pagination: TablePaginationConfig,
filters: Record<string, (string | number | boolean)[] | null>,
sorter: SorterResult<Metric> | SorterResult<Metric>[]
) => {
const sortResult = sorter as SorterResult<Metric>;
setSorter({
field: sortResult.field as string,
order: sortResult.order as 'ascend' | 'descend'
});
setPagination(pagination);
};
const columns = [
{
@ -35,18 +82,18 @@ const ListView: React.FC<Props> = (props: Props) => {
dataIndex: 'name',
key: 'title',
className: 'cap-first',
sorter: (a: any, b: any) => a.name.localeCompare(b.name),
width: '40%',
render: (text: any, metric: any) => (
width:'35%',
sorter: true,
render: (text: string, metric: Metric) => (
<MetricListItem
key={metric.metricId}
metric={metric}
siteId={siteId}
disableSelection={disableSelection}
selected={selectedList.includes(parseInt(metric.metricId))}
selected={selectedList.includes(metric.metricId)}
toggleSelection={(e: any) => {
e.stopPropagation();
toggleSelection && toggleSelection(parseInt(metric.metricId));
toggleSelection && toggleSelection(metric.metricId);
}}
renderColumn="title"
/>
@ -57,9 +104,9 @@ const ListView: React.FC<Props> = (props: Props) => {
dataIndex: 'owner',
key: 'owner',
className: 'capitalize',
sorter: (a: any, b: any) => a.owner.localeCompare(b.owner),
width: '25%',
render: (text: any, metric: any) => (
width:'25%',
sorter: true,
render: (text: string, metric: Metric) => (
<MetricListItem
key={metric.metricId}
metric={metric}
@ -72,9 +119,8 @@ const ListView: React.FC<Props> = (props: Props) => {
title: 'Last Modified',
dataIndex: 'lastModified',
key: 'lastModified',
sorter: (a: any, b: any) => new Date(a.lastModified).getTime() - new Date(b.lastModified).getTime(),
width: '20%',
render: (text: any, metric: any) => (
sorter: true,
render: (text: string, metric: Metric) => (
<MetricListItem
key={metric.metricId}
metric={metric}
@ -88,7 +134,7 @@ const ListView: React.FC<Props> = (props: Props) => {
dataIndex: 'visibility',
key: 'visibility',
width: '10%',
render: (text: any, metric: any) => (
render: (text: string, metric: Metric) => (
<MetricListItem
key={metric.metricId}
metric={metric}
@ -97,14 +143,11 @@ const ListView: React.FC<Props> = (props: Props) => {
/>
),
},
{
title: '',
key: 'options',
className: 'text-right',
width: '5%',
align: 'right',
render: (text: any, metric: any) => (
render: (text: string, metric: Metric) => (
<MetricListItem
key={metric.metricId}
metric={metric}
@ -115,20 +158,16 @@ const ListView: React.FC<Props> = (props: Props) => {
},
];
const data = list.map((metric: any) => ({
...metric,
key: metric.metricId,
}));
return (
<Table
columns={columns}
dataSource={data}
dataSource={paginatedData}
rowKey="metricId"
onChange={handleTableChange}
rowSelection={
!disableSelection
? {
selectedRowKeys: selectedList.map((id: any) => id.toString()),
selectedRowKeys: selectedList.map((id: number) => id.toString()),
onChange: (selectedRowKeys) => {
selectedRowKeys.forEach((key) => {
toggleSelection && toggleSelection(parseInt(key));
@ -137,7 +176,11 @@ const ListView: React.FC<Props> = (props: Props) => {
}
: undefined
}
pagination={false}
pagination={{
current: pagination.current,
pageSize: pagination.pageSize,
total: sortedData.length,
}}
/>
);
};