Skip to content

Commit

Permalink
fix: error when pureRenderer displaying pivot table (#390)
Browse files Browse the repository at this point in the history
* fix: min-size of middle panel

* fix: pivot table pureRenderer

* chore: disable collapse for pure renderer

* fix: merge fields filter function to storeStateLib

* fix: dependency

* fix: json file name
  • Loading branch information
islxyqwe authored Jun 19, 2024
1 parent fd23e71 commit 9c73454
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 52 deletions.
4 changes: 2 additions & 2 deletions packages/graphic-walker/scripts/create-json-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ const config = {
};

const generator = tsj.createGenerator(config);
if (!fs.existsSync(resolve(__dirname, '../public'))){
if (!fs.existsSync(resolve(__dirname, '../public'))) {
fs.mkdirSync(resolve(__dirname, '../public'));
}
fs.writeFileSync(resolve(__dirname, '../public/chartinfo.json'), JSON.stringify(generator.createSchema('IChart'), undefined, 4));
fs.writeFileSync(resolve(__dirname, '../public/stoinfo_V2.json'), JSON.stringify(generator.createSchema('IStoInfoV2'), undefined, 4));
fs.writeFileSync(resolve(__dirname, '../public/stoinfo_v2.json'), JSON.stringify(generator.createSchema('IStoInfoV2'), undefined, 4));
2 changes: 1 addition & 1 deletion packages/graphic-walker/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export const VizApp = observer(function VizApp(props: BaseVizProps) {
<SideResize
defaultWidth={180}
handleWidth={4}
className="min-w-[100%] max-w-full sm:min-w-[120px] sm:max-w-[30%] flex-shrink-0"
className="min-w-[100%] max-w-full sm:min-w-[164px] sm:max-w-[314px] flex-shrink-0"
handlerClassName="hidden sm:block"
>
<FilterField />
Expand Down
70 changes: 46 additions & 24 deletions packages/graphic-walker/src/components/pivotTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { useEffect, useMemo, useState, useRef } from 'react';
import React, { useEffect, useMemo, useState, useRef, useCallback } from 'react';
import { buildPivotTableService } from '../../services';
import { toWorkflow } from '../../utils/workflow';
import { dataQuery } from '../../computation';
import { useAppRootContext } from '../../components/appRoot';
import LeftTree from './leftTree';
import TopTree from './topTree';
import { observer } from 'mobx-react-lite';
import { DeepReadonly, DraggableFieldState, IDarkMode, IRow, IThemeKey, IViewField, IVisualConfigNew, IVisualLayout, IVisualConfig } from '../../interfaces';
import { DeepReadonly, DraggableFieldState, IRow, IThemeKey, IViewField, IVisualConfigNew, IVisualLayout, IVisualConfig } from '../../interfaces';
import { INestNode } from './inteface';
import { unstable_batchedUpdates } from 'react-dom';
import MetricTable from './metricTable';
Expand All @@ -15,28 +14,47 @@ import { useCompututaion, useVizStore } from '../../store';
import { fold2 } from '../../lib/op/fold';
import { getFieldIdentifier, getSort, getSortedEncoding } from '../../utils';
import { GWGlobalConfig } from '@/vis/theme';
import { getAllFields, getViewEncodingFields } from '../../store/storeStateLib';

interface PivotTableProps {
vizThemeConfig?: IThemeKey | GWGlobalConfig;
data: IRow[];
draggableFieldState: DeepReadonly<DraggableFieldState>;
draggableFieldState: DraggableFieldState;
visualConfig: IVisualConfigNew;
layout: IVisualLayout;
disableCollapse?: boolean;
}

const emptyMap = new Map();

const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableComponent(props) {
const PivotTable: React.FC<PivotTableProps> = function PivotTableComponent(props) {
const { data, visualConfig, layout, draggableFieldState } = props;
const computation = useCompututaion();
const appRef = useAppRootContext();
const [leftTree, setLeftTree] = useState<INestNode | null>(null);
const [topTree, setTopTree] = useState<INestNode | null>(null);
const [metricTable, setMetricTable] = useState<any[][]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const vizStore = useVizStore();
const enableCollapse = !!vizStore;
const tableCollapsedHeaderMap = vizStore?.tableCollapsedHeaderMap ?? emptyMap;

const enableCollapse = !props.disableCollapse;
const [tableCollapsedHeaderMap, setTableCollapsedHeaderMap] = useState<Record<string, INestNode['path']>>({});
const updateTableCollapsedHeader = useCallback((node: INestNode) => {
const { uniqueKey, height } = node;
if (height < 1) return;
setTableCollapsedHeaderMap((map) => {
const updatedMap = { ...map };
// if some child nodes of the incoming node are collapsed, remove them first
Object.entries(updatedMap).forEach(([existingKey, existingPath]) => {
if (existingKey.startsWith(uniqueKey) && existingKey.length > uniqueKey.length) {
delete updatedMap[existingKey];
}
});
if (!updatedMap[uniqueKey]) {
updatedMap[uniqueKey] = node.path;
} else {
delete updatedMap[uniqueKey];
}
return updatedMap;
});
}, []);
const { rows, columns } = draggableFieldState;
const { defaultAggregated, folds } = visualConfig;
const { showTableSummary } = layout;
Expand Down Expand Up @@ -64,18 +82,18 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
generateNewTable();
return;
}
if (vizStore && vizStore.tableCollapsedHeaderMap.size > 0) {
if (Object.keys(tableCollapsedHeaderMap).length > 0) {
// If some visual configs change, clear the collapse state
// As tableCollapsedHeaderMap is also listened, data will be reaggregated later.
vizStore.resetTableCollapsedHeader();
setTableCollapsedHeaderMap({});
// This forces data to be reaggregated if showTableSummary is on, as aggregation will be skipped later.
if (showTableSummary) {
aggregateGroupbyData();
}
} else {
aggregateThenGenerate();
}
}, [data, enableCollapse, vizStore]);
}, [data, enableCollapse]);

useEffect(() => {
if (!enableCollapse || showTableSummary) {
Expand All @@ -84,7 +102,7 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
} else {
aggregateThenGenerate();
}
}, [enableCollapse, vizStore?.tableCollapsedHeaderMap]);
}, [enableCollapse, tableCollapsedHeaderMap]);

useEffect(() => {
aggregateThenGenerate();
Expand All @@ -105,7 +123,7 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
dimsInColumn,
data,
aggData.current,
Array.from(tableCollapsedHeaderMap.keys()),
Object.keys(tableCollapsedHeaderMap),
showTableSummary,
sort !== 'none' && sortedEncoding !== 'none'
? {
Expand Down Expand Up @@ -143,7 +161,7 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
groupbyCombListInRow = dimsInRow.map((dim, idx) => dimsInRow.slice(0, idx));
groupbyCombListInCol = dimsInColumn.map((dim, idx) => dimsInColumn.slice(0, idx));
} else {
const collapsedDimList = Array.from(tableCollapsedHeaderMap).map(([key, path]) => path[path.length - 1].key);
const collapsedDimList = Object.entries(tableCollapsedHeaderMap).map(([key, path]) => path[path.length - 1].key);
const collapsedDimsInRow = dimsInRow.filter((dim) => collapsedDimList.includes(dim.fid));
const collapsedDimsInColumn = dimsInColumn.filter((dim) => collapsedDimList.includes(dim.fid));
groupbyCombListInRow = collapsedDimsInRow.map((dim) => dimsInRow.slice(0, dimsInRow.indexOf(dim) + 1));
Expand All @@ -166,9 +184,13 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
setIsLoading(true);
appRef.current?.updateRenderStatus('computing');
const groupbyPromises: Promise<IRow[]>[] = groupbyCombList.map((dimComb) => {
if (!vizStore) return Promise.resolve([]);
const { viewFilters, allFields, viewMeasures, sort, limit, config } = vizStore;
const { timezoneDisplayOffset } = config;
const viewFilters = draggableFieldState.filters;
const allFields = getAllFields(draggableFieldState);
const viewFields = getViewEncodingFields(draggableFieldState, 'table');
const viewMeasures = viewFields.filter((f) => f.analyticType === 'measure');
const sort = getSort(draggableFieldState);
const { limit } = visualConfig;
const { timezoneDisplayOffset } = visualConfig;
const workflow = toWorkflow(
viewFilters,
allFields,
Expand Down Expand Up @@ -240,9 +262,9 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
data={leftTree}
dimsInRow={dimsInRow}
measInRow={measInRow}
onHeaderCollapse={(n) => vizStore?.updateTableCollapsedHeader(n)}
onHeaderCollapse={(n) => updateTableCollapsedHeader(n)}
enableCollapse={enableCollapse}
displayOffset={vizStore.config.timezoneDisplayOffset}
displayOffset={visualConfig.timezoneDisplayOffset}
/>
)}
</table>
Expand All @@ -252,10 +274,10 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
data={topTree}
dimsInCol={dimsInColumn}
measInCol={measInColumn}
onHeaderCollapse={(n) => vizStore?.updateTableCollapsedHeader(n)}
onHeaderCollapse={(n) => updateTableCollapsedHeader(n)}
onTopTreeHeaderRowNumChange={(num) => setTopTreeHeaderRowNum(num)}
enableCollapse={enableCollapse}
displayOffset={vizStore.config.timezoneDisplayOffset}
displayOffset={visualConfig.timezoneDisplayOffset}
/>
)}
{metricTable && (
Expand All @@ -265,6 +287,6 @@ const PivotTable: React.FC<PivotTableProps> = observer(function PivotTableCompon
</div>
</div>
);
});
};

export default PivotTable;
4 changes: 3 additions & 1 deletion packages/graphic-walker/src/models/visSpec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const viewEncodingKeys = (geom: string) => {
import { DraggableFieldState } from '../interfaces';

export const viewEncodingKeys = (geom: string): Exclude<keyof DraggableFieldState, 'filters'>[] => {
switch (geom) {
case 'choropleth':
return ['geoId', 'color', 'opacity', 'text', 'details'];
Expand Down
3 changes: 3 additions & 0 deletions packages/graphic-walker/src/renderer/pureRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type IPureRendererProps = {
channelScales?: IChannelScales;
scales?: IChannelScales;
overrideSize?: IVisualLayout['size'];
disableCollapse?: boolean;
};

type LocalProps = {
Expand Down Expand Up @@ -87,6 +88,7 @@ const PureRenderer = forwardRef<IReactVegaHandler, IPureRendererProps & (LocalPr
themeConfig,
channelScales,
scales,
disableCollapse,
} = props;
const computation = useMemo(() => {
if (props.type === 'remote') {
Expand Down Expand Up @@ -188,6 +190,7 @@ const PureRenderer = forwardRef<IReactVegaHandler, IPureRendererProps & (LocalPr
locale={locale ?? 'en-US'}
scales={scales ?? channelScales}
vizThemeConfig={vizThemeConfig ?? themeConfig ?? themeKey}
disableCollapse={disableCollapse}
/>
)}
<div className={`App ${darkMode === 'dark' ? 'dark' : ''}`} ref={setPortal} />
Expand Down
29 changes: 13 additions & 16 deletions packages/graphic-walker/src/renderer/specRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import React, { forwardRef, useMemo, useContext } from 'react';
import PivotTable from '../components/pivotTable';
import LeafletRenderer, { LEAFLET_DEFAULT_HEIGHT, LEAFLET_DEFAULT_WIDTH } from '../components/leafletRenderer';
import ReactVega, { IReactVegaHandler } from '../vis/react-vega';
import { DraggableFieldState, IDarkMode, IRow, IThemeKey, IVisualConfigNew, IVisualLayout, VegaGlobalConfig, IChannelScales } from '../interfaces';
import LoadingLayer from '../components/loadingLayer';
import { DraggableFieldState, IRow, IThemeKey, IVisualConfigNew, IVisualLayout, VegaGlobalConfig, IChannelScales } from '../interfaces';
import { getTheme } from '../utils/useTheme';
import { GWGlobalConfig } from '../vis/theme';
import { uiThemeContext, themeContext } from '@/store/theme';
Expand All @@ -23,25 +22,14 @@ interface SpecRendererProps {
locale?: string;
scales?: IChannelScales;
onReportSpec?: (spec: string) => void;
disableCollapse?: boolean;
}
/**
* Sans-store renderer of GraphicWalker.
* This is a pure component, which means it will not depend on any global state.
*/
const SpecRenderer = forwardRef<IReactVegaHandler, SpecRendererProps>(function (
{
name,
layout,
data,
draggableFieldState,
visualConfig,
onGeomClick,
onChartResize,
locale,
onReportSpec,
vizThemeConfig,
scales,
},
{ name, layout, data, draggableFieldState, visualConfig, onGeomClick, onChartResize, locale, onReportSpec, vizThemeConfig, scales, disableCollapse },
ref
) {
// const { draggableFieldState, visualConfig } = vizStore;
Expand Down Expand Up @@ -121,7 +109,16 @@ const SpecRenderer = forwardRef<IReactVegaHandler, SpecRendererProps>(function (
}, [themeConfig, mediaTheme, zeroScale, resolve, background, format.normalizedNumberFormat, format.numberFormat, format.timeFormat]);

if (isPivotTable) {
return <PivotTable data={data} draggableFieldState={draggableFieldState} visualConfig={visualConfig} layout={layout} vizThemeConfig={vizThemeConfig} />;
return (
<PivotTable
data={data}
draggableFieldState={draggableFieldState}
visualConfig={visualConfig}
layout={layout}
vizThemeConfig={vizThemeConfig}
disableCollapse={disableCollapse}
/>
);
}

const isSpatial = coordSystem === 'geographic';
Expand Down
10 changes: 10 additions & 0 deletions packages/graphic-walker/src/store/storeStateLib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { viewEncodingKeys } from '@/models/visSpec';
import { DraggableFieldState, IViewField } from '../interfaces';

export function getAllFields(encodings: { dimensions: IViewField[]; measures: IViewField[] }) {
return [...encodings.dimensions, ...encodings.measures];
}

export function getViewEncodingFields(encodings: Partial<Omit<DraggableFieldState, 'filters'>>, geom: string) {
return viewEncodingKeys(geom).flatMap((k) => encodings[k] ?? []);
}
7 changes: 4 additions & 3 deletions packages/graphic-walker/src/store/visualSpecStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { getSQLItemAnalyticType, parseSQLExpr } from '../lib/sql';
import { IPaintMapAdapter } from '../lib/paint';
import { toChatMessage } from '@/models/chat';
import { viewEncodingKeys } from '@/models/visSpec';
import { getAllFields, getViewEncodingFields } from './storeStateLib';

const encodingKeys = (Object.keys(emptyEncodings) as (keyof DraggableFieldState)[]).filter((dkey) => !GLOBAL_CONFIG.META_FIELD_KEYS.includes(dkey));
export class VizSpecStore {
Expand Down Expand Up @@ -153,7 +154,7 @@ export class VizSpecStore {
}

get allFields() {
return [...this.dimensions, ...this.measures];
return getAllFields(this);
}

get config() {
Expand All @@ -179,7 +180,7 @@ export class VizSpecStore {
return result;
}

get viewEncodings() {
get viewEncodings(): Partial<Omit<DraggableFieldState, 'filters'>> {
const result: Record<string, IViewField[]> = {};
viewEncodingKeys(this.config.geoms[0]).forEach((k) => {
result[k] = this.currentEncodings[k];
Expand All @@ -188,7 +189,7 @@ export class VizSpecStore {
}

get viewEncodingFields() {
return viewEncodingKeys(this.config.geoms[0]).flatMap((k) => this.viewEncodings[k]);
return getViewEncodingFields(this.viewEncodings, this.config.geoms[0]);
}

get viewDimensions() {
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2076,7 +2076,7 @@
"@types/react" "*"
"@types/reactcss" "*"

"@types/react-dom@*", "@types/react-dom@^18.2.15":
"@types/react-dom@*", "@types/react-dom@^18.2.15", "@types/react-dom@^18.x":
version "18.3.0"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0"
integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==
Expand All @@ -2090,10 +2090,10 @@
dependencies:
"@types/react" "*"

"@types/react@*", "@types/react@^18.2.37":
version "18.3.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.2.tgz#462ae4904973bc212fa910424d901e3d137dbfcd"
integrity sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==
"@types/react@*", "@types/react@^18.2.37", "@types/react@^18.x":
version "18.3.3"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f"
integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==
dependencies:
"@types/prop-types" "*"
csstype "^3.0.2"
Expand Down

0 comments on commit 9c73454

Please sign in to comment.