Skip to content

Commit

Permalink
Merge pull request #4767 from relative-ci/improve-metrics-table-export
Browse files Browse the repository at this point in the history
Improve metrics table export
  • Loading branch information
vio authored Oct 9, 2024
2 parents af787f2 + 996cd2e commit 3179af7
Show file tree
Hide file tree
Showing 15 changed files with 157 additions and 101 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { useHistory } from 'react-router-dom';
import {
Expand Down Expand Up @@ -73,8 +73,10 @@ export const BundleAssetsTotals = ({
);

const exportDialog = useDialogState();
const [exportSourceType, setExportSourceType] = useState(undefined);

const handleExportClick = useCallback(() => {
const handleExportClick = useCallback((sourceType) => {
setExportSourceType(sourceType);
exportDialog.toggle();
}, []);

Expand Down Expand Up @@ -120,7 +122,13 @@ export const BundleAssetsTotals = ({
</Stack>

<Dialog title={I18N.EXPORT} width="wide" state={exportDialog}>
{exportDialog.open && <MetricsTableExport items={items} download="bundle-stats--totals" />}
{exportDialog.open && (
<MetricsTableExport
items={items}
initialSourceType={exportSourceType}
download="bundle-stats--totals"
/>
)}
</Dialog>
</>
);
Expand Down
14 changes: 11 additions & 3 deletions packages/ui/src/components/bundle-assets/bundle-assets.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import get from 'lodash/get';
Expand Down Expand Up @@ -316,8 +316,10 @@ export const BundleAssets = (props) => {
}, [allItems, entryId]);

const exportDialog = useDialogState();
const [exportSourceType, setExportSourceType] = useState(undefined);

const handleExportClick = useCallback(() => {
const handleExportClick = useCallback((sourceType) => {
setExportSourceType(sourceType);
exportDialog.toggle();
}, []);

Expand Down Expand Up @@ -396,7 +398,13 @@ export const BundleAssets = (props) => {
)}

<Dialog title={I18N.EXPORT} width="wide" state={exportDialog}>
{exportDialog.open && <MetricsTableExport items={items} download="bundle-stats--assets" />}
{exportDialog.open && (
<MetricsTableExport
items={items}
initialSourceType={exportSourceType}
download="bundle-stats--assets"
/>
)}
</Dialog>
</>
);
Expand Down
14 changes: 11 additions & 3 deletions packages/ui/src/components/bundle-modules/bundle-modules.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import cx from 'classnames';
import { SECTIONS, COMPONENT, type Job, ReportMetricRow } from '@bundle-stats/utils';
import escapeRegExp from 'lodash/escapeRegExp';
Expand Down Expand Up @@ -255,8 +255,10 @@ export const BundleModules = (props: BundleModulesProps) => {
}, [allItems, entryId]);

const exportDialog = useDialogState();
const [exportSourceType, setExportSourceType] = useState<string | undefined>(undefined);

const handleExportClick = useCallback(() => {
const handleExportClick = useCallback((sourceType: string) => {
setExportSourceType(sourceType);
exportDialog.toggle();
}, []);

Expand Down Expand Up @@ -374,7 +376,13 @@ export const BundleModules = (props: BundleModulesProps) => {
)}

<Dialog title={I18N.EXPORT} width="wide" state={exportDialog}>
{exportDialog.open && <MetricsTableExport items={items} download="bundle-stats--modules"/>}
{exportDialog.open && (
<MetricsTableExport
items={items}
initialSourceType={exportSourceType}
download="bundle-stats--modules"
/>
)}
</Dialog>
</>
);
Expand Down
14 changes: 11 additions & 3 deletions packages/ui/src/components/bundle-packages/bundle-packages.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import escapeRegExp from 'lodash/escapeRegExp';
Expand Down Expand Up @@ -264,8 +264,10 @@ export const BundlePackages = (props) => {
}, [allItems, entryId]);

const exportDialog = useDialogState();
const [exportSourceType, setExportSourceType] = useState(undefined);

const handleExportClick = useCallback(() => {
const handleExportClick = useCallback((sourceType) => {
setExportSourceType(sourceType);
exportDialog.toggle();
}, []);

Expand Down Expand Up @@ -338,7 +340,13 @@ export const BundlePackages = (props) => {
)}

<Dialog title={I18N.EXPORT} width="wide" state={exportDialog}>
{exportDialog.open && <MetricsTableExport items={items} download="bundle-stats--packages"/>}
{exportDialog.open && (
<MetricsTableExport
items={items}
initialSourceType={exportSourceType}
download="bundle-stats--packages"
/>
)}
</Dialog>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { useState } from 'react';
import type { ReportMetricRow } from '@bundle-stats/utils';

import { Stack } from '../../layout/stack';
import { Tabs } from '../../ui/tabs';
import { Tabs, TabItem } from '../../ui/tabs';
import { PreviewSource } from '../preview-source';

const generateSourceJSON = (items: Array<ReportMetricRow>): string => {
Expand Down Expand Up @@ -49,49 +49,58 @@ const generateSourceCSV = (items: Array<ReportMetricRow>): string => {
return output.join('\r');
};

const SOURCES = [
{
const SOURCES = {
csv: {
label: 'CSV',
transformFn: generateSourceCSV,
extension: 'csv',
extension: '.csv',
},
{
json: {
label: 'JSON',
transformFn: generateSourceJSON,
extension: 'json',
extension: '.json',
},
];
};

const SOURCE_ENTRIES = Object.entries(SOURCES);
const SOURCE_KEYS = Object.keys(SOURCES);

type MetricsTableExportProps = {
items: Array<ReportMetricRow>;
initialSourceType?: string;
download: string;
} & ComponentProps<typeof Stack>;

export const MetricsTableExport = (props: MetricsTableExportProps) => {
const { items, download, ...restProps } = props;
const [selectedId, setSelectedId] = useState(SOURCES[0].label);
const { initialSourceType = SOURCE_KEYS[0], items, download, ...restProps } = props;
const [selectedSourceType, setSelectedSourceType] = useState(initialSourceType);

return (
<Stack space="small" {...restProps}>
<Tabs>
{SOURCES.map((source) => (
<Tabs.Item
onClick={() => setSelectedId(source.label)}
isTabActive={selectedId === source.label}
key={source.label}
{SOURCE_ENTRIES.map(([sourceId, source]) => (
<TabItem
onClick={() => setSelectedSourceType(sourceId)}
isTabActive={selectedSourceType === sourceId}
id={`metrics-table-export-tab-${sourceId}`}
aria-controls={`metrics-table-export-panel-${sourceId}`}
key={sourceId}
>
{source.label}
</Tabs.Item>
</TabItem>
))}
</Tabs>
<div>
{SOURCES.map(
(source) =>
selectedId === source.label && (
{SOURCE_ENTRIES.map(
([sourceId, source]) =>
selectedSourceType === sourceId && (
<PreviewSource
source={source.transformFn(items)}
rows={20}
download={`${download}.${source.extension}`}
download={`${download}${source.extension}`}
role="tabpanel"
id={`metrics-table-export-panel-${sourceId}`}
aria-labelledby={`metrics-table-export-tab-${sourceId}`}
key={source.label}
/>
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.group + .group {
margin-top: calc(var(--space-xxxsmall) / 2);
padding-top: calc(var(--space-xxxsmall) / 2);
border-top: 1px solid var(--color-outline);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@ import React from 'react';

import I18N from '../../i18n';
import { Dropdown, DropdownItem } from '../../ui/dropdown';
import { Separator } from '../../layout/separator';
import css from './metrics-table-options.module.css';

type MetricsTableOptionsProps = {
onViewAllClick?: () => void;
onResetClick?: () => void;
onExportClick?: () => void;
onExportClick?: (sourceType: string) => void;
} & ComponentProps<typeof Dropdown>;

export const MetricsTableOptions = (props: MetricsTableOptionsProps) => {
const { onViewAllClick, onResetClick, onExportClick, ...restProps } = props;

return (
<Dropdown glyph="more-vertical" {...restProps}>
{onResetClick && <DropdownItem onClick={onResetClick}>{I18N.RESET_FILTERS}</DropdownItem>}
{onViewAllClick && <DropdownItem onClick={onViewAllClick}>{I18N.VIEW_ALL}</DropdownItem>}
{((onResetClick || onViewAllClick) && onExportClick) && <Separator />}
{onExportClick && <DropdownItem onClick={onExportClick}>{I18N.EXPORT}</DropdownItem>}
<div className={css.group}>
{onResetClick && <DropdownItem onClick={onResetClick}>{I18N.RESET_FILTERS}</DropdownItem>}
{onViewAllClick && <DropdownItem onClick={onViewAllClick}>{I18N.VIEW_ALL}</DropdownItem>}
</div>
<div className={css.group}>
{onExportClick && (
<>
<DropdownItem onClick={() => onExportClick('csv')}>{I18N.EXPORT_CSV}</DropdownItem>
<DropdownItem onClick={() => onExportClick('json')}>{I18N.EXPORT_JSON}</DropdownItem>
</>
)}
</div>
</Dropdown>
);
};
2 changes: 2 additions & 0 deletions packages/ui/src/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export default {
RESET_FILTERS: 'Reset filters',
VIEW_ALL: 'View all entries',
EXPORT: 'Export',
EXPORT_CSV: 'Export CSV',
EXPORT_JSON: 'Export JSON',

COPY_TO_CLIPBOARD: 'Copy to clipboard',
COPY_TO_CLIPBOARD_DONE: 'Copied to clipboard',
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/ui/tabs/index.js

This file was deleted.

1 change: 1 addition & 0 deletions packages/ui/src/ui/tabs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './tabs';
39 changes: 0 additions & 39 deletions packages/ui/src/ui/tabs/tabs.jsx

This file was deleted.

12 changes: 6 additions & 6 deletions packages/ui/src/ui/tabs/tabs.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
}

.item {
appearance: none;
background: none;
border: 0;
position: relative;
display: inline-block;
padding: var(--space-xsmall) var(--space-small);
color: var(--color-text-ultra-light);
font-weight: bold;
text-decoration: none;
cursor: default;
transition: var(--ui-transition-out);
}

.item::after {
Expand All @@ -27,8 +30,9 @@
.item:hover,
.item:active,
.item:focus {
color: var(--color-primary-dark);
color: var(--color-primary);
outline: none;
transition: var(--ui-transition-out);
}

.item:hover::after,
Expand All @@ -44,7 +48,3 @@
.itemActive::after {
background: currentColor;
}

.item + .item {
_margin-left: var(--space-medium);
}
18 changes: 0 additions & 18 deletions packages/ui/src/ui/tabs/tabs.stories.jsx

This file was deleted.

25 changes: 25 additions & 0 deletions packages/ui/src/ui/tabs/tabs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';

import { getWrapperDecorator } from '../../stories';
import { Tabs, TabItem } from '.';

const meta: Meta<typeof Tabs> = {
title: 'UI/Tabs',
component: Tabs,
decorators: [getWrapperDecorator()],
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<Tabs>
<TabItem isTabActive>Option A</TabItem>
<TabItem>Option B</TabItem>
<TabItem>Option C</TabItem>
</Tabs>
),
};
Loading

0 comments on commit 3179af7

Please sign in to comment.