From 2178f4f8cc4eead00a603dee090dac639322dc01 Mon Sep 17 00:00:00 2001 From: islxyqwe Date: Thu, 6 Jun 2024 14:37:37 +0800 Subject: [PATCH 1/6] fix: min-size of middle panel --- packages/graphic-walker/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/graphic-walker/src/App.tsx b/packages/graphic-walker/src/App.tsx index cf8f4531..1cd94d60 100644 --- a/packages/graphic-walker/src/App.tsx +++ b/packages/graphic-walker/src/App.tsx @@ -227,7 +227,7 @@ export const VizApp = observer(function VizApp(props: BaseVizProps) { From 79c935a8f7a37779454a55fd09a8aeeed5d46b09 Mon Sep 17 00:00:00 2001 From: islxyqwe Date: Fri, 31 May 2024 12:14:47 +0800 Subject: [PATCH 2/6] fix: pivot table pureRenderer --- .../src/components/pivotTable/index.tsx | 67 ++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/packages/graphic-walker/src/components/pivotTable/index.tsx b/packages/graphic-walker/src/components/pivotTable/index.tsx index 5ac45eeb..b6aedf10 100644 --- a/packages/graphic-walker/src/components/pivotTable/index.tsx +++ b/packages/graphic-walker/src/components/pivotTable/index.tsx @@ -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'; @@ -22,11 +21,10 @@ interface PivotTableProps { draggableFieldState: DeepReadonly; visualConfig: IVisualConfigNew; layout: IVisualLayout; + disableCollapse?: boolean; } -const emptyMap = new Map(); - -const PivotTable: React.FC = observer(function PivotTableComponent(props) { +const PivotTable: React.FC = function PivotTableComponent(props) { const { data, visualConfig, layout, draggableFieldState } = props; const computation = useCompututaion(); const appRef = useAppRootContext(); @@ -34,9 +32,28 @@ const PivotTable: React.FC = observer(function PivotTableCompon const [topTree, setTopTree] = useState(null); const [metricTable, setMetricTable] = useState([]); const [isLoading, setIsLoading] = useState(false); - const vizStore = useVizStore(); - const enableCollapse = !!vizStore; - const tableCollapsedHeaderMap = vizStore?.tableCollapsedHeaderMap ?? emptyMap; + + const enableCollapse = !props.disableCollapse; + const [tableCollapsedHeaderMap, setTableCollapsedHeaderMap] = useState>({}); + 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; @@ -64,10 +81,10 @@ const PivotTable: React.FC = 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(); @@ -75,7 +92,7 @@ const PivotTable: React.FC = observer(function PivotTableCompon } else { aggregateThenGenerate(); } - }, [data, enableCollapse, vizStore]); + }, [data, enableCollapse]); useEffect(() => { if (!enableCollapse || showTableSummary) { @@ -84,7 +101,7 @@ const PivotTable: React.FC = observer(function PivotTableCompon } else { aggregateThenGenerate(); } - }, [enableCollapse, vizStore?.tableCollapsedHeaderMap]); + }, [enableCollapse, tableCollapsedHeaderMap]); useEffect(() => { aggregateThenGenerate(); @@ -105,7 +122,7 @@ const PivotTable: React.FC = observer(function PivotTableCompon dimsInColumn, data, aggData.current, - Array.from(tableCollapsedHeaderMap.keys()), + Object.keys(tableCollapsedHeaderMap), showTableSummary, sort !== 'none' && sortedEncoding !== 'none' ? { @@ -143,7 +160,7 @@ const PivotTable: React.FC = 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)); @@ -166,9 +183,13 @@ const PivotTable: React.FC = observer(function PivotTableCompon setIsLoading(true); appRef.current?.updateRenderStatus('computing'); const groupbyPromises: Promise[] = groupbyCombList.map((dimComb) => { - if (!vizStore) return Promise.resolve([]); - const { viewFilters, allFields, viewMeasures, sort, limit, config } = vizStore; - const { timezoneDisplayOffset } = config; + const viewFilters = draggableFieldState.filters.map((x) => ({ ...x })); + const allFields = [...draggableFieldState.dimensions, ...draggableFieldState.measures]; + const viewFields = [...draggableFieldState.columns, ...draggableFieldState.rows]; + const viewMeasures = viewFields.filter((f) => f.analyticType === 'measure'); + const sort = getSort(draggableFieldState); + const { limit } = visualConfig; + const { timezoneDisplayOffset } = visualConfig; const workflow = toWorkflow( viewFilters, allFields, @@ -240,9 +261,9 @@ const PivotTable: React.FC = 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} /> )} @@ -252,10 +273,10 @@ const PivotTable: React.FC = 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 && ( @@ -265,6 +286,6 @@ const PivotTable: React.FC = observer(function PivotTableCompon ); -}); +}; export default PivotTable; From 97c36556446b137b8b72d0585cc2b53d442367ba Mon Sep 17 00:00:00 2001 From: islxyqwe Date: Fri, 31 May 2024 15:21:24 +0800 Subject: [PATCH 3/6] chore: disable collapse for pure renderer --- .../src/renderer/pureRenderer.tsx | 3 ++ .../src/renderer/specRenderer.tsx | 29 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/graphic-walker/src/renderer/pureRenderer.tsx b/packages/graphic-walker/src/renderer/pureRenderer.tsx index 007d45a3..c09dbc5b 100644 --- a/packages/graphic-walker/src/renderer/pureRenderer.tsx +++ b/packages/graphic-walker/src/renderer/pureRenderer.tsx @@ -49,6 +49,7 @@ type IPureRendererProps = { channelScales?: IChannelScales; scales?: IChannelScales; overrideSize?: IVisualLayout['size']; + disableCollapse?: boolean; }; type LocalProps = { @@ -87,6 +88,7 @@ const PureRenderer = forwardRef { if (props.type === 'remote') { @@ -188,6 +190,7 @@ const PureRenderer = forwardRef )}
diff --git a/packages/graphic-walker/src/renderer/specRenderer.tsx b/packages/graphic-walker/src/renderer/specRenderer.tsx index e4eaaf36..164a8108 100644 --- a/packages/graphic-walker/src/renderer/specRenderer.tsx +++ b/packages/graphic-walker/src/renderer/specRenderer.tsx @@ -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'; @@ -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(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; @@ -121,7 +109,16 @@ const SpecRenderer = forwardRef(function ( }, [themeConfig, mediaTheme, zeroScale, resolve, background, format.normalizedNumberFormat, format.numberFormat, format.timeFormat]); if (isPivotTable) { - return ; + return ( + + ); } const isSpatial = coordSystem === 'geographic'; From 0cb1a705bc5c22ae1a01d4b52498a9a85e2b877c Mon Sep 17 00:00:00 2001 From: islxyqwe Date: Wed, 19 Jun 2024 17:03:12 +0800 Subject: [PATCH 4/6] fix: merge fields filter function to storeStateLib --- .../graphic-walker/src/components/pivotTable/index.tsx | 9 +++++---- packages/graphic-walker/src/models/visSpec.ts | 4 +++- packages/graphic-walker/src/store/storeStateLib.ts | 10 ++++++++++ packages/graphic-walker/src/store/visualSpecStore.ts | 7 ++++--- 4 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 packages/graphic-walker/src/store/storeStateLib.ts diff --git a/packages/graphic-walker/src/components/pivotTable/index.tsx b/packages/graphic-walker/src/components/pivotTable/index.tsx index b6aedf10..31411731 100644 --- a/packages/graphic-walker/src/components/pivotTable/index.tsx +++ b/packages/graphic-walker/src/components/pivotTable/index.tsx @@ -14,11 +14,12 @@ 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; visualConfig: IVisualConfigNew; layout: IVisualLayout; disableCollapse?: boolean; @@ -183,9 +184,9 @@ const PivotTable: React.FC = function PivotTableComponent(props setIsLoading(true); appRef.current?.updateRenderStatus('computing'); const groupbyPromises: Promise[] = groupbyCombList.map((dimComb) => { - const viewFilters = draggableFieldState.filters.map((x) => ({ ...x })); - const allFields = [...draggableFieldState.dimensions, ...draggableFieldState.measures]; - const viewFields = [...draggableFieldState.columns, ...draggableFieldState.rows]; + 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; diff --git a/packages/graphic-walker/src/models/visSpec.ts b/packages/graphic-walker/src/models/visSpec.ts index 9800c189..23ec266c 100644 --- a/packages/graphic-walker/src/models/visSpec.ts +++ b/packages/graphic-walker/src/models/visSpec.ts @@ -1,4 +1,6 @@ -export const viewEncodingKeys = (geom: string) => { +import { DraggableFieldState } from '..'; + +export const viewEncodingKeys = (geom: string): Exclude[] => { switch (geom) { case 'choropleth': return ['geoId', 'color', 'opacity', 'text', 'details']; diff --git a/packages/graphic-walker/src/store/storeStateLib.ts b/packages/graphic-walker/src/store/storeStateLib.ts new file mode 100644 index 00000000..74754914 --- /dev/null +++ b/packages/graphic-walker/src/store/storeStateLib.ts @@ -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>, geom: string) { + return viewEncodingKeys(geom).flatMap((k) => encodings[k] ?? []); +} diff --git a/packages/graphic-walker/src/store/visualSpecStore.ts b/packages/graphic-walker/src/store/visualSpecStore.ts index 8987f9bc..d1e1be7f 100644 --- a/packages/graphic-walker/src/store/visualSpecStore.ts +++ b/packages/graphic-walker/src/store/visualSpecStore.ts @@ -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 { @@ -153,7 +154,7 @@ export class VizSpecStore { } get allFields() { - return [...this.dimensions, ...this.measures]; + return getAllFields(this); } get config() { @@ -179,7 +180,7 @@ export class VizSpecStore { return result; } - get viewEncodings() { + get viewEncodings(): Partial> { const result: Record = {}; viewEncodingKeys(this.config.geoms[0]).forEach((k) => { result[k] = this.currentEncodings[k]; @@ -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() { From 1cb001d16c809e4f4295775c92aba22e84f2ccc5 Mon Sep 17 00:00:00 2001 From: islxyqwe Date: Wed, 19 Jun 2024 17:09:16 +0800 Subject: [PATCH 5/6] fix: dependency --- .../graphic-walker/src/components/pivotTable/index.tsx | 2 +- packages/graphic-walker/src/models/visSpec.ts | 2 +- yarn.lock | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/graphic-walker/src/components/pivotTable/index.tsx b/packages/graphic-walker/src/components/pivotTable/index.tsx index 31411731..6b15eb46 100644 --- a/packages/graphic-walker/src/components/pivotTable/index.tsx +++ b/packages/graphic-walker/src/components/pivotTable/index.tsx @@ -14,7 +14,7 @@ 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'; +import { getAllFields, getViewEncodingFields } from '../../store/storeStateLib'; interface PivotTableProps { vizThemeConfig?: IThemeKey | GWGlobalConfig; diff --git a/packages/graphic-walker/src/models/visSpec.ts b/packages/graphic-walker/src/models/visSpec.ts index 23ec266c..bd6b247e 100644 --- a/packages/graphic-walker/src/models/visSpec.ts +++ b/packages/graphic-walker/src/models/visSpec.ts @@ -1,4 +1,4 @@ -import { DraggableFieldState } from '..'; +import { DraggableFieldState } from '../interfaces'; export const viewEncodingKeys = (geom: string): Exclude[] => { switch (geom) { diff --git a/yarn.lock b/yarn.lock index c6ece5c8..116a1232 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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== @@ -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" From 09eb22f5df153c3871405a1c9517d8065aabb01b Mon Sep 17 00:00:00 2001 From: islxyqwe Date: Wed, 19 Jun 2024 17:11:34 +0800 Subject: [PATCH 6/6] fix: json file name --- packages/graphic-walker/scripts/create-json-schema.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/graphic-walker/scripts/create-json-schema.js b/packages/graphic-walker/scripts/create-json-schema.js index 9fabb306..8ebc560b 100644 --- a/packages/graphic-walker/scripts/create-json-schema.js +++ b/packages/graphic-walker/scripts/create-json-schema.js @@ -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));