@kanaries/graphic-walker 0.2.12 → 0.2.13
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/components/dataTable/index.d.ts +10 -0
- package/dist/components/dataTable/pagination.d.ts +10 -0
- package/dist/components/tabs/defaultTab.d.ts +14 -0
- package/dist/components/tabs/{pureTab.d.ts → editableTab.d.ts} +2 -2
- package/dist/dataSource/datasetConfig/index.d.ts +3 -0
- package/dist/graphic-walker.es.js +14228 -14025
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +132 -130
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/interfaces.d.ts +4 -0
- package/dist/segments/segmentNav.d.ts +3 -0
- package/dist/store/commonStore.d.ts +7 -1
- package/package.json +1 -1
- package/src/App.tsx +67 -42
- package/src/components/dataTable/index.tsx +187 -0
- package/src/components/dataTable/pagination.tsx +44 -0
- package/src/components/tabs/defaultTab.tsx +43 -0
- package/src/components/tabs/{pureTab.tsx → editableTab.tsx} +3 -3
- package/src/dataSource/dataSelection/index.tsx +1 -1
- package/src/dataSource/datasetConfig/index.tsx +21 -0
- package/src/dataSource/table.tsx +11 -155
- package/src/interfaces.ts +5 -0
- package/src/locales/en-US.json +8 -0
- package/src/locales/zh-CN.json +8 -0
- package/src/renderer/index.tsx +1 -0
- package/src/segments/segmentNav.tsx +58 -0
- package/src/segments/visNav.tsx +2 -2
- package/src/store/commonStore.ts +28 -2
package/src/dataSource/table.tsx
CHANGED
|
@@ -1,171 +1,27 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import styled from "styled-components";
|
|
1
|
+
import React from "react";
|
|
3
2
|
import { observer } from "mobx-react-lite";
|
|
4
|
-
import { IMutField } from "../interfaces";
|
|
5
3
|
import { useGlobalStore } from "../store";
|
|
6
|
-
import
|
|
4
|
+
import DataTable from "../components/dataTable";
|
|
5
|
+
import { toJS } from "mobx";
|
|
7
6
|
|
|
8
7
|
interface TableProps {
|
|
9
8
|
size?: number;
|
|
10
9
|
}
|
|
11
|
-
const Container = styled.div`
|
|
12
|
-
overflow-x: auto;
|
|
13
|
-
table {
|
|
14
|
-
box-sizing: content-box;
|
|
15
|
-
border-collapse: collapse;
|
|
16
|
-
font-size: 12px;
|
|
17
|
-
thead {
|
|
18
|
-
th {
|
|
19
|
-
}
|
|
20
|
-
th.number {
|
|
21
|
-
border-top: 3px solid #5cdbd3;
|
|
22
|
-
}
|
|
23
|
-
th.text {
|
|
24
|
-
border-top: 3px solid #69c0ff;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
tbody {
|
|
28
|
-
td {
|
|
29
|
-
}
|
|
30
|
-
td.number {
|
|
31
|
-
text-align: right;
|
|
32
|
-
}
|
|
33
|
-
td.text {
|
|
34
|
-
text-align: left;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
`;
|
|
39
|
-
const ANALYTIC_TYPE_LIST = ["dimension", "measure"];
|
|
40
|
-
const SEMANTIC_TYPE_LIST = ["nominal", "ordinal", "quantitative", "temporal"];
|
|
41
|
-
// function getCellType(field: IMutField): 'number' | 'text' {
|
|
42
|
-
// return field.dataType === 'number' || field.dataType === 'integer' ? 'number' : 'text';
|
|
43
|
-
// }
|
|
44
|
-
function getHeaderType(field: IMutField): "number" | "text" {
|
|
45
|
-
return field.analyticType === "dimension" ? "text" : "number";
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function getHeaderClassNames(field: IMutField) {
|
|
49
|
-
return field.analyticType === "dimension" ? "border-t-4 border-blue-400" : "border-t-4 border-teal-400";
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function getSemanticColors(field: IMutField): string {
|
|
53
|
-
switch (field.semanticType) {
|
|
54
|
-
case "nominal":
|
|
55
|
-
return "bg-indigo-100 text-indigo-800";
|
|
56
|
-
case "ordinal":
|
|
57
|
-
return "bg-purple-100 text-purple-800"
|
|
58
|
-
case "quantitative":
|
|
59
|
-
return "bg-green-100 text-green-800"
|
|
60
|
-
case "temporal":
|
|
61
|
-
return "bg-yellow-100 text-yellow-800"
|
|
62
|
-
default:
|
|
63
|
-
return "bg-gray-400";
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
10
|
|
|
67
11
|
const Table: React.FC<TableProps> = (props) => {
|
|
68
12
|
const { size = 10 } = props;
|
|
69
13
|
const { commonStore } = useGlobalStore();
|
|
70
14
|
const { tmpDSRawFields, tmpDataSource } = commonStore;
|
|
71
|
-
const { t } = useTranslation();
|
|
72
|
-
|
|
73
|
-
const analyticTypeList = useMemo<{ value: string; label: string }[]>(() => {
|
|
74
|
-
return ANALYTIC_TYPE_LIST.map((at) => ({
|
|
75
|
-
value: at,
|
|
76
|
-
label: t(`constant.analytic_type.${at}`),
|
|
77
|
-
}));
|
|
78
|
-
}, []);
|
|
79
|
-
|
|
80
|
-
const semanticTypeList = useMemo<{ value: string; label: string }[]>(() => {
|
|
81
|
-
return SEMANTIC_TYPE_LIST.map((st) => ({
|
|
82
|
-
value: st,
|
|
83
|
-
label: t(`constant.semantic_type.${st}`),
|
|
84
|
-
}));
|
|
85
|
-
}, []);
|
|
86
15
|
|
|
87
16
|
return (
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
getHeaderClassNames(field) +
|
|
97
|
-
" whitespace-nowrap py-3.5 px-6 text-left text-xs font-semibold text-gray-900 sm:pl-6"
|
|
98
|
-
}
|
|
99
|
-
>
|
|
100
|
-
<b>{field.name || field.fid}</b>
|
|
101
|
-
<div>
|
|
102
|
-
<select
|
|
103
|
-
className={
|
|
104
|
-
"px-2 py font-normal mt-2 rounded-full text-xs text-white " +
|
|
105
|
-
(field.analyticType === "dimension" ? "bg-blue-500" : "bg-teal-500")
|
|
106
|
-
}
|
|
107
|
-
// className="border-b border-gray-200 bg-gray-50 pl-0 mt-2 font-light"
|
|
108
|
-
value={field.analyticType}
|
|
109
|
-
onChange={(e) => {
|
|
110
|
-
commonStore.updateTempFieldAnalyticType(
|
|
111
|
-
field.fid,
|
|
112
|
-
e.target.value as IMutField["analyticType"]
|
|
113
|
-
);
|
|
114
|
-
}}
|
|
115
|
-
>
|
|
116
|
-
{analyticTypeList.map((type) => (
|
|
117
|
-
<option key={type.value} value={type.value}>
|
|
118
|
-
{type.label}
|
|
119
|
-
</option>
|
|
120
|
-
))}
|
|
121
|
-
</select>
|
|
122
|
-
</div>
|
|
123
|
-
<div>
|
|
124
|
-
<select
|
|
125
|
-
className={
|
|
126
|
-
"inline-block px-2.5 py-0.5 text-xs font-medium mt-1 rounded-full text-xs text-white " +
|
|
127
|
-
getSemanticColors(field)
|
|
128
|
-
}
|
|
129
|
-
// className="border-b border-gray-200 bg-gray-50 pl-0 mt-2 font-light"
|
|
130
|
-
value={field.semanticType}
|
|
131
|
-
onChange={(e) => {
|
|
132
|
-
commonStore.updateTempFieldSemanticType(
|
|
133
|
-
field.fid,
|
|
134
|
-
e.target.value as IMutField["semanticType"]
|
|
135
|
-
);
|
|
136
|
-
}}
|
|
137
|
-
>
|
|
138
|
-
{semanticTypeList.map((type) => (
|
|
139
|
-
<option key={type.value} value={type.value}>
|
|
140
|
-
{type.label}
|
|
141
|
-
</option>
|
|
142
|
-
))}
|
|
143
|
-
</select>
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
</th>
|
|
147
|
-
))}
|
|
148
|
-
</tr>
|
|
149
|
-
</thead>
|
|
150
|
-
<tbody className="divide-y divide-gray-200 bg-white">
|
|
151
|
-
{tmpDataSource.slice(0, size).map((record, index) => (
|
|
152
|
-
<tr className={"divide-x divide-gray-200 " + (index % 2 ? "bg-gray-50" : "")} key={index}>
|
|
153
|
-
{tmpDSRawFields.map((field) => (
|
|
154
|
-
<td
|
|
155
|
-
key={field.fid + index}
|
|
156
|
-
className={
|
|
157
|
-
getHeaderType(field) +
|
|
158
|
-
" whitespace-nowrap py-2 pl-4 pr-3 text-xs text-gray-500 sm:pl-6"
|
|
159
|
-
}
|
|
160
|
-
>
|
|
161
|
-
{record[field.fid]}
|
|
162
|
-
</td>
|
|
163
|
-
))}
|
|
164
|
-
</tr>
|
|
165
|
-
))}
|
|
166
|
-
</tbody>
|
|
167
|
-
</table>
|
|
168
|
-
</Container>
|
|
17
|
+
<DataTable
|
|
18
|
+
size={size}
|
|
19
|
+
metas={toJS(tmpDSRawFields)}
|
|
20
|
+
data={tmpDataSource}
|
|
21
|
+
onMetaChange={(fid, fIndex, diffMeta) => {
|
|
22
|
+
commonStore.updateTempDatasetMetas(fid, diffMeta);
|
|
23
|
+
}}
|
|
24
|
+
/>
|
|
169
25
|
);
|
|
170
26
|
};
|
|
171
27
|
|
package/src/interfaces.ts
CHANGED
|
@@ -178,4 +178,9 @@ export interface IVisSpec {
|
|
|
178
178
|
readonly name?: [string, Record<string, any>?];
|
|
179
179
|
readonly encodings: DeepReadonly<DraggableFieldState>;
|
|
180
180
|
readonly config: DeepReadonly<IVisualConfig>;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export enum ISegmentKey {
|
|
184
|
+
vis = 'vis',
|
|
185
|
+
data = 'data'
|
|
181
186
|
}
|
package/src/locales/en-US.json
CHANGED
|
@@ -81,6 +81,10 @@
|
|
|
81
81
|
"App": {
|
|
82
82
|
"labels": {
|
|
83
83
|
"data_interpretation": "Interpret Data"
|
|
84
|
+
},
|
|
85
|
+
"segments": {
|
|
86
|
+
"vis": "Visualization",
|
|
87
|
+
"data": "Data"
|
|
84
88
|
}
|
|
85
89
|
},
|
|
86
90
|
"DataSource": {
|
|
@@ -177,5 +181,9 @@
|
|
|
177
181
|
"children_major_factor": "major factor",
|
|
178
182
|
"children_outlier": "outlier"
|
|
179
183
|
}
|
|
184
|
+
},
|
|
185
|
+
"actions": {
|
|
186
|
+
"prev": "Previous",
|
|
187
|
+
"next": "Next"
|
|
180
188
|
}
|
|
181
189
|
}
|
package/src/locales/zh-CN.json
CHANGED
|
@@ -81,6 +81,10 @@
|
|
|
81
81
|
"App": {
|
|
82
82
|
"labels": {
|
|
83
83
|
"data_interpretation": "数据解读"
|
|
84
|
+
},
|
|
85
|
+
"segments": {
|
|
86
|
+
"vis": "可视化",
|
|
87
|
+
"data": "数据"
|
|
84
88
|
}
|
|
85
89
|
},
|
|
86
90
|
"DataSource": {
|
|
@@ -177,5 +181,9 @@
|
|
|
177
181
|
"children_major_factor": "子节点主要因素",
|
|
178
182
|
"children_outlier": "子节点异常"
|
|
179
183
|
}
|
|
184
|
+
},
|
|
185
|
+
"actions": {
|
|
186
|
+
"prev": "向前",
|
|
187
|
+
"next": "向后"
|
|
180
188
|
}
|
|
181
189
|
}
|
package/src/renderer/index.tsx
CHANGED
|
@@ -32,6 +32,7 @@ const ReactiveRenderer = forwardRef<IReactVegaHandler, {}>(function ReactiveRend
|
|
|
32
32
|
|
|
33
33
|
const handleGeomClick = useCallback((values: any, e: any) => {
|
|
34
34
|
if (shouldTriggerMenu) {
|
|
35
|
+
e.stopPropagation();
|
|
35
36
|
runInAction(() => {
|
|
36
37
|
commonStore.showEmbededMenu([e.pageX, e.pageY])
|
|
37
38
|
commonStore.setFilters(values);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React, { Fragment, useCallback } from "react";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import DefaultTab, { ITabOption } from "../components/tabs/defaultTab";
|
|
4
|
+
import { useGlobalStore } from "../store";
|
|
5
|
+
import { ChartBarIcon, ChartPieIcon, CircleStackIcon } from "@heroicons/react/24/outline";
|
|
6
|
+
import { ISegmentKey } from "../interfaces";
|
|
7
|
+
import { useTranslation } from "react-i18next";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const ADD_KEY = '_add';
|
|
11
|
+
|
|
12
|
+
const SegmentNav: React.FC = (props) => {
|
|
13
|
+
const { vizStore, commonStore } = useGlobalStore();
|
|
14
|
+
const { visIndex, visList } = vizStore;
|
|
15
|
+
const { currentDataset, segmentKey } = commonStore;
|
|
16
|
+
const { t } = useTranslation();
|
|
17
|
+
|
|
18
|
+
const tabs: ITabOption[] = [
|
|
19
|
+
{
|
|
20
|
+
key: ISegmentKey.data,
|
|
21
|
+
label: <div className="flex">
|
|
22
|
+
<CircleStackIcon className="w-4 mr-2" /> {t('App.segments.data')}
|
|
23
|
+
</div>
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
key: ISegmentKey.vis,
|
|
27
|
+
label: <div className="flex">
|
|
28
|
+
<ChartPieIcon className="w-4 mr-2" /> {t('App.segments.vis')}
|
|
29
|
+
</div>
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const visSelectionHandler = useCallback((tabKey: string, tabIndex: number) => {
|
|
34
|
+
if (tabKey === ADD_KEY) {
|
|
35
|
+
vizStore.addVisualization();
|
|
36
|
+
vizStore.initMetaState(currentDataset)
|
|
37
|
+
} else {
|
|
38
|
+
vizStore.selectVisualization(tabIndex);
|
|
39
|
+
}
|
|
40
|
+
}, [currentDataset, vizStore])
|
|
41
|
+
|
|
42
|
+
const editLabelHandler = useCallback((content: string, tabIndex: number) => {
|
|
43
|
+
vizStore.setVisName(tabIndex, content)
|
|
44
|
+
}, [])
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<DefaultTab
|
|
48
|
+
selectedKey={segmentKey}
|
|
49
|
+
tabs={tabs}
|
|
50
|
+
onEditLabel={editLabelHandler}
|
|
51
|
+
onSelected={(k) => {
|
|
52
|
+
commonStore.setSegmentKey(k as ISegmentKey)
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default observer(SegmentNav);
|
package/src/segments/visNav.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback } from "react";
|
|
2
2
|
import { observer } from "mobx-react-lite";
|
|
3
|
-
import
|
|
3
|
+
import EditableTabs, { ITabOption } from "../components/tabs/editableTab";
|
|
4
4
|
import { useGlobalStore } from "../store";
|
|
5
5
|
|
|
6
6
|
|
|
@@ -36,7 +36,7 @@ const VisNav: React.FC = (props) => {
|
|
|
36
36
|
}, [])
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
|
-
<
|
|
39
|
+
<EditableTabs
|
|
40
40
|
selectedKey={visList[visIndex].visId}
|
|
41
41
|
tabs={tabs}
|
|
42
42
|
onEditLabel={editLabelHandler}
|
package/src/store/commonStore.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataSet, Filters, IDataSet, IDataSetInfo, IDataSource, IMutField, IRow } from '../interfaces';
|
|
1
|
+
import { DataSet, Filters, IDataSet, IDataSetInfo, IDataSource, IMutField, IRow, ISegmentKey } from '../interfaces';
|
|
2
2
|
import { makeAutoObservable, observable, toJS } from 'mobx';
|
|
3
3
|
import { transData } from '../dataSource/utils';
|
|
4
4
|
import { extendCountField } from '../utils';
|
|
@@ -13,8 +13,9 @@ export class CommonStore {
|
|
|
13
13
|
public showDSPanel: boolean = false;
|
|
14
14
|
public showInsightBoard: boolean = false;
|
|
15
15
|
public vizEmbededMenu: { show: boolean; position: [number, number] } = { show: false, position: [0, 0] };
|
|
16
|
-
|
|
16
|
+
public showDataConfig: boolean = false;
|
|
17
17
|
public filters: Filters = {};
|
|
18
|
+
public segmentKey: ISegmentKey = ISegmentKey.vis;
|
|
18
19
|
constructor () {
|
|
19
20
|
this.datasets = [];
|
|
20
21
|
this.dataSources = [];
|
|
@@ -44,9 +45,15 @@ export class CommonStore {
|
|
|
44
45
|
dataSource: []
|
|
45
46
|
}
|
|
46
47
|
}
|
|
48
|
+
public setSegmentKey (sk: ISegmentKey) {
|
|
49
|
+
this.segmentKey = sk;
|
|
50
|
+
}
|
|
47
51
|
public setShowDSPanel (show: boolean) {
|
|
48
52
|
this.showDSPanel = show;
|
|
49
53
|
}
|
|
54
|
+
public setShowDataConfig (show: boolean) {
|
|
55
|
+
this.showDataConfig = show;
|
|
56
|
+
}
|
|
50
57
|
public setShowInsightBoard (show: boolean) {
|
|
51
58
|
this.showInsightBoard = show;
|
|
52
59
|
}
|
|
@@ -66,6 +73,25 @@ export class CommonStore {
|
|
|
66
73
|
this.tmpDSRawFields = fields;
|
|
67
74
|
}
|
|
68
75
|
|
|
76
|
+
public updateCurrentDatasetMetas (fid: string, diffMeta: Partial<IMutField>) {
|
|
77
|
+
const dataset = this.datasets[this.dsIndex];
|
|
78
|
+
const field = dataset.rawFields.find(f => f.fid === fid);
|
|
79
|
+
if (field) {
|
|
80
|
+
for (let mk in diffMeta) {
|
|
81
|
+
field[mk] = diffMeta[mk];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public updateTempDatasetMetas (fid: string, diffMeta: Partial<IMutField>) {
|
|
87
|
+
const field = this.tmpDSRawFields.find(f => f.fid === fid);
|
|
88
|
+
if (field) {
|
|
89
|
+
for (let mk in diffMeta) {
|
|
90
|
+
field[mk] = diffMeta[mk];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
69
95
|
public updateTempFieldAnalyticType (fieldKey: string, analyticType: IMutField['analyticType']) {
|
|
70
96
|
const field = this.tmpDSRawFields.find(f => f.fid === fieldKey);
|
|
71
97
|
if (field) {
|