Skip to content

Commit

Permalink
Merge pull request #620 from tailwarden/feature/tech-966
Browse files Browse the repository at this point in the history
Export CSV Component
  • Loading branch information
mlabouardy authored Mar 17, 2023
2 parents d79cbe8 + 279259f commit d4f1170
Show file tree
Hide file tree
Showing 24 changed files with 700 additions and 434 deletions.
4 changes: 3 additions & 1 deletion dashboard/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function Button({

const primary = `${base} bg-gradient-to-br from-primary bg-secondary hover:bg-primary active:from-secondary active:bg-secondary text-white disabled:from-primary disabled:bg-secondary disabled:opacity-50`;

const secondary = `${base} hover:bg-black-100 active:bg-black-150 text-black-400 disabled:bg-black-100 disabled:opacity-50`;
const secondary = `${base} hover:bg-black-100 text-black-900 active:bg-black-150 text-black-400 disabled:hover:bg-transparent disabled:opacity-30`;

const bulk = `${base} bg-white hover:bg-komiser-200 active:bg-komiser-300 text-secondary disabled:bg-white disabled:opacity-50`;

Expand Down Expand Up @@ -94,6 +94,7 @@ function Button({
type={type}
className={handleStyle()}
disabled={disabled || loading}
data-testid={style}
>
{loading && (
<>
Expand All @@ -102,6 +103,7 @@ function Button({
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
data-testid="loading-spinner"
>
<circle
className="opacity-25"
Expand Down
38 changes: 38 additions & 0 deletions dashboard/components/export-csv/ExportCSV.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useRouter } from 'next/router';
import { useState } from 'react';
import settingsService from '../../services/settingsService';
import { ToastProps } from '../toast/hooks/useToast';
import ExportCSVButton from './ExportCSVButton';

type ExportCSVProps = {
displayInTable?: boolean;
setToast: (toast: ToastProps | undefined) => void;
};

function ExportCSV({ displayInTable = false, setToast }: ExportCSVProps) {
const router = useRouter();

function exportCSV(id?: string) {
settingsService.exportCSV(id);
setToast({
hasError: false,
title: 'CSV exported',
message: 'The download of the CSV file should begin shortly.'
});
}

const isFilteredList =
Object.keys(router.query).length > 0 && !router.query.view;
const id = router.query.view ? router.query.view.toString() : undefined;

return (
<ExportCSVButton
id={id}
disabled={isFilteredList}
displayInTable={displayInTable}
exportCSV={exportCSV}
/>
);
}

export default ExportCSV;
29 changes: 29 additions & 0 deletions dashboard/components/export-csv/ExportCSVButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Meta, StoryObj } from '@storybook/react';
import ExportCSVButton from './ExportCSVButton';

const meta: Meta<typeof ExportCSVButton> = {
title: 'Komiser/Export CSV',
component: ExportCSVButton,
tags: ['autodocs'],
argTypes: {},
decorators: [
Story => (
<div className="flex items-center justify-center">
<div className="min-w-24 relative">
<Story />
</div>
</div>
)
]
};

export default meta;
type Story = StoryObj<typeof ExportCSVButton>;

export const Primary: Story = {
args: {
disabled: false,
displayInTable: false,
exportCSV: () => {}
}
};
27 changes: 27 additions & 0 deletions dashboard/components/export-csv/ExportCSVButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { render, screen } from '@testing-library/react';
import ExportCSVButton from './ExportCSVButton';

const props = {
id: undefined,
disabled: false,
displayInTable: false,
exportCSV: jest.fn()
};

describe('Export CSV component', () => {
it('should render without crashing', () => {
render(<ExportCSVButton {...props} />);
});

it('should render the correct button props if displayInTable is true', () => {
render(<ExportCSVButton {...props} displayInTable={true} />);
const button = screen.getByTestId('secondary');
expect(button).toBeInTheDocument();
});

it('should display the auxiliary info in the tooltip if disabled is true', () => {
render(<ExportCSVButton {...props} disabled={true} />);
const tooltip = screen.getByRole('tooltip');
expect(tooltip).toBeInTheDocument();
});
});
44 changes: 44 additions & 0 deletions dashboard/components/export-csv/ExportCSVButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Button from '../button/Button';
import DownloadIcon from '../icons/DownloadIcon';
import Tooltip from '../tooltip/Tooltip';

type ExportCSVButtonProps = {
id?: string;
disabled: boolean;
displayInTable: boolean;
exportCSV: (id?: string) => void;
};

function ExportCSVButton({
id,
disabled,
displayInTable,
exportCSV
}: ExportCSVButtonProps) {
return (
<>
<div className="peer flex flex-col">
<Button
style={displayInTable ? 'secondary' : 'ghost'}
size="sm"
align="left"
gap="md"
transition={false}
disabled={disabled}
onClick={() => exportCSV(id)}
>
<DownloadIcon width={24} height={24} />
Download CSV
</Button>
</div>
{disabled && (
<Tooltip top="sm" align="right" width="lg">
This feature isn&apos;t available yet. To download data from a
filtered table, save it as a view and download it from there.
</Tooltip>
)}
</>
);
}

export default ExportCSVButton;
34 changes: 34 additions & 0 deletions dashboard/components/icons/AlertIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { SVGProps } from 'react';

const AlertIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M12.02 2.91c-3.31 0-6 2.69-6 6v2.89c0 .61-.26 1.54-.57 2.06L4.3 15.77c-.71 1.18-.22 2.49 1.08 2.93 4.31 1.44 8.96 1.44 13.27 0 1.21-.4 1.74-1.83 1.08-2.93l-1.15-1.91c-.3-.52-.56-1.45-.56-2.06V8.91c0-3.3-2.7-6-6-6z"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M13.87 3.2a6.754 6.754 0 00-3.7 0c.29-.74 1.01-1.26 1.85-1.26.84 0 1.56.52 1.85 1.26z"
></path>
<path
stroke="currentColor"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M15.02 19.06c0 1.65-1.35 3-3 3-.82 0-1.58-.34-2.12-.88a3.01 3.01 0 01-.88-2.12"
></path>
</svg>
);

export default AlertIcon;
27 changes: 27 additions & 0 deletions dashboard/components/icons/BookmarkIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { SVGProps } from 'react';

const BookmarkIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M16 8.99v11.36c0 1.45-1.04 2.06-2.31 1.36l-3.93-2.19c-.42-.23-1.1-.23-1.52 0l-3.93 2.19c-1.27.7-2.31.09-2.31-1.36V8.99c0-1.71 1.4-3.11 3.11-3.11h7.78c1.71 0 3.11 1.4 3.11 3.11z"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 5.11v11.36c0 1.45-1.04 2.06-2.31 1.36L16 15.77V8.99c0-1.71-1.4-3.11-3.11-3.11H8v-.77C8 3.4 9.4 2 11.11 2h7.78C20.6 2 22 3.4 22 5.11zM7 12h4M9 14v-4"
></path>
</svg>
);

export default BookmarkIcon;
21 changes: 21 additions & 0 deletions dashboard/components/icons/ChevronDownIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SVGProps } from 'react';

const ChevronDownIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M19.92 8.95l-6.52 6.52c-.77.77-2.03.77-2.8 0L4.08 8.95"
></path>
</svg>
);

export default ChevronDownIcon;
20 changes: 20 additions & 0 deletions dashboard/components/icons/CloseIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { SVGProps } from 'react';

const CloseIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M7.757 16.243l8.486-8.486M16.243 16.243L7.757 7.757"
></path>
</svg>
);

export default CloseIcon;
20 changes: 20 additions & 0 deletions dashboard/components/icons/DeleteIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { SVGProps } from 'react';

const DeleteIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M21 5.98c-3.33-.33-6.68-.5-10.02-.5-1.98 0-3.96.1-5.94.3L3 5.98M8.5 4.97l.22-1.31C8.88 2.71 9 2 10.69 2h2.62c1.69 0 1.82.75 1.97 1.67l.22 1.3M18.85 9.14l-.65 10.07C18.09 20.78 18 22 15.21 22H8.79C6 22 5.91 20.78 5.8 19.21L5.15 9.14M10.33 16.5h3.33M9.5 12.5h5"
></path>
</svg>
);

export default DeleteIcon;
34 changes: 34 additions & 0 deletions dashboard/components/icons/DownloadIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { SVGProps } from 'react';

const DownloadIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M9 11.5v6l2-2M9 17.5l-2-2"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 10.5v5c0 5-2 7-7 7H9c-5 0-7-2-7-7v-6c0-5 2-7 7-7h5"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 10.5h-4c-3 0-4-1-4-4v-4l8 8z"
></path>
</svg>
);

export default DownloadIcon;
27 changes: 27 additions & 0 deletions dashboard/components/icons/DuplicateIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { SVGProps } from 'react';

const DuplicateIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M16 12.9v4.2c0 3.5-1.4 4.9-4.9 4.9H6.9C3.4 22 2 20.6 2 17.1v-4.2C2 9.4 3.4 8 6.9 8h4.2c3.5 0 4.9 1.4 4.9 4.9z"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M22 6.9v4.2c0 3.5-1.4 4.9-4.9 4.9H16v-3.1C16 9.4 14.6 8 11.1 8H8V6.9C8 3.4 9.4 2 12.9 2h4.2C20.6 2 22 3.4 22 6.9z"
></path>
</svg>
);

export default DuplicateIcon;
28 changes: 28 additions & 0 deletions dashboard/components/icons/EditIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { SVGProps } from 'react';

const EditIcon = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M11 2H9C4 2 2 4 2 9v6c0 5 2 7 7 7h6c5 0 7-2 7-7v-2"
></path>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="1.5"
d="M16.04 3.02L8.16 10.9c-.3.3-.6.89-.66 1.32l-.43 3.01c-.16 1.09.61 1.85 1.7 1.7l3.01-.43c.42-.06 1.01-.36 1.32-.66l7.88-7.88c1.36-1.36 2-2.94 0-4.94-2-2-3.58-1.36-4.94 0zM14.91 4.15a7.144 7.144 0 004.94 4.94"
></path>
</svg>
);

export default EditIcon;
Loading

0 comments on commit d4f1170

Please sign in to comment.