Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add table filter ref and example #407

Merged
merged 4 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/graphic-walker/src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const TableApp = observer(function VizApp(props: BaseTableProps) {
<div className={`${darkMode === 'dark' ? 'dark' : ''} App font-sans bg-background text-foreground h-full m-0 p-0`}>
<div className="bg-background text-foreground h-full">
<DatasetTable
ref={props.tableFilterRef}
onMetaChange={vizStore.onMetaChange ? (fid, fIndex, diffMeta) => {
vizStore.updateCurrentDatasetMetas(fid, diffMeta);
} : undefined}
Expand Down
21 changes: 17 additions & 4 deletions packages/graphic-walker/src/components/dataTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo, useState, useRef, useEffect, useCallback } from 'react';
import React, { useMemo, useState, useRef, useEffect, useCallback, forwardRef, useImperativeHandle, ForwardedRef } from 'react';
import styled from 'styled-components';
import type { IMutField, IRow, IComputationFunction, IFilterFiledSimple, IFilterRule, IFilterField, IFilterWorkflowStep, IField } from '../../interfaces';
import type { IMutField, IRow, IComputationFunction, IFilterFiledSimple, IFilterRule, IFilterField, IFilterWorkflowStep, IField, IVisFilter } from '../../interfaces';
import { useTranslation } from 'react-i18next';
import LoadingLayer from '../loadingLayer';
import { dataReadRaw } from '../../computation';
Expand Down Expand Up @@ -232,7 +232,13 @@ function TruncateDector(props: { value: string }) {
);
}

const DataTable: React.FC<DataTableProps> = (props) => {
const DataTable = forwardRef(
(
props: DataTableProps,
ref: ForwardedRef<{
getFilters: () => IVisFilter[];
}>
) => {
const { size = 10, onMetaChange, metas, computation, disableFilter, displayOffset, hidePaginationAtOnepage, hideProfiling } = props;
const [pageIndex, setPageIndex] = useState(0);
const { t } = useTranslation();
Expand All @@ -253,6 +259,13 @@ const DataTable: React.FC<DataTableProps> = (props) => {

const { filters, editingFilterIdx, onClose, onDeleteFilter, onSelectFilter, onWriteFilter, options } = useFilters(metas);

const filtersRef = useRef(filters);
filtersRef.current = filters;

useImperativeHandle(ref, () => ({
getFilters: () => filtersRef.current.filter(x => x.rule) as IVisFilter[],
}));

const [total, setTotal] = useState(0);
const [statLoading, setStatLoading] = useState(false);

Expand Down Expand Up @@ -541,7 +554,7 @@ const DataTable: React.FC<DataTableProps> = (props) => {
)}
</Container>
);
};
});

export default DataTable;

Expand Down
3 changes: 3 additions & 0 deletions packages/graphic-walker/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,9 @@ export interface ITableSpecProps {
/** @deprecated use vizThemeConfig instead */
themeConfig?: GWGlobalConfig;
vizThemeConfig?: IThemeKey | GWGlobalConfig;
tableFilterRef?: React.Ref<{
getFilters: () => IVisFilter[];
}>;
}

export interface IVizAppProps extends IAppI18nProps, IVizProps, IThemeProps, IErrorHandlerProps, IVizStoreProps, ISpecProps {}
Expand Down
57 changes: 54 additions & 3 deletions packages/playground/src/examples/pages/table.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,62 @@
import { useContext } from 'react';
import { TableWalker } from '@kanaries/graphic-walker';
import { useContext, useRef } from 'react';
import { getComputation, IVisFilter, TableWalker } from '@kanaries/graphic-walker';
import { themeContext } from '../context';
import { useFetch, IDataSource } from '../util';

export default function GraphicWalkerComponent() {
const { theme } = useContext(themeContext);
const { dataSource, fields } = useFetch<IDataSource>('https://pub-2422ed4100b443659f588f2382cfc7b1.r2.dev/datasets/ds-students-service.json');
const tableRef = useRef<{ getFilters: () => IVisFilter[] }>(null);

return <TableWalker fields={fields} data={dataSource} appearance={theme} pageSize={50} />;
const downloadCSV = async () => {
const filters = tableRef.current?.getFilters() ?? [];

// or use a remote computation service
// const computation = async (workflow) => fetch(endPoint, { body: JSON.stringify(workflow) }).then(resp => resp.json())
const computation = getComputation(dataSource);

const result = await computation({
workflow: [
{ type: 'filter', filters },
{
type: 'view',
query: [
{
op: 'raw',
fields: fields.map((x) => x.fid),
},
],
},
],
});

const header = fields.map((x) => x.name).join(',');
const data = result
.map((row) =>
fields
.map((x) => row[x.fid] ?? '')
.map((x) => (typeof x === 'string' ? `"${x}"` : `${x}`))
.join(',')
)
.join('\n');
const blob = new Blob([header + '\n' + data], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `Student.csv`;
a.click();
URL.revokeObjectURL(url);
};

return (
<div className="flex flex-col gap-2">
<button
onClick={downloadCSV}
className="h-9 px-4 py-2 w-fit m-2 bg-zinc-950 text-white shadow hover:bg-primary/90 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
>
Export CSV
</button>
<TableWalker tableFilterRef={tableRef} fields={fields} data={dataSource} appearance={theme} pageSize={50} vizThemeConfig="g2" />
</div>
);
}
Loading