Skip to content

Commit

Permalink
support for downloading as csv via data table manager
Browse files Browse the repository at this point in the history
  • Loading branch information
aswinshenoy committed Feb 7, 2024
1 parent 58bf26d commit cb52ed3
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 25 deletions.
74 changes: 70 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chaya-ui",
"version": "1.0.0-beta.76",
"version": "1.0.0-beta.77",
"description": "Modern, Functional Design System & Components for React",
"scripts": {
"tailwind": "tailwindcss -i ./src/style.scss -o ./dist/style.css -c ./tailwind.config.cjs",
Expand Down Expand Up @@ -68,6 +68,7 @@
"@storybook/testing-library": "^0.2.2",
"@storybook/theming": "^7.6.4",
"@types/color": "^3.0.3",
"@types/papaparse": "^5.3.14",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@types/webappsec-credential-management": "^0.6.4",
Expand All @@ -84,9 +85,10 @@
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-react": "^7.32.1",
"eslint-plugin-storybook": "^0.6.15",
"flatten-anything": "^3.0.5",
"immer": "^9.0.21",
"loadash": "^1.0.0",
"nanoid": "5.0.3",
"papaparse": "^5.4.1",
"postcss": "^8.4.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
23 changes: 20 additions & 3 deletions src/components/DataTableManager.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client';
import React, { useState, useEffect } from 'react';
import Papa from 'papaparse';
import { flatten } from 'flatten-anything';

import Close from '../utils/icons/close';
import Filter from '../utils/icons/filter';
Expand Down Expand Up @@ -58,7 +60,7 @@ export type DataTableManagerProps = {
isFilteringInitialised?: boolean,

// download
onDownload?: () => void,
onDownload?: () => Promise<object[]> | object[],
isDownloadLoading?: boolean,

// create
Expand Down Expand Up @@ -109,6 +111,21 @@ const DataTableManager = ({
const [_keyword, _setKeyword] = useState(keyword || '');
const [showFilters, setShowFilters] = useState(isFilteringInitialised);

const handleDownload = async () => {
if (typeof onDownload !== 'function')
return;
const data = await onDownload();
if (!data) return;
const csv = Papa.unparse(data?.map((i) => flatten(i)));
const csvData = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const csvURL = window.URL.createObjectURL(csvData);
const link = document.createElement('a');
link.setAttribute('href', csvURL);
link.setAttribute('download', `${labels.label || 'data'}_${new Date().getTime()}.csv`);
document.body.appendChild(link);
link.click();
};

useEffect(() => {
_setKeyword(keyword || '');
}, [keyword]);
Expand Down Expand Up @@ -199,7 +216,7 @@ const DataTableManager = ({
type="button"
variant="minimal"
color="shade"
onClick={onDownload}
onClick={handleDownload}
isLoading={isDownloadLoading}
isDisabled={isDownloadLoading}
>
Expand Down Expand Up @@ -297,7 +314,7 @@ const DataTableManager = ({
onClick={onCancelSelections}
/>
</div>
<div className="dsr-w-full md:dsr-w-1/2 lg:dsr-w-2/3 dsr-px-2 dsr-py-2 dsr-flex dsr-items-center dsr-justify-end dsr-gap-1">
<div className="dsr-w-full md:dsr-w-1/2 lg:dsr-w-2/3 dsr-px-2 dsr-py-2 dsr-flex dsr-items-center dsr-justify-end dsr-gap-2">
{selectionActions?.filter((a) => !a.isHidden).map((a) => (
<Button
variant="minimal"
Expand Down
38 changes: 27 additions & 11 deletions src/components/DropdownFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SearchBox from './SearchBox';
import Dropdown from './Dropdown';
import ListViewItem from './ListView/item';
import { IconInputType } from './Icon';
import SkeletonItem from './SkeletonItem';

const defaultLabels = {
searchPlaceholder: 'Search',
Expand Down Expand Up @@ -68,7 +69,10 @@ const DropdownRender = ({

useEffect(onLoad, []);

const availableOptions = options ? options.filter((f) => keyword.length == 0 || f.label.toLowerCase().startsWith(keyword.toLowerCase())) : [];
const availableOptions =
options ?
options.filter((f) => keyword.length == 0 || f.label.toLowerCase().startsWith(keyword.toLowerCase()))
: [];

useEffect(() => {
optionRefs.current = Array(availableOptions.length).fill(null).map(() => React.createRef());
Expand Down Expand Up @@ -134,16 +138,28 @@ const DropdownRender = ({
setKeyword={setKeyword}
/>
</div>
<div className="dsr-w-full dsr-px-2 dsr-py-1 dsr-bg-background dsr-border-b dsr-border-neutral-200/50">
<span className="dsr-opacity-80 dsr-uppercase dsr-font-semibold dsr-text-xs">
{labels.optionsTitle}
</span>
</div>
<div className="dsr-max-h-[30vh] dsr-overflow-y-auto">
{labels.optionsTitle?.length > 0 ? (
<div className="dsr-w-full dsr-px-2 dsr-py-1 dsr-bg-background dsr-border-b dsr-border-neutral-200/50">
<span className="dsr-opacity-80 dsr-uppercase dsr-font-semibold dsr-text-xs">
{labels.optionsTitle}
</span>
</div>
) : null}
<div
className={clsx([
!(labels.optionsTitle?.length > 0) && 'dsr-border-t dsr-border-neutral-200/50',
'dsr-max-h-[30vh] dsr-overflow-y-auto',
])}
>
{isFetching ? (
<div>
Fetching
</div>
<ul>
{Array.from({ length: 4 }).map((_, index) => (
<div key={index} className="dsr-flex dsr-items-center dsr-p-2 dsr-gap-2">
<SkeletonItem variant="wave" w={24} h={24} />
<SkeletonItem variant="wave" w="80%" h={24} />
</div>
))}
</ul>
) : (
<ul tabIndex={-1} role="listbox">
{availableOptions.map((field, index) => (
Expand Down Expand Up @@ -245,7 +261,7 @@ const DropdownFilter = ({
try {
const fetchedOptions = await onFetch(searchKeyword);
setOptions((prev) => {
const newOptions = fetchedOptions.filter((option) => !prev.find((prevOption) => prevOption.value === option.value));
const newOptions = (fetchedOptions || []).filter((option) => !prev.find((prevOption) => prevOption.value === option.value));
return [...prev, ...newOptions];
});
} catch (error) {
Expand Down
9 changes: 6 additions & 3 deletions src/components/SkeletonItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export type SkeletonItemProps = {
variant?: 'wave' | 'pulse'
w?: string | number
h?: string | number
className?: string
className?: string,
children?: React.ReactNode,
};

const SkeletonItem = ({ circular, minWidth, w, h, className, variant = 'wave' } : SkeletonItemProps) => (
const SkeletonItem = ({ circular, minWidth, w, h, className, variant = 'wave', children } : SkeletonItemProps) => (
<div
className={clsx([
circular ? 'dsr-rounded-full' : 'dsr-rounded-lg',
Expand All @@ -25,7 +26,9 @@ const SkeletonItem = ({ circular, minWidth, w, h, className, variant = 'wave' }
width: w ?? '20px',
height: h ?? '20px',
}}
/>
>
{children}
</div>
);


Expand Down
3 changes: 1 addition & 2 deletions stories/components/display/DataTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ const DataTableManagerTemplate: Story<DataTableProps<ItemType>> = (args) => {
<DataTableManager
keyword={keyword}
setKeyword={setKeyword}
onDownload={() => window.alert('Download')}
onDownload={() => { window.alert('Download'); return []; }}
onCreate={() => window.alert('Create')}
tabs={[
{ label: 'All', key: 'all' },
Expand All @@ -416,7 +416,6 @@ const DataTableManagerTemplate: Story<DataTableProps<ItemType>> = (args) => {
labels: {
label: 'Category',
searchLabel: 'Search Category',
optionsTitle: 'Category',
},
options: [
{ value: 'hardware', label: 'Hardware' },
Expand Down

0 comments on commit cb52ed3

Please sign in to comment.