Skip to content

Commit

Permalink
Improve data table manager
Browse files Browse the repository at this point in the history
  • Loading branch information
aswinshenoy committed Feb 7, 2024
1 parent cb8d2b3 commit 58bf26d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 28 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chaya-ui",
"version": "1.0.0-beta.75",
"version": "1.0.0-beta.76",
"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
107 changes: 84 additions & 23 deletions src/components/DataTableManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,60 @@ import Button from './Button';
import SearchBox from './SearchBox';
import DropdownFilter from './DropdownFilter';
import { IconInputType } from './Icon';
import { HorizontalNavigatorItemType } from './HorizontalNavigator/item';
import HorizontalNavigator from './HorizontalNavigator';


export type FilterInputs = {
[key: string]: any,
};

export type DataTableFilterConfig = {
key: string,
options?: {
label: string,
value: string,
}[]
isHidden?: boolean,
onFetch?: (keyword: string) => Promise<{ label: string, value: string }[]>,
labels?: {
label?: string,
searchLabel?: string,
optionsTitle?: string,
}
};

export type DataTableManagerProps = {
// search
keyword?: string
setKeyword?: (keyword: string) => void
// meta
totalCount?: number
isLoading?: boolean
labels?: {
searchLabel?: string,
searchPlaceholder?: string,
label: string,
labelPlural: string,
label?: string,
labelPlural?: string,
create?: string,
}
// columns
columns?: { label: string, value: string }[],
selectedColumns?: string[],
setColumns?: (c: string[]) => void,
// filters
filterConfig?: {
key: string,
options: {
label: string,
value: string,
}[],
labels?: {
label?: string,
searchLabel?: string,
optionsTitle?: string,
}
}[],
filterConfig?: DataTableFilterConfig[],
filters?: FilterInputs,
setFilters?: (f: FilterInputs) => void,
isFilteringInitialised?: boolean,

// download
showDownloadButton?: boolean,
onDownload?: () => void,
isDownloadLoading?: boolean,

// create
onCreate?: () => void,

// selections
selections?: {
total: number,
Expand All @@ -66,20 +79,27 @@ export type DataTableManagerProps = {
leftIcon?: IconInputType,
rightIcon?: IconInputType,
}[],

// tag filters
tabs?: HorizontalNavigatorItemType[],
currentTab?: string,
onTabChange?: (key: string, item: HorizontalNavigatorItemType) => void,

};

const defaultLabels = {
label: 'Record',
labelPlural: 'Records',
searchLabel: 'Search',
searchPlaceholder: 'Search...',
create: 'Create',
};


const DataTableManager = ({
keyword, setKeyword, labels: _labels, isLoading = false, totalCount,
filterConfig, filters, setFilters = () => {}, isFilteringInitialised,
showDownloadButton = false, onDownload = () => {}, isDownloadLoading = false,
onDownload, isDownloadLoading = false, onCreate, tabs, currentTab, onTabChange = () => {},
columns, selectedColumns = [], setColumns = () => {},
selections, onCancelSelections = () => {}, selectionActions = [],
}: DataTableManagerProps) => {
Expand All @@ -97,6 +117,20 @@ const DataTableManager = ({
setShowFilters(isFilteringInitialised);
}, [isFilteringInitialised]);

const [cachedOptions, setCachedOptions] = useState<{ [key: string]: { label: string, value: string }[] }>({});
const onFetch = async (key: string, keyword: string, onFetch: (keyword: string) => Promise<{ label: string, value: string }[]>) => {
const options = await onFetch(keyword);
setCachedOptions({ ...cachedOptions, [key]: options });
return options;
};

const getOptions = (f: DataTableFilterConfig) => {
if (typeof f.onFetch === 'function')
return cachedOptions[f.key] || [];
if (f.options) return f.options;
return [];
};

return (
<div>
<div className="md:dsr-flex dsr-justify-between dsr-items-center dsr-gap-3">
Expand All @@ -120,7 +154,16 @@ const DataTableManager = ({
</div>
)}
</div>
<div className="dsr-flex dsr-gap-3 dsr-p-2">
{tabs && tabs?.length > 0 ? (
<HorizontalNavigator
items={tabs}
activeItem={currentTab}
onClickItem={onTabChange}
itemClassName="dsr-py-1 dsr-text-base dsr-px-2"
className="dsr-py-1 dsr-px-2"
/>
) : null}
<div className="dsr-flex dsr-items-center dsr-gap-3 dsr-p-2">
{(filters && !showFilters) && (
<Button
type="button"
Expand Down Expand Up @@ -151,7 +194,7 @@ const DataTableManager = ({
</Button>
</DropdownFilter>
) : null}
{showDownloadButton && (
{typeof onDownload === 'function' && (
<Button
type="button"
variant="minimal"
Expand All @@ -163,15 +206,33 @@ const DataTableManager = ({
<Download />
</Button>
)}
{typeof onCreate === 'function' && (
<Button
type="button"
variant="solid"
color="primary"
onClick={onCreate}
rightIcon="plus"
className="!dsr-py-1.5"
>
Create
</Button>
)}
</div>
</div>
{(showFilters && filterConfig) && (
<div className="dark:dsr-bg-gray-500/20 dsr-bg-gray-500/10 dsr-border dark:dsr-border-neutral-500/70 dsr-border-neutral-500/10 dsr-mx-2 dsr-mb-2 dsr-shadow-inner dsr-rounded-lg dsr-p-2">
<div className="dsr-flex dsr-items-center dsr-flex-wrap dsr-gap-3">
{filterConfig.filter((f) => f.options.length).map((f) => (
{filterConfig.filter((f) =>
(typeof f.onFetch === 'function' || f.options?.length) && !f.isHidden,
).map((f) => (
<div key={f.key} className="dsr-p-1">
<DropdownFilter
options={f.options}
options={f.options || []}
isAsync={typeof f.onFetch === 'function'}
onFetch={(keyword) =>
typeof f.onFetch === 'function' ? onFetch(f.key, keyword, f.onFetch) : Promise.resolve([])
}
labels={{
searchLabel: f.labels?.searchLabel,
optionsTitle: f.labels?.optionsTitle,
Expand All @@ -180,8 +241,8 @@ const DataTableManager = ({
setSelections={(selections) => setFilters({ ...filters, [f.key]: selections ?? [] })}
>
<Button
variant={filters?.[f.key] && filters?.[f.key]?.length && filters?.[f.key]?.length < f.options.length ? 'solid' : 'minimal'}
color={filters?.[f.key] && filters?.[f.key]?.length && filters?.[f.key]?.length < f.options.length ? 'primary' : 'shade'}
variant={filters?.[f.key] && filters?.[f.key]?.length && filters?.[f.key]?.length < getOptions(f).length ? 'solid' : 'minimal'}
color={filters?.[f.key] && filters?.[f.key]?.length && filters?.[f.key]?.length < getOptions(f).length ? 'primary' : 'shade'}
size="sm"
className="dsr-flex dsr-items-center dsr-gap-1"
>
Expand All @@ -194,7 +255,7 @@ const DataTableManager = ({
))}
</div>
<div className="dsr-flex dsr-items-center dsr-flex-wrap dsr-gap-2 dsr-mt-1 dsr-border-t dsr-pt-2">
{filterConfig.filter((f) => f.options.length && filters?.[f.key]?.length && f.options.length != filters?.[f.key]?.length).map((f) => (
{filterConfig.filter((f) => getOptions(f).length && filters?.[f.key]?.length && getOptions(f).length != filters?.[f.key]?.length).map((f) => (
<div className="md:dsr-flex dsr-items-center dsr-pb-3 dsr-pt-1" key={f.key}>
{(f.labels && f.labels.label && f.labels.label?.length > 0) ? (
<div className="md:dsr-mr-2 dsr-mb-1 md:dsr-mb-0 dsr-text-sm dsr-font-semibold">
Expand Down
2 changes: 1 addition & 1 deletion src/components/HorizontalNavigator/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const HorizontalNavigatorItem = ({
variant: {
pill: [
'border border-neutral-300/20 dsr-px-5 dsr-py-2',
activeItem === item.key && 'dsr-text-primaryTextColor',
activeItem === item.key && 'dsr-text-primaryTextColor dsr-z-[1000]',
activeItem !== item.key && !item?.isDisabled && 'hover:dsr-bg-neutral-50/80 dark:hover:dsr-bg-neutral-500/80',
],
line: [
Expand Down
8 changes: 7 additions & 1 deletion stories/components/display/DataTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,14 @@ const DataTableManagerTemplate: Story<DataTableProps<ItemType>> = (args) => {
<DataTableManager
keyword={keyword}
setKeyword={setKeyword}
showDownloadButton
onDownload={() => window.alert('Download')}
onCreate={() => window.alert('Create')}
tabs={[
{ label: 'All', key: 'all' },
{ label: 'Selected', key: 'selected' },
{ label: 'Excluded', key: 'excluded' },
]}
currentTab="all"
isFilteringInitialised
filters={filters}
setFilters={setFilters}
Expand Down

0 comments on commit 58bf26d

Please sign in to comment.