@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.
- package/dist/App.d.ts +9 -2
- package/dist/assets/filter.worker-f09fcd6f.js.map +1 -1
- package/dist/assets/sort.worker-f77540ac.js.map +1 -0
- package/dist/assets/transform.worker-bae8e910.js.map +1 -0
- package/dist/assets/{viewQuery.worker-03404216.js.map → viewQuery.worker-bdb6477c.js.map} +1 -1
- package/dist/components/askViz/index.d.ts +6 -0
- package/dist/components/askViz/schemaTransform.d.ts +2 -0
- package/dist/components/dataTable/index.d.ts +8 -5
- package/dist/components/pivotTable/store.d.ts +0 -2
- package/dist/components/spinner.d.ts +2 -0
- package/dist/computation/clientComputation.d.ts +3 -0
- package/dist/computation/serverComputation.d.ts +8 -0
- package/dist/config.d.ts +3 -1
- package/dist/fields/filterField/tabs.d.ts +2 -1
- package/dist/graphic-walker.es.js +22226 -21650
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +137 -137
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/interfaces.d.ts +93 -4
- package/dist/lib/execExp.d.ts +4 -4
- package/dist/lib/interfaces.d.ts +1 -0
- package/dist/lib/viewQuery.d.ts +2 -2
- package/dist/renderer/hooks.d.ts +8 -4
- package/dist/renderer/index.d.ts +2 -1
- package/dist/renderer/pureRenderer.d.ts +17 -1
- package/dist/renderer/specRenderer.d.ts +1 -0
- package/dist/services.d.ts +8 -5
- package/dist/store/commonStore.d.ts +2 -2
- package/dist/store/visualSpecStore.d.ts +58 -42
- package/dist/utils/save.d.ts +10 -2
- package/dist/utils/workflow.d.ts +3 -0
- package/dist/vis/react-vega.d.ts +3 -1
- package/dist/workers/sort.d.ts +2 -2
- package/dist/workers/transform.d.ts +5 -2
- package/package.json +2 -2
- package/src/App.tsx +46 -7
- package/src/components/askViz/index.tsx +92 -0
- package/src/components/askViz/schemaTransform.ts +38 -0
- package/src/components/dataTable/index.tsx +51 -11
- package/src/components/pivotTable/index.tsx +0 -1
- package/src/components/pivotTable/store.tsx +0 -16
- package/src/components/spinner.tsx +14 -0
- package/src/components/toggle.tsx +2 -2
- package/src/components/visualConfig/index.tsx +78 -8
- package/src/computation/clientComputation.ts +55 -0
- package/src/computation/serverComputation.ts +153 -0
- package/src/config.ts +15 -2
- package/src/dataSource/datasetConfig/index.tsx +38 -6
- package/src/dataSource/table.tsx +11 -2
- package/src/fields/filterField/filterEditDialog.tsx +11 -10
- package/src/fields/filterField/tabs.tsx +178 -77
- package/src/index.tsx +2 -0
- package/src/interfaces.ts +108 -5
- package/src/lib/execExp.ts +20 -11
- package/src/lib/interfaces.ts +1 -0
- package/src/lib/op/aggregate.ts +1 -1
- package/src/lib/viewQuery.ts +2 -2
- package/src/locales/en-US.json +11 -2
- package/src/locales/ja-JP.json +11 -2
- package/src/locales/zh-CN.json +11 -2
- package/src/main.tsx +1 -1
- package/src/renderer/hooks.ts +100 -66
- package/src/renderer/index.tsx +10 -6
- package/src/renderer/pureRenderer.tsx +40 -14
- package/src/renderer/specRenderer.tsx +24 -7
- package/src/services.ts +7 -8
- package/src/store/commonStore.ts +7 -7
- package/src/store/visualSpecStore.ts +287 -192
- package/src/utils/save.ts +81 -3
- package/src/utils/workflow.ts +148 -0
- package/src/vis/react-vega.tsx +21 -6
- package/src/vis/spec/aggregate.ts +3 -2
- package/src/vis/spec/stack.ts +7 -6
- package/src/visualSettings/index.tsx +2 -3
- package/src/workers/filter.worker.js +1 -1
- package/src/workers/sort.ts +3 -4
- package/src/workers/sort.worker.ts +2 -2
- package/src/workers/transform.ts +7 -8
- package/src/workers/transform.worker.js +2 -2
- package/src/workers/viewQuery.worker.js +2 -2
- package/dist/assets/sort.worker-4299a6a0.js.map +0 -1
- 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 = (
|
|
7
|
-
const { commonStore
|
|
8
|
+
const DatasetConfig: React.FC = () => {
|
|
9
|
+
const { commonStore } = useGlobalStore();
|
|
8
10
|
const { currentDataset } = commonStore;
|
|
9
|
-
|
|
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}
|
|
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
|
}}
|
package/src/dataSource/table.tsx
CHANGED
|
@@ -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
|
-
|
|
20
|
-
|
|
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}
|