diff --git a/src/app/(main)/websites/[id]/WebsiteDetails.tsx b/src/app/(main)/websites/[id]/WebsiteDetails.tsx
index 4d3a18e7..7d8d2d99 100644
--- a/src/app/(main)/websites/[id]/WebsiteDetails.tsx
+++ b/src/app/(main)/websites/[id]/WebsiteDetails.tsx
@@ -6,7 +6,7 @@ import FilterTags from 'components/metrics/FilterTags';
import useNavigation from 'components/hooks/useNavigation';
import { useWebsite } from 'components/hooks';
import WebsiteChart from './WebsiteChart';
-import WebsiteMenuView from './WebsiteMenuView';
+import WebsiteExpandedView from './WebsiteExpandedView';
import WebsiteHeader from './WebsiteHeader';
import WebsiteMetricsBar from './WebsiteMetricsBar';
import WebsiteTableView from './WebsiteTableView';
@@ -34,7 +34,7 @@ export default function WebsiteDetails({ websiteId }: { websiteId: string }) {
{website && (
<>
{!view && }
- {view && }
+ {view && }
>
)}
>
diff --git a/src/app/(main)/websites/[id]/WebsiteMenuView.module.css b/src/app/(main)/websites/[id]/WebsiteExpandedView.module.css
similarity index 100%
rename from src/app/(main)/websites/[id]/WebsiteMenuView.module.css
rename to src/app/(main)/websites/[id]/WebsiteExpandedView.module.css
diff --git a/src/app/(main)/websites/[id]/WebsiteMenuView.tsx b/src/app/(main)/websites/[id]/WebsiteExpandedView.tsx
similarity index 93%
rename from src/app/(main)/websites/[id]/WebsiteMenuView.tsx
rename to src/app/(main)/websites/[id]/WebsiteExpandedView.tsx
index 670ea469..e97cd002 100644
--- a/src/app/(main)/websites/[id]/WebsiteMenuView.tsx
+++ b/src/app/(main)/websites/[id]/WebsiteExpandedView.tsx
@@ -15,7 +15,7 @@ import SideNav from 'components/layout/SideNav';
import useNavigation from 'components/hooks/useNavigation';
import useMessages from 'components/hooks/useMessages';
import LinkButton from 'components/common/LinkButton';
-import styles from './WebsiteMenuView.module.css';
+import styles from './WebsiteExpandedView.module.css';
const views = {
url: PagesTable,
@@ -33,7 +33,7 @@ const views = {
query: QueryParametersTable,
};
-export default function WebsiteMenuView({
+export default function WebsiteExpandedView({
websiteId,
websiteDomain,
}: {
@@ -113,11 +113,11 @@ export default function WebsiteMenuView({
const DetailsComponent = views[view] || (() => null);
- const handleChange = view => {
+ const handleChange = (view: any) => {
router.push(makeUrl({ view }));
};
- const renderValue = value => items.find(({ key }) => key === value)?.label;
+ const renderValue = (value: string) => items.find(({ key }) => key === value)?.label;
return (
@@ -146,9 +146,10 @@ export default function WebsiteMenuView({
websiteDomain={websiteDomain}
limit={false}
animate={false}
- showFilters={true}
virtualize={true}
itemCount={25}
+ allowFilter={true}
+ allowSearch={true}
/>
diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts
index d8a49331..efaa717f 100644
--- a/src/components/hooks/useDateRange.ts
+++ b/src/components/hooks/useDateRange.ts
@@ -46,7 +46,7 @@ export function useDateRange(websiteId?: string) {
};
return [dateRange, saveDateRange] as [
- { startDate: Date; endDate: Date },
+ { startDate: Date; endDate: Date; modified?: number },
(value: string | DateRange) => void,
];
}
diff --git a/src/components/hooks/useFormat.ts b/src/components/hooks/useFormat.ts
index f804eb72..06585e49 100644
--- a/src/components/hooks/useFormat.ts
+++ b/src/components/hooks/useFormat.ts
@@ -18,14 +18,19 @@ export function useFormat() {
};
const formatRegion = (value: string): string => {
- return regions[value] ? regions[value] : value;
+ const [country] = value.split('-');
+ return regions[value] ? `${regions[value]}, ${countryNames[country]}` : value;
+ };
+
+ const formatCity = (value: string, country?: string): string => {
+ return `${value}, ${countryNames[country]}`;
};
const formatDevice = (value: string): string => {
return formatMessage(labels[value] || labels.unknown);
};
- const formatValue = (value: string, type: string): string => {
+ const formatValue = (value: string, type: string, data?: { [key: string]: any }): string => {
switch (type) {
case 'browser':
return formatBrowser(value);
@@ -33,6 +38,8 @@ export function useFormat() {
return formatCountry(value);
case 'region':
return formatRegion(value);
+ case 'city':
+ return formatCity(value, data?.country);
case 'device':
return formatDevice(value);
default:
diff --git a/src/components/layout/SideNav.tsx b/src/components/layout/SideNav.tsx
index f38bdba0..0b5c9856 100644
--- a/src/components/layout/SideNav.tsx
+++ b/src/components/layout/SideNav.tsx
@@ -9,7 +9,7 @@ export interface SideNavProps {
items: any[];
shallow?: boolean;
scroll?: boolean;
- className?: boolean;
+ className?: string;
onSelect?: () => void;
}
diff --git a/src/components/metrics/CitiesTable.tsx b/src/components/metrics/CitiesTable.tsx
index 69b89962..067e07e9 100644
--- a/src/components/metrics/CitiesTable.tsx
+++ b/src/components/metrics/CitiesTable.tsx
@@ -11,8 +11,8 @@ export function CitiesTable(props: MetricsTableProps) {
const countryNames = useCountryNames(locale);
const renderLabel = (city: string, country: string) => {
- const name = countryNames[country];
- return name ? `${city}, ${name}` : city;
+ const countryName = countryNames[country];
+ return countryName ? `${city}, ${countryName}` : city;
};
const renderLink = ({ x: city, country }) => {
diff --git a/src/components/metrics/MetricsTable.module.css b/src/components/metrics/MetricsTable.module.css
index c00e4356..f04d9ae4 100644
--- a/src/components/metrics/MetricsTable.module.css
+++ b/src/components/metrics/MetricsTable.module.css
@@ -6,13 +6,33 @@
flex: 1;
}
+.actions {
+ display: flex;
+ gap: 20px;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
+
.footer {
display: flex;
justify-content: center;
}
+.search {
+ max-width: 300px;
+}
+
@media only screen and (max-width: 992px) {
.container {
min-height: auto;
}
+
+ .actions {
+ flex-direction: column;
+ }
+
+ .search {
+ max-width: 100%;
+ }
}
diff --git a/src/components/metrics/MetricsTable.tsx b/src/components/metrics/MetricsTable.tsx
index d4ad793d..48beac68 100644
--- a/src/components/metrics/MetricsTable.tsx
+++ b/src/components/metrics/MetricsTable.tsx
@@ -1,5 +1,5 @@
-import { useMemo } from 'react';
-import { Loading, Icon, Text } from 'react-basics';
+import { ReactNode, useMemo, useState } from 'react';
+import { Loading, Icon, Text, SearchField } from 'react-basics';
import classNames from 'classnames';
import useApi from 'components/hooks/useApi';
import { percentFilter } from 'lib/filters';
@@ -12,6 +12,7 @@ import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
import Icons from 'components/icons';
import useMessages from 'components/hooks/useMessages';
import useLocale from 'components/hooks/useLocale';
+import useFormat from 'components//hooks/useFormat';
import styles from './MetricsTable.module.css';
export interface MetricsTableProps extends ListTableProps {
@@ -22,6 +23,9 @@ export interface MetricsTableProps extends ListTableProps {
limit?: number;
delay?: number;
onDataLoad?: (data: any) => void;
+ onSearch?: (search: string) => void;
+ allowSearch?: boolean;
+ children?: ReactNode;
}
export function MetricsTable({
@@ -32,8 +36,12 @@ export function MetricsTable({
limit,
onDataLoad,
delay = null,
+ allowSearch = false,
+ children,
...props
}: MetricsTableProps) {
+ const [search, setSearch] = useState('');
+ const { formatValue } = useFormat();
const [{ startDate, endDate, modified }] = useDateRange(websiteId);
const {
makeUrl,
@@ -42,7 +50,6 @@ export function MetricsTable({
const { formatMessage, labels } = useMessages();
const { get, useQuery } = useApi();
const { dir } = useLocale();
-
const { data, isLoading, isFetched, error } = useQuery({
queryKey: [
'websites:metrics',
@@ -94,24 +101,43 @@ export function MetricsTable({
}
}
+ if (search) {
+ items = items.filter(({ x, ...data }) => {
+ const value = formatValue(x, type, data);
+
+ return value.toLowerCase().includes(search.toLowerCase());
+ });
+ }
+
items = percentFilter(items);
if (limit) {
- items = items.filter((e, i) => i < limit);
+ items = items.slice(0, limit - 1);
}
return items;
}
return [];
- }, [data, error, dataFilter, limit]);
+ }, [data, dataFilter, search, limit, formatValue, type]);
return (
- {!data && isLoading && !isFetched &&
}
{error &&
}
+
+ {allowSearch && (
+
+ )}
+ {children}
+
{data && !error && (
)}
+ {!data && isLoading && !isFetched &&
}
{data && !error && limit && (
diff --git a/src/components/metrics/OSTable.tsx b/src/components/metrics/OSTable.tsx
index c39cba22..102bafd3 100644
--- a/src/components/metrics/OSTable.tsx
+++ b/src/components/metrics/OSTable.tsx
@@ -1,4 +1,4 @@
-import MetricsTable from './MetricsTable';
+import MetricsTable, { MetricsTableProps } from './MetricsTable';
import FilterLink from 'components/common/FilterLink';
import useMessages from 'components/hooks/useMessages';
@@ -8,7 +8,7 @@ const names = {
'Sun OS': 'SunOS',
};
-export function OSTable({ websiteId, limit }: { websiteId: string; limit?: number }) {
+export function OSTable(props: MetricsTableProps) {
const { formatMessage, labels } = useMessages();
function renderLink({ x: os }) {
@@ -28,12 +28,11 @@ export function OSTable({ websiteId, limit }: { websiteId: string; limit?: numbe
return (
);
}
diff --git a/src/components/metrics/PagesTable.tsx b/src/components/metrics/PagesTable.tsx
index 23676467..11379a2e 100644
--- a/src/components/metrics/PagesTable.tsx
+++ b/src/components/metrics/PagesTable.tsx
@@ -6,10 +6,10 @@ import useNavigation from 'components/hooks/useNavigation';
import { emptyFilter } from 'lib/filters';
export interface PagesTableProps extends MetricsTableProps {
- showFilters?: boolean;
+ allowFilter?: boolean;
}
-export function PagesTable({ showFilters, ...props }: PagesTableProps) {
+export function PagesTable({ allowFilter, ...props }: PagesTableProps) {
const {
router,
makeUrl,
@@ -37,17 +37,16 @@ export function PagesTable({ showFilters, ...props }: PagesTableProps) {
};
return (
- <>
- {showFilters && }
-
- >
+
+ {allowFilter && }
+
);
}
diff --git a/src/components/metrics/QueryParametersTable.tsx b/src/components/metrics/QueryParametersTable.tsx
index 65cac664..90489460 100644
--- a/src/components/metrics/QueryParametersTable.tsx
+++ b/src/components/metrics/QueryParametersTable.tsx
@@ -13,9 +13,9 @@ const filters = {
};
export function QueryParametersTable({
- showFilters,
+ allowFilter,
...props
-}: { showFilters: boolean } & MetricsTableProps) {
+}: { allowFilter: boolean } & MetricsTableProps) {
const [filter, setFilter] = useState(FILTER_COMBINED);
const { formatMessage, labels } = useMessages();
@@ -28,27 +28,26 @@ export function QueryParametersTable({
];
return (
- <>
- {showFilters && }
-
- filter === FILTER_RAW ? (
- x
- ) : (
-
-
{safeDecodeURI(p)}
-
{safeDecodeURI(v)}
-
- )
- }
- delay={0}
- />
- >
+
+ filter === FILTER_RAW ? (
+ x
+ ) : (
+
+
{safeDecodeURI(p)}
+
{safeDecodeURI(v)}
+
+ )
+ }
+ delay={0}
+ >
+ {allowFilter && }
+
);
}