@kanaries/graphic-walker 0.3.16 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/App.d.ts +9 -2
  2. package/dist/assets/filter.worker-f09fcd6f.js.map +1 -1
  3. package/dist/assets/sort.worker-f77540ac.js.map +1 -0
  4. package/dist/assets/transform.worker-bae8e910.js.map +1 -0
  5. package/dist/assets/{viewQuery.worker-03404216.js.map → viewQuery.worker-bdb6477c.js.map} +1 -1
  6. package/dist/components/askViz/index.d.ts +6 -0
  7. package/dist/components/askViz/schemaTransform.d.ts +2 -0
  8. package/dist/components/dataTable/index.d.ts +8 -5
  9. package/dist/components/pivotTable/store.d.ts +0 -2
  10. package/dist/components/spinner.d.ts +2 -0
  11. package/dist/computation/clientComputation.d.ts +3 -0
  12. package/dist/computation/serverComputation.d.ts +8 -0
  13. package/dist/config.d.ts +3 -1
  14. package/dist/fields/filterField/tabs.d.ts +2 -1
  15. package/dist/graphic-walker.es.js +22226 -21650
  16. package/dist/graphic-walker.es.js.map +1 -1
  17. package/dist/graphic-walker.umd.js +137 -137
  18. package/dist/graphic-walker.umd.js.map +1 -1
  19. package/dist/index.d.ts +2 -0
  20. package/dist/interfaces.d.ts +93 -4
  21. package/dist/lib/execExp.d.ts +4 -4
  22. package/dist/lib/interfaces.d.ts +1 -0
  23. package/dist/lib/viewQuery.d.ts +2 -2
  24. package/dist/renderer/hooks.d.ts +8 -4
  25. package/dist/renderer/index.d.ts +2 -1
  26. package/dist/renderer/pureRenderer.d.ts +17 -1
  27. package/dist/renderer/specRenderer.d.ts +1 -0
  28. package/dist/services.d.ts +8 -5
  29. package/dist/store/commonStore.d.ts +2 -2
  30. package/dist/store/visualSpecStore.d.ts +58 -42
  31. package/dist/utils/save.d.ts +10 -2
  32. package/dist/utils/workflow.d.ts +3 -0
  33. package/dist/vis/react-vega.d.ts +3 -1
  34. package/dist/workers/sort.d.ts +2 -2
  35. package/dist/workers/transform.d.ts +5 -2
  36. package/package.json +2 -2
  37. package/src/App.tsx +46 -7
  38. package/src/components/askViz/index.tsx +92 -0
  39. package/src/components/askViz/schemaTransform.ts +38 -0
  40. package/src/components/dataTable/index.tsx +51 -11
  41. package/src/components/pivotTable/index.tsx +0 -1
  42. package/src/components/pivotTable/store.tsx +0 -16
  43. package/src/components/spinner.tsx +14 -0
  44. package/src/components/toggle.tsx +2 -2
  45. package/src/components/visualConfig/index.tsx +78 -8
  46. package/src/computation/clientComputation.ts +55 -0
  47. package/src/computation/serverComputation.ts +153 -0
  48. package/src/config.ts +15 -2
  49. package/src/dataSource/datasetConfig/index.tsx +38 -6
  50. package/src/dataSource/table.tsx +11 -2
  51. package/src/fields/filterField/filterEditDialog.tsx +11 -10
  52. package/src/fields/filterField/tabs.tsx +178 -77
  53. package/src/index.tsx +2 -0
  54. package/src/interfaces.ts +108 -5
  55. package/src/lib/execExp.ts +20 -11
  56. package/src/lib/interfaces.ts +1 -0
  57. package/src/lib/op/aggregate.ts +1 -1
  58. package/src/lib/viewQuery.ts +2 -2
  59. package/src/locales/en-US.json +11 -2
  60. package/src/locales/ja-JP.json +11 -2
  61. package/src/locales/zh-CN.json +11 -2
  62. package/src/main.tsx +1 -1
  63. package/src/renderer/hooks.ts +100 -66
  64. package/src/renderer/index.tsx +10 -6
  65. package/src/renderer/pureRenderer.tsx +40 -14
  66. package/src/renderer/specRenderer.tsx +24 -7
  67. package/src/services.ts +7 -8
  68. package/src/store/commonStore.ts +7 -7
  69. package/src/store/visualSpecStore.ts +287 -192
  70. package/src/utils/save.ts +81 -3
  71. package/src/utils/workflow.ts +148 -0
  72. package/src/vis/react-vega.tsx +21 -6
  73. package/src/vis/spec/aggregate.ts +3 -2
  74. package/src/vis/spec/stack.ts +7 -6
  75. package/src/visualSettings/index.tsx +2 -3
  76. package/src/workers/filter.worker.js +1 -1
  77. package/src/workers/sort.ts +3 -4
  78. package/src/workers/sort.worker.ts +2 -2
  79. package/src/workers/transform.ts +7 -8
  80. package/src/workers/transform.worker.js +2 -2
  81. package/src/workers/viewQuery.worker.js +2 -2
  82. package/dist/assets/sort.worker-4299a6a0.js.map +0 -1
  83. package/dist/assets/transform.worker-a12fb3d8.js.map +0 -1
@@ -0,0 +1,153 @@
1
+ import type {
2
+ IComputationFunction,
3
+ IDataQueryPayload,
4
+ IDataQueryWorkflowStep,
5
+ IDatasetStats,
6
+ IFieldStats,
7
+ IRow,
8
+ } from '../interfaces';
9
+
10
+ export const datasetStatsServer = async (service: IComputationFunction): Promise<IDatasetStats> => {
11
+ const res = (await service({
12
+ workflow: [
13
+ {
14
+ type: 'view',
15
+ query: [
16
+ {
17
+ op: 'aggregate',
18
+ groupBy: [],
19
+ measures: [
20
+ {
21
+ field: '*',
22
+ agg: 'count',
23
+ asFieldKey: 'count',
24
+ },
25
+ ],
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ })) as [{ count: number }];
31
+ return {
32
+ rowCount: res[0].count,
33
+ };
34
+ };
35
+
36
+ export const dataReadRawServer = async (
37
+ service: IComputationFunction,
38
+ pageSize: number,
39
+ pageOffset = 0
40
+ ): Promise<IRow[]> => {
41
+ const res = await service({
42
+ workflow: [
43
+ {
44
+ type: 'view',
45
+ query: [
46
+ {
47
+ op: 'raw',
48
+ fields: ['*'],
49
+ },
50
+ ],
51
+ },
52
+ ],
53
+ limit: pageSize,
54
+ offset: pageOffset * pageSize,
55
+ });
56
+ return res;
57
+ };
58
+
59
+ export const dataQueryServer = async (
60
+ service: IComputationFunction,
61
+ workflow: IDataQueryWorkflowStep[],
62
+ limit?: number,
63
+ ): Promise<IRow[]> => {
64
+ if (
65
+ workflow.length === 1 &&
66
+ workflow[0].type === 'view' &&
67
+ workflow[0].query.length === 1 &&
68
+ workflow[0].query[0].op === 'raw' &&
69
+ workflow[0].query[0].fields.length === 0
70
+ ) {
71
+ return [];
72
+ }
73
+ const res = await service({
74
+ workflow,
75
+ limit
76
+ });
77
+ return res;
78
+ };
79
+
80
+ export const fieldStatServer = async (
81
+ service: IComputationFunction,
82
+ field: string,
83
+ options: { values?: boolean; range?: boolean }
84
+ ): Promise<IFieldStats> => {
85
+ const { values = true, range = true } = options;
86
+ const COUNT_ID = `count_${field}`;
87
+ const MIN_ID = `min_${field}`;
88
+ const MAX_ID = `max_${field}`;
89
+ const valuesQueryPayload: IDataQueryPayload = {
90
+ workflow: [
91
+ {
92
+ type: 'view',
93
+ query: [
94
+ {
95
+ op: 'aggregate',
96
+ groupBy: [field],
97
+ measures: [
98
+ {
99
+ field,
100
+ agg: 'count',
101
+ asFieldKey: COUNT_ID,
102
+ },
103
+ ],
104
+ },
105
+ ],
106
+ },
107
+ ],
108
+ };
109
+ const valuesRes = values ? await service(valuesQueryPayload) : [];
110
+ const rangeQueryPayload: IDataQueryPayload = {
111
+ workflow: [
112
+ {
113
+ type: 'view',
114
+ query: [
115
+ {
116
+ op: 'aggregate',
117
+ groupBy: [],
118
+ measures: [
119
+ {
120
+ field,
121
+ agg: 'min',
122
+ asFieldKey: MIN_ID,
123
+ },
124
+ {
125
+ field,
126
+ agg: 'max',
127
+ asFieldKey: MAX_ID,
128
+ },
129
+ ],
130
+ },
131
+ ],
132
+ },
133
+ ],
134
+ };
135
+ const [rangeRes] = range
136
+ ? await service(rangeQueryPayload)
137
+ : [
138
+ {
139
+ [MIN_ID]: 0,
140
+ [MAX_ID]: 0,
141
+ },
142
+ ];
143
+
144
+ return {
145
+ values: valuesRes
146
+ .sort((a, b) => b[COUNT_ID] - a[COUNT_ID])
147
+ .map((row) => ({
148
+ value: row[field],
149
+ count: row[COUNT_ID],
150
+ })),
151
+ range: [rangeRes[MIN_ID], rangeRes[MAX_ID]],
152
+ };
153
+ };
package/src/config.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { DraggableFieldState, IStackMode } from "./interfaces";
1
+ import { DraggableFieldState, IStackMode, IVisualConfig } from "./interfaces";
2
2
 
3
3
  export const GEMO_TYPES: Readonly<string[]> = [
4
4
  'auto',
@@ -19,7 +19,8 @@ export const GEMO_TYPES: Readonly<string[]> = [
19
19
  export const STACK_MODE: Readonly<IStackMode[]> = [
20
20
  'none',
21
21
  'stack',
22
- 'normalize'
22
+ 'normalize',
23
+ 'center'
23
24
  ]
24
25
 
25
26
  export const CHART_LAYOUT_TYPE: Readonly<string[]> = [
@@ -57,4 +58,16 @@ export const CHANNEL_LIMIT = {
57
58
  export const MetaFieldKeys: Array<keyof DraggableFieldState> = [
58
59
  'dimensions',
59
60
  'measures',
61
+ ]
62
+
63
+ export const PositionChannelConfigList: Array<keyof IVisualConfig['resolve']> = [
64
+ 'x',
65
+ 'y',
66
+ ]
67
+
68
+ export const NonPositionChannelConfigList: Array<keyof IVisualConfig['resolve']> = [
69
+ 'color',
70
+ 'opacity',
71
+ 'shape',
72
+ 'size'
60
73
  ]
@@ -1,15 +1,47 @@
1
- import React from "react";
1
+ import React, { useEffect, useRef, useState } from "react";
2
2
  import DatasetTable from "../../components/dataTable";
3
3
  import { observer } from "mobx-react-lite";
4
4
  import { useGlobalStore } from "../../store";
5
+ import { useComputationFunc } from "../../renderer/hooks";
6
+ import { datasetStatsServer } from "../../computation/serverComputation";
5
7
 
6
- const DatasetConfig: React.FC = (props) => {
7
- const { commonStore, vizStore } = useGlobalStore();
8
+ const DatasetConfig: React.FC = () => {
9
+ const { commonStore } = useGlobalStore();
8
10
  const { currentDataset } = commonStore;
9
- const { dataSource, rawFields } = currentDataset;
11
+
12
+ const computationFunction = useComputationFunc();
13
+
14
+ const [count, setCount] = useState(0);
15
+ const taskIdRef = useRef(0);
16
+ const [loading, setLoading] = useState(false);
17
+
18
+ useEffect(() => {
19
+ const taskId = ++taskIdRef.current;
20
+ setLoading(true);
21
+ datasetStatsServer(computationFunction).then(res => {
22
+ if (taskId !== taskIdRef.current) {
23
+ return;
24
+ }
25
+ setCount(res.rowCount);
26
+ setLoading(false);
27
+ }).catch(err => {
28
+ if (taskId !== taskIdRef.current) {
29
+ return;
30
+ }
31
+ console.error(err);
32
+ setLoading(false);
33
+ });
34
+ return () => {
35
+ taskIdRef.current++;
36
+ };
37
+ }, [computationFunction]);
38
+
10
39
  return (
11
- <div>
12
- <DatasetTable size={100} data={dataSource} metas={rawFields}
40
+ <div className="relative">
41
+ <DatasetTable size={100}
42
+ total={count}
43
+ dataset={currentDataset}
44
+ loading={loading}
13
45
  onMetaChange={(fid, fIndex, diffMeta) => {
14
46
  commonStore.updateCurrentDatasetMetas(fid, diffMeta)
15
47
  }}
@@ -13,11 +13,20 @@ const Table: React.FC<TableProps> = (props) => {
13
13
  const { commonStore } = useGlobalStore();
14
14
  const { tmpDSRawFields, tmpDataSource } = commonStore;
15
15
 
16
+ const tempDataset = React.useMemo(() => {
17
+ return {
18
+ id: "tmp",
19
+ name: "tmp",
20
+ dataSource: tmpDataSource,
21
+ rawFields: toJS(tmpDSRawFields),
22
+ };
23
+ }, [tmpDataSource, tmpDSRawFields]);
24
+
16
25
  return (
17
26
  <DataTable
18
27
  size={size}
19
- metas={toJS(tmpDSRawFields)}
20
- data={tmpDataSource}
28
+ dataset={tempDataset}
29
+ total={tmpDataSource.length}
21
30
  onMetaChange={(fid, fIndex, diffMeta) => {
22
31
  commonStore.updateTempDatasetMetas(fid, diffMeta);
23
32
  }}
@@ -10,27 +10,28 @@ import DefaultButton from "../../components/button/default";
10
10
  import PrimaryButton from "../../components/button/primary";
11
11
  import DropdownSelect from "../../components/dropdownSelect";
12
12
 
13
- const QuantitativeRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
14
- return <Tabs field={field} onChange={onChange} tabs={["range", "one of"]} />;
13
+ const QuantitativeRuleForm: React.FC<RuleFormProps> = ({ dataset, field, onChange }) => {
14
+ return <Tabs field={field} onChange={onChange} tabs={["range", "one of"]} dataset={dataset} />;
15
15
  };
16
16
 
17
- const NominalRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
18
- return <Tabs field={field} onChange={onChange} tabs={["one of"]} />;
17
+ const NominalRuleForm: React.FC<RuleFormProps> = ({ dataset, field, onChange }) => {
18
+ return <Tabs field={field} onChange={onChange} tabs={["one of"]} dataset={dataset} />;
19
19
  };
20
20
 
21
- const OrdinalRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
22
- return <Tabs field={field} onChange={onChange} tabs={["range", "one of"]} />;
21
+ const OrdinalRuleForm: React.FC<RuleFormProps> = ({ dataset, field, onChange }) => {
22
+ return <Tabs field={field} onChange={onChange} tabs={["range", "one of"]} dataset={dataset} />;
23
23
  };
24
24
 
25
- const TemporalRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
26
- return <Tabs field={field} onChange={onChange} tabs={["temporal range", "one of"]} />;
25
+ const TemporalRuleForm: React.FC<RuleFormProps> = ({ dataset, field, onChange }) => {
26
+ return <Tabs field={field} onChange={onChange} tabs={["temporal range", "one of"]} dataset={dataset} />;
27
27
  };
28
28
 
29
29
  const EmptyForm: React.FC<RuleFormProps> = () => <React.Fragment />;
30
30
 
31
31
  const FilterEditDialog: React.FC = observer(() => {
32
- const { vizStore } = useGlobalStore();
32
+ const { vizStore, commonStore } = useGlobalStore();
33
33
  const { editingFilterIdx, draggableFieldState } = vizStore;
34
+ const { currentDataset } = commonStore;
34
35
 
35
36
  const { t } = useTranslation("translation", { keyPrefix: "filters" });
36
37
 
@@ -113,7 +114,7 @@ const FilterEditDialog: React.FC = observer(() => {
113
114
  selectedKey={uncontrolledField.fid}
114
115
  onSelect={handleSelectFilterField}
115
116
  />
116
- <Form field={uncontrolledField} onChange={handleChange} />
117
+ <Form dataset={currentDataset} field={uncontrolledField} onChange={handleChange} />
117
118
  <div className="mt-4">
118
119
  <PrimaryButton
119
120
  onClick={handleSubmit}