diff --git a/packages/graphic-walker/src/Table.tsx b/packages/graphic-walker/src/Table.tsx
index 1d0ab289..822b0276 100644
--- a/packages/graphic-walker/src/Table.tsx
+++ b/packages/graphic-walker/src/Table.tsx
@@ -85,6 +85,7 @@ export const TableApp = observer(function VizApp(props: BaseTableProps) {
{
vizStore.updateCurrentDatasetMetas(fid, diffMeta);
} : undefined}
diff --git a/packages/graphic-walker/src/components/dataTable/index.tsx b/packages/graphic-walker/src/components/dataTable/index.tsx
index 1f16fd28..8745a842 100644
--- a/packages/graphic-walker/src/components/dataTable/index.tsx
+++ b/packages/graphic-walker/src/components/dataTable/index.tsx
@@ -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';
@@ -232,7 +232,13 @@ function TruncateDector(props: { value: string }) {
);
}
-const DataTable: React.FC = (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();
@@ -253,6 +259,13 @@ const DataTable: React.FC = (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);
@@ -541,7 +554,7 @@ const DataTable: React.FC = (props) => {
)}
);
-};
+});
export default DataTable;
diff --git a/packages/graphic-walker/src/interfaces.ts b/packages/graphic-walker/src/interfaces.ts
index c1fae193..1d28d77a 100644
--- a/packages/graphic-walker/src/interfaces.ts
+++ b/packages/graphic-walker/src/interfaces.ts
@@ -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 {}
diff --git a/packages/playground/src/examples/pages/table.stories.tsx b/packages/playground/src/examples/pages/table.stories.tsx
index a6acd6de..6289917a 100644
--- a/packages/playground/src/examples/pages/table.stories.tsx
+++ b/packages/playground/src/examples/pages/table.stories.tsx
@@ -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('https://pub-2422ed4100b443659f588f2382cfc7b1.r2.dev/datasets/ds-students-service.json');
+ const tableRef = useRef<{ getFilters: () => IVisFilter[] }>(null);
- return ;
+ 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 (
+
+ );
}