diff --git a/README.md b/README.md index 13d714cf..8fad9c33 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ Graphic Walker is a lite tableau style visual analysis interface. It is used for You can also use Graphic Walker as a lite tableau style analysis app independently. It can be used as an independent app or an embeding module. +more details can be found in README.md in graphic-walker folder. + ## Examples + [DataSet: NASA - Kepler](https://www.kaggle.com/nasa/kepler-exoplanet-search-results) diff --git a/README.zh-CN.md b/README.zh-CN.md index e15713b1..43ac9e81 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -33,6 +33,8 @@ Rath中包含一个tableau风格的自助分析工具,它是一个和基于图 这个模块从工程上是独立的,你可以把它单独作为一个分析应用来使用或者作为一个嵌入式的模块(Rath便是这也使用它)。 +详细的使用方式详见graphic-walker文件夹下的README.md文件 + ## 案例 diff --git a/packages/frontend/package.json b/packages/frontend/package.json index d9dd6d36..8a589655 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -47,7 +47,7 @@ "vega": "^5.19.1", "vega-embed": "^6.15.1", "vega-lite": "^4.17.0", - "visual-insights": "0.6.2", + "visual-insights": "0.6.3", "web-vitals": "^0.2.4", "worker-loader": "^3.0.7", "yarn": "^1.19.0" diff --git a/packages/frontend/src/pages/visualInterface/index.tsx b/packages/frontend/src/pages/visualInterface/index.tsx index ebe4bf06..c14a4dce 100644 --- a/packages/frontend/src/pages/visualInterface/index.tsx +++ b/packages/frontend/src/pages/visualInterface/index.tsx @@ -2,12 +2,25 @@ import React from 'react'; import { observer } from 'mobx-react-lite'; import { GraphicWalker } from 'graphic-walker'; import { useGlobalStore } from '../../store'; +import { useMemo } from 'react'; +import { IMutField } from 'graphic-walker/dist/interfaces'; +import 'graphic-walker/dist/style.css'; const VisualInterface: React.FC = props => { const { dataSourceStore } = useGlobalStore(); // TODO: discuss use clean data from dataSourceStore or cooked data from dataPipeline? - const { cleanedData, dimensions, measures } = dataSourceStore; - return + const { cleanedData, mutFields } = dataSourceStore; + const gwRawFields = useMemo(() => { + return mutFields.map(f => { + return { + key: f.fid, + semanticType: f.semanticType, + dataType: '?', + analyticType: f.analyticType + } + }) + }, [mutFields]) + return } export default observer(VisualInterface); \ No newline at end of file diff --git a/packages/graphic-walker/README.md b/packages/graphic-walker/README.md new file mode 100644 index 00000000..ce721bac --- /dev/null +++ b/packages/graphic-walker/README.md @@ -0,0 +1,33 @@ +# Graphic Walker +Graphic Walker is a lite tableau style visual analysis interface. It is used for cases when users have specific analytic target or user want to analysis further result based on the recommanded results by Rath's auto insights. + +** You can also use Graphic Walker as a lite tableau style analysis app independently. It can be used as an independent app or an embeding module. ** + +Main features: + ++ A grammar of graphics based visual analytic user interface where use can build visualization from low level visual channel encodings. ++ A Data Explainer which explain some why some patterns occur / what may cause them. + +## Usage +```bash +cd graphic-waler +yarn install +npm run build +``` + +In your app: +```typescript +import { GraphicWalker } from 'graphic-walker'; +import 'graphic-walker/dist/style.css' + +const YourEmbeddingTableauStyleApp: React.FC = props => { + const { dataSource, fields } = props; + + return +} + +export default YourEmbeddingTableauStyleApp; +``` \ No newline at end of file diff --git a/packages/graphic-walker/package.json b/packages/graphic-walker/package.json index 213d210c..8cd994ca 100644 --- a/packages/graphic-walker/package.json +++ b/packages/graphic-walker/package.json @@ -20,16 +20,21 @@ }, "types": "./dist/index.d.ts", "dependencies": { - "@fluentui/react": "^8.29.0", - "@tableau/tableau-ui": "^3.2.0", + "@heroicons/react": "^1.0.4", + "autoprefixer": "^10.3.5", + "mobx": "^6.3.3", + "mobx-react-lite": "^3.2.1", + "postcss": "^8.3.7", "react": "^17.0.2", "react-beautiful-dnd": "^13.1.0", "react-dom": "^17.0.2", "react-json-view": "^1.21.3", "styled-components": "^5.3.0", + "tailwindcss": "^2.2.15", "vega": "^5.20.2", "vega-embed": "^6.18.2", - "vega-lite": "^5.1.0" + "vega-lite": "^5.1.0", + "visual-insights": "0.6.3" }, "devDependencies": { "@rollup/plugin-typescript": "^8.2.5", diff --git a/packages/graphic-walker/postcss.config.js b/packages/graphic-walker/postcss.config.js new file mode 100644 index 00000000..f7bd3abe --- /dev/null +++ b/packages/graphic-walker/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + } +} \ No newline at end of file diff --git a/packages/graphic-walker/src/App.tsx b/packages/graphic-walker/src/App.tsx index 6e0a4d27..068c82a8 100644 --- a/packages/graphic-walker/src/App.tsx +++ b/packages/graphic-walker/src/App.tsx @@ -1,128 +1,52 @@ -import React, { useState, useEffect, useMemo, useCallback } from 'react'; -import DraggableFields, { DraggableFieldState } from './Fields'; -import { Record, Filters, Field, IField } from './interfaces'; -import ReactVega from './vis/react-vega'; -import { GEMO_TYPES } from './config'; -import { LiteForm } from './components/liteForm'; -import { Container } from './components/container'; +import React, { useState, useEffect } from 'react'; +import { Record, IMutField } from './interfaces'; +import VisualSettings from './visualSettings'; +import { Container, NestContainer } from './components/container'; import ClickMenu from './components/clickMenu'; -import InsightBoard from './InsightBoard'; -import { Button, DropdownSelect, Checkbox } from '@tableau/tableau-ui'; -import { ProgressIndicator } from '@fluentui/react' -import Modal from './components/modal'; -import DataSourcePanel from './dataSource/index'; -import { useLocalState } from './store'; +import InsightBoard from './InsightBoard/index'; +import PosFields from './Fields/posFields'; +import AestheticFields from './Fields/AestheticFields'; +import DatasetFields from './Fields/DatasetFields'; +import ReactiveRenderer from './renderer/index'; +import DataSourceSegment from './dataSource/index'; +import { useGlobalStore } from './store'; import { preAnalysis, destroyWorker } from './services' - - -const INIT_DF_STATE: DraggableFieldState = { - fields: [], - rows: [], - columns: [], - color: [], - opacity: [], - size: [], -}; +import { observer } from 'mobx-react-lite'; +import { toJS } from 'mobx'; +import "tailwindcss/tailwind.css" +import './index.css' export interface EditorProps { dataSource?: Record[]; - dimensions?: string[]; - measures?: string[]; + rawFields?: IMutField[]; } const App: React.FC = props => { - const { dataSource = [], dimensions = [], measures = [] } = props; - const [GS, updateGS] = useLocalState(); - const [fields, setFields] = useState([]); - const [fstate, setFstate] = useState(INIT_DF_STATE); - const [geomType, setGeomType] = useState(GEMO_TYPES[0].value); - const [aggregated, setAggregated] = useState(true); - const [position, setPosition] = useState<[number, number]>([0, 0]); - const [showMenu, setShowMenu] = useState(false); - const [showInsight, setShowInsight] = useState(false); - const [filters, setFilters] = useState({}); - const [showDSPanel, setShowDSPanel] = useState(false); + const { dataSource = [], rawFields = [] } = props; + const { commonStore } = useGlobalStore(); const [insightReady, setInsightReady] = useState(true); - // const [ds, setDS] = useState({ dimensions: [], measures: [], dataSource: []}); - const [newDBIndex, setNewDBIndex] = useState(0); - // useEffect(() => { - // const target = DS_LIST.find(d => d.value === dsKey); - // if (target) { - // setDS(target.service()) - // } - // }, [dsKey]) + + const { currentDataset, datasets, vizEmbededMenu } = commonStore; + + // use as an embeding module, use outside datasource from props. useEffect(() => { if (dataSource.length > 0) { - const fields: IField[] = []; - dimensions.forEach(f => { - fields.push({ - key: f, - type: 'D', - analyticType: 'dimension' - }) - }); - measures.forEach(f => { - fields.push({ - key: f, - type: 'D', - analyticType: 'measure' - }) - }); - updateGS(state => { - state.dataBase = [ - { - id: 'default', - name: 'context dataset', - dataSource: dataSource, - fields - } - ] + commonStore.addAndUseDS({ + name: 'context dataset', + dataSource: dataSource, + rawFields }) } - }, [dataSource, dimensions, measures]) - useEffect(() => { - const fs: Field[] = []; - const ds = GS.dataBase[GS.currentDBIndex]; - if (ds) { - ds.fields.forEach((f) => { - fs.push({ - id: f.key, - name: f.key, - type: f.analyticType === 'dimension' ? 'D' : 'M', - aggName: f.analyticType === 'measure' ? 'sum' : undefined, - }) - }) - setFields(fs) - } - }, [GS.currentDBIndex, GS.dataBase]); - - const viewDimensions = useMemo(() => { - return [ - ...fstate.rows, - ...fstate.columns, - ...fstate.color, - ...fstate.opacity, - ...fstate.size - ].filter(f => f.type === 'D'); - }, [fstate]) - const viewMeasures = useMemo(() => { - return [ - ...fstate.rows, - ...fstate.columns, - ...fstate.color, - ...fstate.opacity, - ...fstate.size, - ].filter((f) => f.type === 'M'); - }, [fstate]); + }, [dataSource, rawFields]) + // do preparation analysis work when using a new dataset useEffect(() => { - const ds = GS.dataBase[GS.currentDBIndex]; - if (ds) { + const ds = currentDataset; + if (ds && ds.dataSource.length > 0 && ds.rawFields.length > 0) { setInsightReady(false) preAnalysis({ dataSource: ds.dataSource, - dimensions: ds.fields.filter(f => f.analyticType === 'dimension').map(f => f.key), - measures: ds.fields.filter(f => f.analyticType === 'measure').map(f => f.key) + fields: toJS(ds.rawFields) }).then(() => { setInsightReady(true); }) @@ -130,153 +54,45 @@ const App: React.FC = props => { return () => { destroyWorker(); } - }, [GS.currentDBIndex, GS.dataBase]); - - const createDB = useCallback(() => { - updateGS(draft => { - const newLastIndex = draft.dataBase.length; - draft.dataBase.push({ - id: 'ds_' + newLastIndex, - name: '新数据源' + newLastIndex, - dataSource: [], - fields: [] - }) - setNewDBIndex(newLastIndex); - }) - }, []); + }, [currentDataset]); return (
+ + - {!insightReady && } - - { - // setDSKey(e.target.value); - updateGS((draft) => { - const index = draft.dataBase.findIndex((ds) => ds.id === e.target.value) - draft.currentDBIndex = index - }) - }} - > - {GS.dataBase.map((ds) => ( - - ))} - - - {showDSPanel && ( - { - setShowDSPanel(false) - }} - > - { - setShowDSPanel(false) - }} - /> - - )} - {insightReady && iready} - - - { - setFstate(state) - }} - fields={fields} - /> - - - -
- { - setAggregated(e.target.checked) - }} - > - 聚合度量 - +
+
+ +
+
+ +
+
+
+
-
- - { - setGeomType(e.target.value) - }} - > - {GEMO_TYPES.map((g) => ( - - ))} - -
- + + {datasets.length > 0 && } + + {vizEmbededMenu.show && ( + +
{ + commonStore.closeEmbededMenu(); + commonStore.setShowInsightBoard(true) + }} + > + 深度解读 +
+
+ )} +
+
+
- {GS.dataBase[GS.currentDBIndex] && ( - - {showInsight && ( - { - setShowInsight(false) - }} - > - - - )} - {showMenu && ( - -
{ - setShowMenu(false) - setShowInsight(true) - }} - > - 深度解读 -
-
- )} - - { - setFilters(values) - setPosition([e.pageX, e.pageY]) - setShowMenu(true) - }} - /> -
- )}
) } -export default App; +export default observer(App); diff --git a/packages/graphic-walker/src/Fields/AestheticFields.tsx b/packages/graphic-walker/src/Fields/AestheticFields.tsx new file mode 100644 index 00000000..240f144c --- /dev/null +++ b/packages/graphic-walker/src/Fields/AestheticFields.tsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { + DragDropContext, + Droppable, + Draggable, + DropResult, + ResponderProvided, + DraggableLocation, +} from "react-beautiful-dnd"; +import { AGGREGATOR_LIST, DRAGGABLE_STATE_KEYS } from './fieldsContext'; +import { AestheticFieldContainer, FieldsContainer, Pill } from './components' +import { useGlobalStore } from '../store/index' + +const aestheticFields = DRAGGABLE_STATE_KEYS.filter(f => ['color', 'opacity', 'size'].includes(f.id)); + +const AestheticFields: React.FC = props => { + const { vizStore } = useGlobalStore(); + const { draggableFieldState } = vizStore; + return
+ { + aestheticFields.map(dkey => + + {(provided, snapshot) => ( + + {draggableFieldState[dkey.id].map((f, index) => ( + + {(provided, snapshot) => { + return ( + + {f.name}  + {f.type === 'M' && ( + + )} + + ); + }} + + ))} + + )} + + ) + } +
+} + +export default AestheticFields; \ No newline at end of file diff --git a/packages/graphic-walker/src/Fields/DatasetFields.tsx b/packages/graphic-walker/src/Fields/DatasetFields.tsx new file mode 100644 index 00000000..920fe994 --- /dev/null +++ b/packages/graphic-walker/src/Fields/DatasetFields.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { FieldListContainer, FieldsContainer, Pill } from "./components"; +import { NestContainer } from '../components/container' +import { observer } from 'mobx-react-lite'; +import { + DragDropContext, + Droppable, + Draggable, + DropResult, + ResponderProvided, + DraggableLocation, + } from "react-beautiful-dnd"; + +import { AGGREGATOR_LIST, DRAGGABLE_STATE_KEYS } from './fieldsContext'; +import { useGlobalStore } from '../store'; + +const rowsAndCols = DRAGGABLE_STATE_KEYS.filter(f => f.id === 'fields'); +const DatasetFields: React.FC = props => { + const { vizStore } = useGlobalStore(); + const { draggableFieldState } = vizStore; + + return +

字段列表

+ { + rowsAndCols.map(dkey =>
+ + {(provided, snapshot) => ( +
+ {draggableFieldState[dkey.id].map((f, index) => ( + + {(provided, snapshot) => { + return ( +
+ {f.name}  +
+ ); + }} +
+ ))} +
+ )} +
+
) + } +
+} + +export default observer(DatasetFields); \ No newline at end of file diff --git a/packages/graphic-walker/src/Fields/components.tsx b/packages/graphic-walker/src/Fields/components.tsx index 4d728207..1d25c332 100644 --- a/packages/graphic-walker/src/Fields/components.tsx +++ b/packages/graphic-walker/src/Fields/components.tsx @@ -1,5 +1,25 @@ import React from "react"; import styled from "styled-components"; +import { COLORS } from "../config"; + +export const AestheticSegment = styled.div` + border: 1px solid #dfe3e8; + font-size: 12px; + margin: 0.2em; + + .aes-header{ + border-bottom: 1px solid #dfe3e8; + background-color: #f5f5f5; + padding: 0.6em; + h4 { + font-weight: 400; + } + } + .aes-container{ + + } + +` export const FieldListContainer: React.FC<{ name: string }> = (props) => { return ( @@ -12,21 +32,32 @@ export const FieldListContainer: React.FC<{ name: string }> = (props) => { ); }; +export const AestheticFieldContainer: React.FC<{ name: string }> = props => { + return ( + +
+

{props.name}

+
+
{props.children}
+
+ ); +} + export const FieldsContainer = styled.div` display: flex; padding: 0.2em; min-height: 2.4em; - display: flex; - flex-wrap: wrap; - >div{ - margin: 1px; - } + flex-wrap: wrap; + >div{ + margin: 1px; + } `; export const FieldListSegment = styled.div` display: flex; border: 1px solid #dfe3e8; margin: 0.2em; + font-size: 12px; div.fl-header { /* flex-basis: 100px; */ width: 100px; @@ -57,3 +88,28 @@ export const FieldLabel = styled.div<{ highlight?: boolean; type?: 'D' | 'M' }>` props.highlight ? "box-shadow: 0px 0px 5px 1px #21ba45" : null}; position: relative; `; + +export const Pill = styled.div<{colType: 'discrete' | 'continuous'}>` + background-color: ${props => props.colType === 'continuous' ? COLORS.measure : COLORS.dimension}; + color: #fff; + -moz-user-select: none; + -ms-user-select: none; + -webkit-align-items: center; + -webkit-user-select: none; + align-items: center; + border-color: transparent; + border-radius: 10px; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + cursor: default; + display: -webkit-flex; + display: flex; + font-size: 12px; + height: 20px; + min-width: 150px; + overflow-y: hidden; + padding: 0 10px; + user-select: none; +` + diff --git a/packages/graphic-walker/src/Fields/fieldsContext.tsx b/packages/graphic-walker/src/Fields/fieldsContext.tsx new file mode 100644 index 00000000..b99c8933 --- /dev/null +++ b/packages/graphic-walker/src/Fields/fieldsContext.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { Field } from '../interfaces'; +import { + DragDropContext, + Droppable, + Draggable, + DropResult, + ResponderProvided, + DraggableLocation, +} from "react-beautiful-dnd"; +import { useGlobalStore } from '../store'; +import { useCallback } from 'react'; + +export interface DraggableFieldState { + fields: Field[]; + rows: Field[]; + columns: Field[]; + color: Field[]; + opacity: Field[]; + size: Field[]; +} + +interface DraggableFieldsProps { + fields: Field[]; + onStateChange?: (state: DraggableFieldState) => void; +} + +export const FieldsContextWrapper: React.FC = props => { + const { vizStore } = useGlobalStore(); + const onDragEnd = useCallback((result: DropResult, provided: ResponderProvided) => { + if (!result.destination) { + vizStore.removeField(result.source.droppableId as keyof DraggableFieldState, result.source.index) + return; + } + const destination = result.destination as DraggableLocation; + if (destination.droppableId === result.source.droppableId) { + if (destination.index === result.source.index) return; + vizStore.reorderField(destination.droppableId as keyof DraggableFieldState, result.source.index, destination.index); + } else { + let sourceKey = result.source + .droppableId as keyof DraggableFieldState; + let targetKey = destination + .droppableId as keyof DraggableFieldState; + vizStore.moveField(sourceKey, result.source.index, targetKey, destination.index) + } + }, []) + return + { props.children } + +} + +export default FieldsContextWrapper; + +export const DRAGGABLE_STATE_KEYS: Array<{ + id: keyof DraggableFieldState; + name: string; + mode: number + }> = [ + { id: 'fields', name: '字段', mode: 0 }, + { id: 'columns', name: '列', mode: 0 }, + { id: 'rows', name: '行', mode: 0 }, + { id: 'color', name: '颜色', mode: 1 }, + { id: 'opacity', name: '透明度', mode: 1 }, + { id: 'size', name: '大小', mode: 1 }, +]; + +export const AGGREGATOR_LIST = [ + { + value: "sum", + label: "求和", + }, + { + value: "mean", + label: "平均值", + }, + { + value: "count", + label: "计数", + }, +]; diff --git a/packages/graphic-walker/src/Fields/index.tsx b/packages/graphic-walker/src/Fields/index.tsx deleted file mode 100644 index 38ce0171..00000000 --- a/packages/graphic-walker/src/Fields/index.tsx +++ /dev/null @@ -1,262 +0,0 @@ -import React, { useState, useEffect, useCallback } from "react"; -import { - DragDropContext, - Droppable, - Draggable, - DropResult, - ResponderProvided, - DraggableLocation, -} from "react-beautiful-dnd"; -import styled from "styled-components"; -import produce from "immer"; -import { FieldListContainer, FieldsContainer } from "./components"; -import { move, reorder } from "./utils"; -import { Field } from "../interfaces"; -import { Container } from '../components/container' -import { Pill, DropdownSelect } from '@tableau/tableau-ui'; - -const RootContainer = styled.div` - font-size: 12px; -`; - -const aggregatorList = [ - { - value: "sum", - label: "求和", - }, - { - value: "mean", - label: "平均值", - }, - { - value: "count", - label: "计数", - }, -]; - -export interface DraggableFieldState { - fields: Field[]; - rows: Field[]; - columns: Field[]; - color: Field[]; - opacity: Field[]; - size: Field[]; -} - -// const draggableStateKeys = Object.keys(initDraggableState) as Array< -// keyof DraggableFieldState -// >; - -const draggableStateKeys: Array<{ - id: keyof DraggableFieldState; - name: string; - mode: number -}> = [ - { id: 'fields', name: '字段', mode: 0 }, - { id: 'columns', name: '列', mode: 0 }, - { id: 'rows', name: '行', mode: 0 }, - { id: 'color', name: '颜色', mode: 1 }, - { id: 'opacity', name: '透明度', mode: 1 }, - { id: 'size', name: '大小', mode: 1 }, -]; - - -interface DraggableFieldsProps { - fields: Field[]; - onStateChange?: (state: DraggableFieldState) => void; -} - -const DraggableFields: React.FC = (props) => { - const { fields = [], onStateChange } = props; - const [state, setState] = useState({ - fields: [], - rows: [], - columns: [], - color: [], - opacity: [], - size: [] - }); - useEffect(() => { - setState({ - fields, - rows: [], - columns: [], - color: [], - opacity: [], - size: [], - }); - }, [fields]); - useEffect(() => { - if (onStateChange) { - onStateChange(state); - } - }, [state, onStateChange]); - const onDragEnd = useCallback( - (result: DropResult, provided: ResponderProvided) => { - if (!result.destination) { - return; - } - const destination = result.destination as DraggableLocation; - if (destination.droppableId === result.source.droppableId) { - if (destination.index === result.source.index) return; - setState((state) => { - let listKey = destination - .droppableId as keyof DraggableFieldState; - let newList = reorder( - state[listKey], - result.source.index, - destination.index - ); - return { - ...state, - [listKey]: newList, - }; - }); - } else { - setState((state) => { - let sourceKey = result.source - .droppableId as keyof DraggableFieldState; - let targetKey = destination - .droppableId as keyof DraggableFieldState; - let { originList, targetList } = move( - state[sourceKey], - result.source.index, - state[targetKey], - destination.index - ); - return { - ...state, - [sourceKey]: originList, - [targetKey]: targetList, - }; - }); - } - }, - [setState] - ); - return ( - - - {draggableStateKeys - .filter((d) => d.mode === 0) - .map((dkey) => ( - - - {(provided, snapshot) => ( - - {state[dkey.id].map((f, index) => ( - - {(provided, snapshot) => { - return ( - - {f.name}  - {f.type === 'M' && ( - { - setState((state) => { - const nextState = produce< - DraggableFieldState - >(state, (draft) => { - draft[dkey.id][index].aggName = e.target.value; - }); - return nextState; - }); - }} - > - { - aggregatorList.map(op => ) - } - - )} - - ); - }} - - ))} - - )} - - - ))} -
- - {draggableStateKeys - .filter((d) => d.mode === 1) - .map((dkey) => ( - - - {(provided, snapshot) => ( - - {state[dkey.id].map((f, index) => ( - - {(provided, snapshot) => { - return ( - - {f.name}  - {f.type === 'M' && ( - { - setState((state) => { - const nextState = produce< - DraggableFieldState - >(state, (draft) => { - draft[dkey.id][index].aggName = - e.target.value; - }); - return nextState; - }); - }} - > - {aggregatorList.map((op) => ( - - ))} - - )} - - ); - }} - - ))} - - )} - - - ))} - -
-
-
- ); -}; - -export default DraggableFields; diff --git a/packages/graphic-walker/src/Fields/posFields.tsx b/packages/graphic-walker/src/Fields/posFields.tsx new file mode 100644 index 00000000..259ef716 --- /dev/null +++ b/packages/graphic-walker/src/Fields/posFields.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { FieldListContainer, FieldsContainer, Pill } from "./components"; +import { observer } from 'mobx-react-lite'; +import { + DragDropContext, + Droppable, + Draggable, + DropResult, + ResponderProvided, + DraggableLocation, + } from "react-beautiful-dnd"; + +import { AGGREGATOR_LIST, DRAGGABLE_STATE_KEYS } from './fieldsContext'; +import { useGlobalStore } from '../store'; +import { useCallback } from 'react'; +const rowsAndCols = DRAGGABLE_STATE_KEYS.filter(f => f.id === 'columns' || f.id === 'rows'); +const PosFields: React.FC = props => { + const { vizStore } = useGlobalStore(); + const { draggableFieldState } = vizStore; + + return
+ { + rowsAndCols.map(dkey => + + {(provided, snapshot) => ( + + {draggableFieldState[dkey.id].map((f, index) => ( + + {(provided, snapshot) => { + return ( + + {f.name}  + {f.type === 'M' && ( + + )} + + ); + }} + + ))} + + )} + + ) + } +
+} + +export default observer(PosFields); \ No newline at end of file diff --git a/packages/graphic-walker/src/InsightBoard/index.tsx b/packages/graphic-walker/src/InsightBoard/index.tsx index 8648bb6c..d173bca2 100644 --- a/packages/graphic-walker/src/InsightBoard/index.tsx +++ b/packages/graphic-walker/src/InsightBoard/index.tsx @@ -1,203 +1,30 @@ -import React, { useEffect, useState, useMemo, useRef } from 'react'; -import { Record, Field, Filters, IMeasure } from '../interfaces'; -import { Insight, Utils, UnivariateSummary } from 'visual-insights'; -import { baseVis, IReasonType } from './std2vegaSpec'; -import embed from 'vega-embed'; -import { getExplaination, IVisSpace } from '../services'; -import { Spinner } from '@tableau/tableau-ui'; -import RadioGroupButtons from './radioGroupButtons'; -import { IExplaination, IMeasureWithStat } from '../insights'; -import { mergeMeasures } from './utils'; -import ReactJson from 'react-json-view'; - -const collection = Insight.IntentionWorkerCollection.init(); - -const ReasonTypeNames: { [key: string]: string} = { - 'selection_dim_distribution': '维度线索', - 'selection_mea_distribution': '度量线索', - 'children_major_factor': '子节点主因', - 'children_outlier': '子节点异常' -} -collection.enable(Insight.DefaultIWorker.cluster, false); -interface SubSpace { - dimensions: string[]; - measures: IMeasure[]; -} - -interface InsightBoardProps { - dataSource: Record[]; - fields: Field[]; - filters?: Filters; - viewDs: Field[]; - viewMs: Field[]; -} -const InsightBoard: React.FC = props => { - const { dataSource, fields, viewDs, viewMs, filters } = props; - const [recSpaces, setRecSpaces] = useState([]); - const [visSpaces, setVisSpaces] = useState([]); - const [visIndex, setVisIndex] = useState(0); - const [loading, setLoading] = useState(false); - const [valueExp, setValueExp] = useState([]); - const container = useRef(null); - - const dimsWithTypes = useMemo(() => { - const dimensions = fields - .filter((f) => f.type === 'D') - .map((f) => f.id) - .filter((f) => !Utils.isFieldUnique(dataSource, f)); - return UnivariateSummary.getAllFieldTypes(dataSource, dimensions); - }, [fields, dataSource]) - - const measWithTypes = useMemo(() => { - const measures = fields.filter((f) => f.type === 'M').map((f) => f.id); - return measures.map((m) => ({ - name: m, - type: 'quantitative', - })); - }, [fields]); - - useEffect(() => { - if (dimsWithTypes.length > 0 && measWithTypes.length > 0 && dataSource.length > 0) { - const measures = fields.filter((f) => f.type === 'M').map((f) => f.id); - const dimensions = dimsWithTypes.map(d => d.name); - const currentSpace: SubSpace = { - dimensions: viewDs.map((f) => f.id), - measures: viewMs.map((f) => ({ - key: f.id, - op: f.aggName as any - })), - }; - setLoading(true); - - getExplaination({ - dimensions, - measures, - dataSource, - currentSpace, - filters - }).then(({ visSpaces, explainations, valueExp }) => { - console.log({ visSpaces, explainations, valueExp }) - setRecSpaces(explainations); - setVisSpaces(visSpaces); - setValueExp(valueExp); - setLoading(false); - }) - } - }, [fields, viewDs, viewMs, measWithTypes, filters, dimsWithTypes, measWithTypes, dataSource]) - - const fieldsWithType = useMemo(() => { - return [...dimsWithTypes, ...measWithTypes]; - }, [dimsWithTypes, measWithTypes]) - - useEffect(() => { - const RecSpace = recSpaces[visIndex]; - const visSpec = visSpaces[visIndex]; - if (container.current && RecSpace && visSpec) { - const usePredicates: boolean = - RecSpace.type === 'selection_dim_distribution' || - RecSpace.type === 'selection_mea_distribution'; - const mergedMeasures = mergeMeasures(RecSpace.measures, RecSpace.extendMs); - const _vegaSpec = baseVis( - visSpec.schema, - visSpec.schema.geomType && visSpec.schema.geomType[0] === 'point' - ? dataSource - : visSpec.dataView, - // result.aggData, - [...RecSpace.dimensions, ...RecSpace.extendDs], - [...RecSpace.measures, ...RecSpace.extendMs].map(m => m.key), - usePredicates ? RecSpace.predicates : null, - mergedMeasures.map((m) => ({ - op: m.op, - field: m.key, - as: m.key, - })), - fieldsWithType as any, - RecSpace.type as IReasonType, - true, - true - ); - if (container.current) { - console.log(_vegaSpec) - embed(container.current, _vegaSpec); - } - } - }, [visIndex, recSpaces, visSpaces, fieldsWithType, dataSource]) - - const FilterDesc = useMemo(() => { - if (filters) { - const dimValues = Object.keys(filters) - .filter(k => filters[k].length > 0) - .map((k) => { - return `${k}=${filters[k]}`; - }); - return `选中对象${dimValues.join(', ')}的数据`; - } - return '' - }, [filters]) - - const valueDesc = useMemo(() => { - const meaStatus = valueExp.map( - (mea) => `${mea.key}(${mea.op})的取值${mea.score === 1 ? '大于' : '小于'}预期` - ); - return meaStatus.join(', '); - }, [valueExp]) - - return ( -
-

- {FilterDesc}, {valueDesc} -

- {loading && ( -
- -
- )} -
-
- ({ - value: s.type || '' + i, - label: `${s.type ? ReasonTypeNames[s.type] : '未识别'}: ${ - s.score.toFixed(2) - }`, - }))} - onChange={(v, i) => { - setVisIndex(i); - }} - /> -
-
-
- {recSpaces[visIndex] && ( -
- 维度是{recSpaces[visIndex].dimensions.join(', ')}。
- 度量是{recSpaces[visIndex].measures.map((m) => m.key).join(', ')}。
- 此时具有 - {recSpaces[visIndex].type - ? ReasonTypeNames[recSpaces[visIndex].type!] - : '未识别'}{' '} - ,评分为{recSpaces[visIndex].score}。 -
- {recSpaces[visIndex].description && - recSpaces[visIndex].description.intMeasures && - FilterDesc + - recSpaces[visIndex].description.intMeasures - .map( - (mea: any) => - `${mea.key}(${mea.op})}的取值${ - mea.score === 1 ? '大于' : '小于' - }预期` - ) - .join(', ')} -
- -
- )} -
-
-
- ); +import { toJS } from 'mobx'; +import { observer } from 'mobx-react-lite'; +import React, { useCallback } from 'react'; +import Modal from '../components/modal'; +import { useGlobalStore } from '../store'; +import InsightMainBoard from './mainBoard'; + +const InsightBoard: React.FC = props => { + const { commonStore, vizStore } = useGlobalStore(); + const { showInsightBoard, currentDataset, filters } = commonStore; + const { viewDimensions, viewMeasures, draggableFieldState } = vizStore; + const onCloseModal = useCallback(() => { + commonStore.setShowInsightBoard(false); + }, []) + return
+ { + showInsightBoard && + + + } +
} -export default InsightBoard; +export default observer(InsightBoard); \ No newline at end of file diff --git a/packages/graphic-walker/src/InsightBoard/mainBoard.tsx b/packages/graphic-walker/src/InsightBoard/mainBoard.tsx new file mode 100644 index 00000000..90626222 --- /dev/null +++ b/packages/graphic-walker/src/InsightBoard/mainBoard.tsx @@ -0,0 +1,198 @@ +import React, { useEffect, useState, useMemo, useRef } from 'react'; +import { Record, Field, Filters, IMeasure } from '../interfaces'; +import { Insight, Utils, UnivariateSummary } from 'visual-insights'; +import { baseVis, IReasonType } from './std2vegaSpec'; +import embed from 'vega-embed'; +import { getExplaination, IVisSpace } from '../services'; +import RadioGroupButtons from './radioGroupButtons'; +import { IExplaination, IMeasureWithStat } from '../insights'; +import { mergeMeasures } from './utils'; +import ReactJson from 'react-json-view'; + +const collection = Insight.IntentionWorkerCollection.init(); + +const ReasonTypeNames: { [key: string]: string} = { + 'selection_dim_distribution': '维度线索', + 'selection_mea_distribution': '度量线索', + 'children_major_factor': '子节点主因', + 'children_outlier': '子节点异常' +} +collection.enable(Insight.DefaultIWorker.cluster, false); +interface SubSpace { + dimensions: string[]; + measures: IMeasure[]; +} + +interface InsightMainBoardProps { + dataSource: Record[]; + fields: Field[]; + filters?: Filters; + viewDs: Field[]; + viewMs: Field[]; +} +const InsightMainBoard: React.FC = props => { + const { dataSource, fields, viewDs, viewMs, filters } = props; + const [recSpaces, setRecSpaces] = useState([]); + const [visSpaces, setVisSpaces] = useState([]); + const [visIndex, setVisIndex] = useState(0); + const [loading, setLoading] = useState(false); + const [valueExp, setValueExp] = useState([]); + const container = useRef(null); + + const dimsWithTypes = useMemo(() => { + const dimensions = fields + .filter((f) => f.type === 'D') + .map((f) => f.id) + .filter((f) => !Utils.isFieldUnique(dataSource, f)); + return UnivariateSummary.getAllFieldTypes(dataSource, dimensions); + }, [fields, dataSource]) + + const measWithTypes = useMemo(() => { + const measures = fields.filter((f) => f.type === 'M').map((f) => f.id); + return measures.map((m) => ({ + name: m, + type: 'quantitative', + })); + }, [fields]); + + useEffect(() => { + if (dimsWithTypes.length > 0 && measWithTypes.length > 0 && dataSource.length > 0) { + const measures = fields.filter((f) => f.type === 'M').map((f) => f.id); + const dimensions = dimsWithTypes.map(d => d.name); + const currentSpace: SubSpace = { + dimensions: viewDs.map((f) => f.id), + measures: viewMs.map((f) => ({ + key: f.id, + op: f.aggName as any + })), + }; + setLoading(true); + + getExplaination({ + dimensions, + measures, + dataSource, + currentSpace, + filters + }).then(({ visSpaces, explainations, valueExp }) => { + setRecSpaces(explainations); + setVisSpaces(visSpaces); + setValueExp(valueExp); + setLoading(false); + }) + } + }, [fields, viewDs, viewMs, measWithTypes, filters, dimsWithTypes, measWithTypes, dataSource]) + + const fieldsWithType = useMemo(() => { + return [...dimsWithTypes, ...measWithTypes]; + }, [dimsWithTypes, measWithTypes]) + + useEffect(() => { + const RecSpace = recSpaces[visIndex]; + const visSpec = visSpaces[visIndex]; + if (container.current && RecSpace && visSpec) { + const usePredicates: boolean = + RecSpace.type === 'selection_dim_distribution' || + RecSpace.type === 'selection_mea_distribution'; + const mergedMeasures = mergeMeasures(RecSpace.measures, RecSpace.extendMs); + const _vegaSpec = baseVis( + visSpec.schema, + visSpec.schema.geomType && visSpec.schema.geomType[0] === 'point' + ? dataSource + : visSpec.dataView, + // result.aggData, + [...RecSpace.dimensions, ...RecSpace.extendDs], + [...RecSpace.measures, ...RecSpace.extendMs].map(m => m.key), + usePredicates ? RecSpace.predicates : null, + mergedMeasures.map((m) => ({ + op: m.op, + field: m.key, + as: m.key, + })), + fieldsWithType as any, + RecSpace.type as IReasonType, + true, + true + ); + if (container.current) { + embed(container.current, _vegaSpec); + } + } + }, [visIndex, recSpaces, visSpaces, fieldsWithType, dataSource]) + + const FilterDesc = useMemo(() => { + if (filters) { + const dimValues = Object.keys(filters) + .filter(k => filters[k].length > 0) + .map((k) => { + return `${k}=${filters[k]}`; + }); + return `选中对象${dimValues.join(', ')}的数据`; + } + return '' + }, [filters]) + + const valueDesc = useMemo(() => { + const meaStatus = valueExp.map( + (mea) => `${mea.key}(${mea.op})的取值${mea.score === 1 ? '大于' : '小于'}预期` + ); + return meaStatus.join(', '); + }, [valueExp]) + + return ( +
+

+ {FilterDesc}, {valueDesc} +

+ {loading && ( +
+ )} +
+
+ ({ + value: s.type || '' + i, + label: `${s.type ? ReasonTypeNames[s.type] : '未识别'}: ${ + s.score.toFixed(2) + }`, + }))} + onChange={(v, i) => { + setVisIndex(i); + }} + /> +
+
+
+ {recSpaces[visIndex] && ( +
+ 维度是{recSpaces[visIndex].dimensions.join(', ')}。
+ 度量是{recSpaces[visIndex].measures.map((m) => m.key).join(', ')}。
+ 此时具有 + {recSpaces[visIndex].type + ? ReasonTypeNames[recSpaces[visIndex].type!] + : '未识别'}{' '} + ,评分为{recSpaces[visIndex].score}。 +
+ {recSpaces[visIndex].description && + recSpaces[visIndex].description.intMeasures && + FilterDesc + + recSpaces[visIndex].description.intMeasures + .map( + (mea: any) => + `${mea.key}(${mea.op})}的取值${ + mea.score === 1 ? '大于' : '小于' + }预期` + ) + .join(', ')} +
+ +
+ )} +
+
+
+ ); +} + +export default InsightMainBoard; diff --git a/packages/graphic-walker/src/InsightBoard/radioGroupButtons.tsx b/packages/graphic-walker/src/InsightBoard/radioGroupButtons.tsx index 76345754..49579542 100644 --- a/packages/graphic-walker/src/InsightBoard/radioGroupButtons.tsx +++ b/packages/graphic-walker/src/InsightBoard/radioGroupButtons.tsx @@ -2,8 +2,9 @@ import React from 'react'; import styled from 'styled-components'; const RGBContainer = styled.div` + font-size: 14px; .option { - padding: 1em; + padding: 0.8em; margin: 4px; border: 1px solid #f0f0f0; background-color: #f0f0f0; diff --git a/packages/graphic-walker/src/InsightBoard/selectionSpec.ts b/packages/graphic-walker/src/InsightBoard/selectionSpec.ts index 2693ecd6..14cf6142 100644 --- a/packages/graphic-walker/src/InsightBoard/selectionSpec.ts +++ b/packages/graphic-walker/src/InsightBoard/selectionSpec.ts @@ -1,4 +1,4 @@ -import { Specification } from 'visual-insights/build/esm/commonTypes'; +import { Specification } from 'visual-insights'; import { Record, SemanticType } from '../interfaces'; export const geomTypeMap: { [key: string]: any } = { interval: 'bar', diff --git a/packages/graphic-walker/src/InsightBoard/std2vegaSpec.ts b/packages/graphic-walker/src/InsightBoard/std2vegaSpec.ts index 93dbed79..9ae1cf41 100644 --- a/packages/graphic-walker/src/InsightBoard/std2vegaSpec.ts +++ b/packages/graphic-walker/src/InsightBoard/std2vegaSpec.ts @@ -1,6 +1,6 @@ -import { Specification } from 'visual-insights/build/esm/commonTypes'; +import { Specification } from 'visual-insights'; import { Record, SemanticType } from '../interfaces'; -import { deepcopy } from 'visual-insights/build/esm/utils'; +import { Utils } from 'visual-insights'; import { IPredicate } from '../utils'; export type IReasonType = 'selection_dim_distribution' | 'selection_mea_distribution' | 'children_major_factor' | 'children_outlier'; export const geomTypeMap: { [key: string]: any } = { @@ -129,7 +129,7 @@ export function baseVis( ...basicSpec, }; } - const basicSpecFilter = deepcopy(basicSpec); + const basicSpecFilter = Utils.deepcopy(basicSpec); basicSpec.mark.opacity = 0.9; basicSpec.mark.color = '#8c8c8c'; // basicSpecFilter.mark.color = '#f5222d'; diff --git a/packages/graphic-walker/src/components/container.tsx b/packages/graphic-walker/src/components/container.tsx index 1910359d..03b7454a 100644 --- a/packages/graphic-walker/src/components/container.tsx +++ b/packages/graphic-walker/src/components/container.tsx @@ -5,4 +5,11 @@ export const Container = styled.div` padding: 1em; margin: 1em; background-color: #fff; -`; \ No newline at end of file +`; + +export const NestContainer = styled.div` + border: 1px solid #d9d9d9; + padding: 0.4em; + margin: 0.2em; + background-color: #fff; +` \ No newline at end of file diff --git a/packages/graphic-walker/src/components/modal.tsx b/packages/graphic-walker/src/components/modal.tsx index ad592a5e..755693a2 100644 --- a/packages/graphic-walker/src/components/modal.tsx +++ b/packages/graphic-walker/src/components/modal.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styled from 'styled-components'; -import { IconButton } from '@fluentui/react'; +import { XCircleIcon } from '@heroicons/react/outline'; const Container = styled.div` width: 880px; max-height: 800px; @@ -8,7 +8,8 @@ const Container = styled.div` > div.header { background-color: #f0f0f0; display: flex; - padding: 8px; + padding: 12px; + font-size: 14px; align-items: center; } > div.container { @@ -19,7 +20,7 @@ const Container = styled.div` top: 50%; transform: translate(-50%, -50%); background-color: #fff; - box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.19); + /* box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.19); */ border-radius: 4px; z-index: 999; `; @@ -30,13 +31,11 @@ interface ModalProps { const Modal: React.FC = props => { const { onClose, title } = props; return ( - -
+ +
{title} -
diff --git a/packages/graphic-walker/src/config.ts b/packages/graphic-walker/src/config.ts index 82b38f72..7aca8dd1 100644 --- a/packages/graphic-walker/src/config.ts +++ b/packages/graphic-walker/src/config.ts @@ -15,4 +15,12 @@ export const GEMO_TYPES = [ value: 'tick', label: '标记', }, -]; \ No newline at end of file +]; + +export const COLORS = { + // tableau style + // dimension: 'rgb(73, 150, 178)', + // measure: 'rgb(0, 177, 128)', + dimension: 'rgb(86, 170, 208)', + measure: 'rgb(232, 149, 72)' +} \ No newline at end of file diff --git a/packages/graphic-walker/src/dataSource/index.tsx b/packages/graphic-walker/src/dataSource/index.tsx index 25815350..d252af80 100644 --- a/packages/graphic-walker/src/dataSource/index.tsx +++ b/packages/graphic-walker/src/dataSource/index.tsx @@ -1,145 +1,50 @@ -import React, { useRef, useState, useCallback } from 'react'; -import { Button, TextField } from '@tableau/tableau-ui'; -import { FileReader } from '@kanaries/web-data-loader'; -import { Record, IField } from '../interfaces'; -import { Insight } from 'visual-insights'; -import Table from './table'; -import styled from 'styled-components'; -import { useLocalState } from '../store'; +import { observer } from 'mobx-react-lite'; +import React, { useState } from 'react'; +import { Container } from '../components/container'; +import Modal from '../components/modal'; +import DataSourcePanel from './pannel'; +import { useGlobalStore } from '../store'; +import { CheckCircleIcon, RefreshIcon } from '@heroicons/react/outline'; -const Container = styled.div` - overflow-x: auto; - table { - box-sizing: content-box; - font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif; - border-collapse: collapse; - thead { - td { - text-align: left; - } - } - tbody { - td.number { - text-align: right; - } - td.text { - text-align: left; - } - } - } -`; -function transData(dataSource: Record[]): { - dataSource: Record[]; - fields: IField[] -} { - if (dataSource.length === 0) return { - dataSource: [], - fields: [] - }; - let ans: Record[] = []; - const keys = Object.keys(dataSource[0]); - const vie = new Insight.VIEngine(); - vie.setDataSource(dataSource) - .setFieldKeys(keys) - .buildfieldsSummary(); - const fields = vie.fields; - // console.log(fields) - for (let record of dataSource) { - const newRecord: Record = {}; - for (let field of fields) { - if (field.dataType === 'number' || field.dataType === 'integer') { - newRecord[field.key] = Number(record[field.key]) - } else { - newRecord[field.key] = record[field.key] - } - } - ans.push(newRecord); - } - return { - dataSource: ans, - fields: fields.map(f => ({ - key: f.key, - type: f.dataType, - analyticType: f.analyticType - })) - } +interface DSSegmentProps { + preWorkDone: boolean; } -interface DSPanelProps { - dbIndex: number; - onSubmit?: () => void -} -const DataSourcePanel: React.FC = props => { - const { dbIndex, onSubmit } = props; - const fileRef = useRef(null); - const [dataSource, setDataSource] = useState([]); - const [fields, setFields] = useState([]); - const [GS, updateGS] = useLocalState(); - const [dsName, setDSName] = useState('新数据集') - const onFieldsChange = useCallback((fields: IField[]) => { - setFields(fields); - }, []) - const onSubmitData = useCallback(() => { - updateGS(draft => { - draft.dataBase[dbIndex] = { - id: 'test' + dbIndex, - name: dsName, - fields, - dataSource - } - }) - if (onSubmit) { - onSubmit(); - } - }, [dbIndex, fields, dataSource, dsName]) - return ( - - { - const files = e.target.files; - if (files !== null) { - const file = files[0]; - FileReader.csvReader({ - file, - config: { type: 'reservoirSampling', size: Infinity }, - onLoading: () => {} - }).then((data) => { - // console.log(data) - const result = transData(data as Record[]); - console.log(result); - // TODO: need fix web-data-loader issue #2 - setDataSource(result.dataSource.slice(0, -1)); - setFields(result.fields); - }); - } - }} - /> -
- - -
-
- { - setDSName(e.target.value) - }} /> -
- - - ); +const DataSourceSegment: React.FC = props => { + const { preWorkDone } = props; + const { commonStore } = useGlobalStore(); + + const { currentDataset, datasets, showDSPanel } = commonStore; + + return + {!preWorkDone &&
} + + + + + {showDSPanel && ( + { commonStore.setShowDSPanel(false) }} + > + + + )} + { preWorkDone && } + { !preWorkDone && } +
} -export default DataSourcePanel; +export default observer(DataSourceSegment); \ No newline at end of file diff --git a/packages/graphic-walker/src/dataSource/pannel.tsx b/packages/graphic-walker/src/dataSource/pannel.tsx new file mode 100644 index 00000000..84a30185 --- /dev/null +++ b/packages/graphic-walker/src/dataSource/pannel.tsx @@ -0,0 +1,71 @@ +import React, { useRef, useState, useCallback } from 'react'; +import { FileReader } from '@kanaries/web-data-loader'; +import { Record } from '../interfaces'; +import Table from './table'; +import styled from 'styled-components'; +import { useGlobalStore } from '../store'; +import { observer } from 'mobx-react-lite'; + +const Container = styled.div` + overflow-x: auto; +`; + +interface DSPanelProps { +} +const DataSourcePanel: React.FC = props => { + const fileRef = useRef(null); + const { commonStore } = useGlobalStore(); + const { tmpDSName, tmpDataSource } = commonStore; + + const onSubmitData = useCallback(() => { + commonStore.commitTempDS(); + }, []) + return ( + + { + const files = e.target.files; + if (files !== null) { + const file = files[0]; + FileReader.csvReader({ + file, + config: { type: 'reservoirSampling', size: Infinity }, + onLoading: () => {} + }).then((data) => { + commonStore.updateTempDS(data as Record[]); + }); + } + }} + /> +
+ + +
+
+ + { + commonStore.updateTempName(e.target.value) + }} + className="text-xs p-1 border border-gray-300 outline-none focus:outline-none focus:border-blue-500" + /> +
+
+ + ); +} + +export default observer(DataSourcePanel); diff --git a/packages/graphic-walker/src/dataSource/table.tsx b/packages/graphic-walker/src/dataSource/table.tsx index 572ce5a4..ccba438e 100644 --- a/packages/graphic-walker/src/dataSource/table.tsx +++ b/packages/graphic-walker/src/dataSource/table.tsx @@ -1,14 +1,13 @@ import React from 'react'; -import { Record, IField } from '../interfaces'; +import { Record, IField, IMutField } from '../interfaces'; import styled from 'styled-components'; -import { DropdownSelect } from '@tableau/tableau-ui'; -import produce from 'immer'; +import { observer } from 'mobx-react-lite'; +import { useGlobalStore } from '../store'; +import { useCallback } from 'react'; +import { DocumentTextIcon, HashtagIcon } from '@heroicons/react/outline'; interface TableProps { - fields: IField[]; - dataSource: Record[]; size?: number; - onFieldsUpdate: (fields: IField[]) => void } const Container = styled.div` overflow-x: auto; @@ -21,8 +20,10 @@ const Container = styled.div` th { text-align: left; border: 1px solid #f5f5f5; - padding: 8px; + padding: 12px; + background-color: #f7f7f7; margin: 2px; + white-space: nowrap; } th.number { border-top: 3px solid #5cdbd3; @@ -34,7 +35,11 @@ const Container = styled.div` tbody { td { border: 1px solid #f5f5f5; - padding: 0px 8px; + padding: 4px 12px; + color: #434343; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } td.number { text-align: right; @@ -55,33 +60,47 @@ const TYPE_LIST = [ label: '度量' } ]; -function getCellType(field: IField): 'number' | 'text' { - return field.type === 'number' || field.type === 'integer' ? 'number' : 'text'; +function getCellType(field: IMutField): 'number' | 'text' { + return field.dataType === 'number' || field.dataType === 'integer' ? 'number' : 'text'; } -function getHeaderType(field: IField): 'number' | 'text' { +function getHeaderType(field: IMutField): 'number' | 'text' { return field.analyticType === 'dimension'? 'text' : 'number'; } +const DataTypeIcon: React.FC<{dataType: IMutField['dataType']}> = props => { + const { dataType } = props; + switch (dataType) { + case 'integer': + case 'number': + return + default: + return + } +} const Table: React.FC = props => { - const { fields, dataSource, size = 10, onFieldsUpdate } = props; + const { size = 10 } = props; + const { commonStore } = useGlobalStore(); + const { tmpDSRawFields, tmpDataSource } = commonStore; + const dataTypeIcon = useCallback(() => { + + }, []) return (
- {fields.map((field, fIndex) => ( + {tmpDSRawFields.map((field, fIndex) => ( @@ -89,9 +108,9 @@ const Table: React.FC = props => { - {dataSource.slice(0, size).map((record, index) => ( + {tmpDataSource.slice(0, size).map((record, index) => ( - {fields.map((field) => ( + {tmpDSRawFields.map((field) => (
- {field.key}({field.type}) + {field.key}
- { - const nextFields = produce(fields, draft => { - draft[fIndex].analyticType = e.target.value as any; - }) - onFieldsUpdate(nextFields); +
= props => { ); } -export default Table; +export default observer(Table); diff --git a/packages/graphic-walker/src/dataSource/utils.ts b/packages/graphic-walker/src/dataSource/utils.ts new file mode 100644 index 00000000..6fbcbb5b --- /dev/null +++ b/packages/graphic-walker/src/dataSource/utils.ts @@ -0,0 +1,48 @@ +import { Record, IField, IMutField } from '../interfaces'; +import { Insight } from 'visual-insights'; + +export function transData(dataSource: Record[]): { + dataSource: Record[]; + fields: IMutField[] +} { + if (dataSource.length === 0) return { + dataSource: [], + fields: [] + }; + let ans: Record[] = []; + const keys = Object.keys(dataSource[0]); + // TODO: 冗余设计,单变量统计被进行了多次重复计算。另外对于这种不完整的分析任务,不建议使用VIEngine。 + const vie = new Insight.VIEngine(); + vie.setData(dataSource) + .setFields(keys.map(k => ({ + key: k, + analyticType: '?', + dataType: '?', + semanticType: '?' + }))) + // TODO: 结合上面的TODO,讨论,VIEngine是否要提供不需要进行univarSelection就提供summary的接口。 + // 这里我们使用了一种非原API设计时期待的用法,即强制指定单变量选择时要全选字段。但我们无法阻止对变量的转换。 + vie.univarSelection('percent', 1); + const fields = vie.fields; + // console.log(fields) + for (let record of dataSource) { + const newRecord: Record = {}; + for (let field of fields) { + if (field.dataType === 'number' || field.dataType === 'integer') { + newRecord[field.key] = Number(record[field.key]) + } else { + newRecord[field.key] = record[field.key] + } + } + ans.push(newRecord); + } + return { + dataSource: ans, + fields: fields.map(f => ({ + key: f.key, + analyticType: f.analyticType, + dataType: f.dataType, + semanticType: f.semanticType + })) + } +} \ No newline at end of file diff --git a/packages/graphic-walker/src/index.tsx b/packages/graphic-walker/src/index.tsx index 2367453b..bd08bd63 100644 --- a/packages/graphic-walker/src/index.tsx +++ b/packages/graphic-walker/src/index.tsx @@ -1,9 +1,12 @@ import React from 'react'; import App, { EditorProps } from './App'; -import { GlobalContextWrapper } from './store/index'; +import { StoreWrapper } from './store/index'; +import { FieldsContextWrapper } from './Fields/fieldsContext'; export const GraphicWalker: React.FC = props => { - return - - + return + + + + } diff --git a/packages/graphic-walker/src/insights.ts b/packages/graphic-walker/src/insights.ts index 151ea297..47046182 100644 --- a/packages/graphic-walker/src/insights.ts +++ b/packages/graphic-walker/src/insights.ts @@ -1,4 +1,4 @@ -import { Insight } from 'visual-insights'; +import { IMutField, Insight } from 'visual-insights'; import { Record, IMeasure } from './interfaces'; import { checkMajorFactor, filterByPredicates, checkChildOutlier, IPredicate } from './utils'; import { normalizeWithParent, compareDistribution, normalizeByMeasures, getDistributionDifference } from './utils/normalization'; @@ -19,45 +19,35 @@ export interface IMeasureWithStat extends IMeasure { } export class DataExplainer { public dataSource: Record[]; - private dimensions: string[]; - private measures: string[]; private engine: Insight.VIEngine; private defaultAggs: StatFuncName[] = ['min', 'max', 'sum', 'count', 'mean']; constructor (dataSource: Record[] = []) { this.engine = new Insight.VIEngine(); this.dataSource = dataSource; - this.dimensions = []; - this.measures = []; let keys: string[] = []; if (dataSource.length > 0) { keys = Object.keys(dataSource[0]); } - this.engine.setDataSource(dataSource) - .setFieldKeys(keys) - .buildfieldsSummary(); + this.engine.setData(dataSource) + // .setFieldKeys(keys) + // .buildfieldsSummary(); // const newKeys = this.engine.fields.filter(f => f.domain.size < 40).map(f => f.key); // this.engine.setFieldKeys(keys); // const keys = Object.keys(dataSource[0]) } - public setDimensions (dimensions: string[]) { - this.dimensions = dimensions; - this.engine.setDimensions(dimensions); - return this; - } - public setMeasures (measures: string[]) { - this.measures = measures; - this.engine.setMeasures(measures); - return this; + public setFields(fields: IMutField[]) { + this.engine.setFields(fields); + this.engine.univarSelection(); } public preAnalysis() { - console.log('start') + console.log('[graphic-walker:preAnalysis]start') this.engine.buildGraph(); this.engine.dataGraph.DIMENSION_CORRELATION_THRESHOLD = 0.6; this.engine.dataGraph.MEASURE_CORRELATION_THRESHOLD = 0.8; - console.log('graph finish') + console.log('[graphic-walker:preAnalysis]graph finish') this.engine .clusterFields(); - console.log('cluster finish') + console.log('[graphic-walker:preAnalysis]cluster finish') this.engine.buildSubspaces({ MAX: 2, MIN: 1 @@ -67,9 +57,9 @@ export class DataExplainer { MIN: 1 } ); - console.log('subspaces finsh. start build-cube') + console.log('[graphic-walker:preAnalysis]subspaces finsh. start build-cube') this.engine.buildCube(); - console.log('cube finish') + console.log('[graphic-walker:preAnalysis]cube finish') return this; } public explain (predicates: IPredicate[], dimensions: string[], measures: IMeasure[], threshold: number = 0.3): IExplaination[] { diff --git a/packages/graphic-walker/src/interfaces.ts b/packages/graphic-walker/src/interfaces.ts index ac8ba926..884e1d61 100644 --- a/packages/graphic-walker/src/interfaces.ts +++ b/packages/graphic-walker/src/interfaces.ts @@ -1,6 +1,6 @@ import { StatFuncName } from "visual-insights/build/esm/statistics"; import { AggFC } from 'cube-core/built/types'; - +import { IMutField as VIMutField } from 'visual-insights'; export interface Record { [key: string]: any; } @@ -17,6 +17,11 @@ export interface IField { analyticType: 'dimension' | 'measure'; } +export type IMutField = VIMutField; + +/** + * @deprecated + */ export interface Field { /** * id: key in data record @@ -35,6 +40,24 @@ export interface Field { cmp?: (a: any, b: any) => number; } +export interface IViewField { + /** + * id: key in data record + */ + id: string; + /** + * display name for field + */ + name: string; + /** + * aggregator's name + */ + aggName?: string; + type: 'D' | 'M'; + [key: string]: any; + cmp?: (a: any, b: any) => number; +} + export interface Measure extends Field { aggregator?: AggFC; minWidth?: number; @@ -45,7 +68,7 @@ export interface Measure extends Field { export interface DataSet { id: string; name: string; - fields: IField[]; + rawFields: IMutField[]; dataSource: Record[]; } @@ -57,4 +80,24 @@ export interface IFieldNeighbor { export interface IMeasure { key: string; op: StatFuncName +} + +export interface IDataSet { + id: string; + name: string; + rawFields: IMutField[]; + dsId: string; +} +/** + * use as props to create a new dataset(IDataSet). + */ +export interface IDataSetInfo { + name: string; + rawFields: IMutField[]; + dataSource: Record[] +} + +export interface IDataSource { + id: string; + data: Record[] } \ No newline at end of file diff --git a/packages/graphic-walker/src/main.tsx b/packages/graphic-walker/src/main.tsx index df741c34..04758a0d 100644 --- a/packages/graphic-walker/src/main.tsx +++ b/packages/graphic-walker/src/main.tsx @@ -1,6 +1,5 @@ import React from 'react' import ReactDOM from 'react-dom' -import './index.css' import { GraphicWalker } from './index' ReactDOM.render( diff --git a/packages/graphic-walker/src/renderer/index.tsx b/packages/graphic-walker/src/renderer/index.tsx new file mode 100644 index 00000000..2b33445f --- /dev/null +++ b/packages/graphic-walker/src/renderer/index.tsx @@ -0,0 +1,39 @@ +import { runInAction, toJS } from 'mobx'; +import { observer } from 'mobx-react-lite'; +import React from 'react'; +import { useCallback } from 'react'; +import { useGlobalStore } from '../store'; +import ReactVega from '../vis/react-vega'; + +const ReactiveRenderer: React.FC = props => { + const { vizStore, commonStore } = useGlobalStore(); + const { draggableFieldState } = vizStore; + const { visualConfig, currentDataset } = commonStore; + + const rows = toJS(draggableFieldState.rows) + const columns = toJS(draggableFieldState.columns) + const color = toJS(draggableFieldState.color) + const opacity = toJS(draggableFieldState.opacity) + const size = toJS(draggableFieldState.size) + + const onGeomClick = useCallback((values: any, e: any) => { + runInAction(() => { + commonStore.showEmbededMenu([e.pageX, e.pageY]) + commonStore.setFilters(values); + }) + }, []) + + return +} + +export default observer(ReactiveRenderer); diff --git a/packages/graphic-walker/src/services.ts b/packages/graphic-walker/src/services.ts index 3e92710d..80255127 100644 --- a/packages/graphic-walker/src/services.ts +++ b/packages/graphic-walker/src/services.ts @@ -1,4 +1,4 @@ -import { Record, Filters, SemanticType, IMeasure } from './interfaces'; +import { Record, Filters, SemanticType, IMeasure, IMutField } from './interfaces'; // import { Insight } from 'visual-insights'; /* eslint import/no-webpack-loader-syntax:0 */ // @ts-ignore @@ -8,7 +8,7 @@ import { Record, Filters, SemanticType, IMeasure } from './interfaces'; // @ts-ignore // eslint-disable-next-line import ExplainerWorker from './workers/explainer.worker?worker&inline'; -import { View, Specification } from 'visual-insights/build/esm/commonTypes'; +import { View, Specification } from 'visual-insights'; import { IExplaination, IMeasureWithStat } from './insights'; interface WorkerState { @@ -79,8 +79,7 @@ export async function getExplaination(props: ExplainParams) { } interface PreAnalysisParams { - dimensions: string[]; - measures: string[]; + fields: IMutField[]; dataSource: Record[]; } export async function preAnalysis(props: PreAnalysisParams) { diff --git a/packages/graphic-walker/src/store/commonStore.ts b/packages/graphic-walker/src/store/commonStore.ts new file mode 100644 index 00000000..57a7919d --- /dev/null +++ b/packages/graphic-walker/src/store/commonStore.ts @@ -0,0 +1,163 @@ +import { DataSet, Filters, IDataSet, IDataSetInfo, IDataSource, IMutField, Record } from '../interfaces'; +import { makeAutoObservable, observable } from 'mobx'; +import { transData } from '../dataSource/utils'; +import { GEMO_TYPES } from '../config'; + +interface VisualConfig { + defaultAggregated: boolean; + geoms: string[]; + defaultStack: boolean; +} + +export class CommonStore { + public datasets: IDataSet[] = []; + public dataSources: IDataSource[] = []; + public dsIndex: number = 0; + public tmpDSName: string = ''; + public tmpDSRawFields: IMutField[] = []; + public tmpDataSource: Record[] = []; + public showDSPanel: boolean = false; + public showInsightBoard: boolean = false; + public vizEmbededMenu: { show: boolean; position: [number, number] } = { show: false, position: [0, 0] }; + + public filters: Filters = {}; + public visualConfig: VisualConfig ={ + defaultAggregated: true, + geoms: [GEMO_TYPES[0].value], + defaultStack: true + } + constructor () { + this.datasets = []; + this.dataSources = []; + makeAutoObservable(this, { + dataSources: observable.ref, + tmpDataSource: observable.ref, + filters: observable.ref + }); + } + public get currentDataset (): DataSet { + const datasetIndex = this.dsIndex; + if (this.datasets.length > 0) { + const dataSourceId = this.datasets[datasetIndex].dsId; + const dataSource = this.dataSources.find(d => d.id === dataSourceId); + return { + ...this.datasets[datasetIndex], + dataSource: dataSource ? dataSource.data : [] + } + } + return { + id: '__null_ds__', + name: 'Empty Dataset', + rawFields: [], + dataSource: [] + } + } + public setVisualConfig (configKey: keyof VisualConfig, value: any) { + this.visualConfig[configKey] = value; + } + public setShowDSPanel (show: boolean) { + this.showDSPanel = show; + } + public setShowInsightBoard (show: boolean) { + this.showInsightBoard = show; + } + public showEmbededMenu (position: [number, number]) { + this.vizEmbededMenu.show = true; + this.vizEmbededMenu.position = position; + } + public closeEmbededMenu () { + this.vizEmbededMenu.show = false; + } + public initTempDS () { + this.tmpDSName = 'New Dataset' + this.tmpDSRawFields = []; + this.tmpDataSource = []; + } + public updateTempFields (fields: IMutField[]) { + this.tmpDSRawFields = fields; + } + + public updateTempFieldAnalyticType (fieldKey: string, analyticType: IMutField['analyticType']) { + const field = this.tmpDSRawFields.find(f => f.key === fieldKey); + if (field) { + field.analyticType = analyticType; + } + } + + public updateTempName (name: string) { + this.tmpDSName = name; + } + + public updateTempDS (rawData: Record[]) { + const result = transData(rawData); + // TODO: need fix web-data-loader issue #2 + this.tmpDataSource = result.dataSource.slice(0, -1); + this.tmpDSRawFields = result.fields; + } + + public commitTempDS () { + const { tmpDSName, tmpDSRawFields, tmpDataSource } = this; + this.addAndUseDS({ + dataSource: tmpDataSource, + rawFields: tmpDSRawFields, + name: tmpDSName + }) + this.setShowDSPanel(false); + this.initTempDS(); + } + + public startDSBuildingTask () { + this.initTempDS(); + this.showDSPanel = true; + } + public addAndUseDS(dataset: IDataSetInfo) { + const datasetId = this.addDS(dataset); + this.dsIndex = this.datasets.length - 1; + return datasetId + } + public addDS(dataset: IDataSetInfo) { + const timestamp = new Date().getTime(); + const dataSetId = `dst-${timestamp}` + const dataSourceId = `dse-${timestamp}`; + this.dataSources.push({ + id: dataSourceId, + data: dataset.dataSource + }) + this.datasets.push({ + id: dataSetId, + name: dataset.name, + rawFields: dataset.rawFields, + dsId: dataSourceId + }) + return dataSetId; + } + public removeDS(datasetId: string) { + const datasetIndex = this.datasets.findIndex(d => d.id === datasetId); + if (datasetIndex > -1) { + const dataSourceId = this.datasets[datasetIndex].dsId; + const dataSourceIndex = this.dataSources.findIndex(d => d.id === dataSourceId); + this.dataSources.splice(dataSourceIndex, 1); + this.datasets.splice(datasetIndex, 1); + } + } + public useDS(datasetId: string) { + const datasetIndex = this.datasets.findIndex(d => d.id === datasetId); + if (datasetIndex > -1) { + this.dsIndex = datasetIndex; + } + } + public createPlaceholderDS() { + this.addDS({ + name: '新数据源', + dataSource: [], + rawFields: [] + }) + } + public setFilters (props: Filters) { + this.filters = props; + } + public destroy () { + this.dataSources = []; + this.datasets = []; + } +} \ No newline at end of file diff --git a/packages/graphic-walker/src/store/index.tsx b/packages/graphic-walker/src/store/index.tsx index 983e2aeb..4caf9756 100644 --- a/packages/graphic-walker/src/store/index.tsx +++ b/packages/graphic-walker/src/store/index.tsx @@ -1,38 +1,34 @@ -import React, { useContext, useState, useCallback } from 'react'; -import { DataSet } from '../interfaces'; -import produce, { setAutoFreeze } from 'immer'; -setAutoFreeze(false); -interface IGlobalState { - dataBase: DataSet[]; - currentDBIndex: number; -} +import React, { useContext, useEffect } from 'react'; +import { CommonStore } from './commonStore' +import { VizSpecStore } from './visualSpecStore' -export function getInitGState(): IGlobalState { - return { - dataBase: [ - // getStudentsData(), - // getTitanicData() - ], - currentDBIndex: 0, - }; +interface GlobalStore { + commonStore: CommonStore; + vizStore: VizSpecStore; } -type IUpdater = (draft: T) => void; -const initState = getInitGState(); -export const GlobalContext = React.createContext<[IGlobalState, (updater: IUpdater) => void]>(null!); -export function useLocalState() { - return useContext(GlobalContext); +const commonStore = new CommonStore(); +const vizStore = new VizSpecStore(commonStore); + +const initStore: GlobalStore = { + commonStore, + vizStore } -export const GlobalContextWrapper: React.FC = props => { - const [gs, setGS] = useState(initState); - const updateGlobalState = useCallback((updater: IUpdater) => { - const nextState = produce(gs, updater); - setGS(nextState); - }, [gs]) - return - { - props.children +const StoreContext = React.createContext(initStore); + +export const StoreWrapper: React.FC = props => { + useEffect(() => { + return () => { + initStore.vizStore.destroy(); + initStore.commonStore.destroy(); } - -} \ No newline at end of file + }, []) + return + { props.children } + +} + +export function useGlobalStore() { + return useContext(StoreContext); +} diff --git a/packages/graphic-walker/src/store/visualSpecStore.ts b/packages/graphic-walker/src/store/visualSpecStore.ts new file mode 100644 index 00000000..ed6237ae --- /dev/null +++ b/packages/graphic-walker/src/store/visualSpecStore.ts @@ -0,0 +1,102 @@ +import { IReactionDisposer, makeAutoObservable, reaction, toJS } from "mobx"; +import { IViewField } from "../interfaces"; +import { CommonStore } from "./commonStore"; + +export interface DraggableFieldState { + fields: IViewField[]; + rows: IViewField[]; + columns: IViewField[]; + color: IViewField[]; + opacity: IViewField[]; + size: IViewField[]; + } + +export class VizSpecStore { + // public fields: IViewField[] = []; + public draggableFieldState: DraggableFieldState; + private reactions: IReactionDisposer[] = [] + constructor (commonStore: CommonStore) { + this.draggableFieldState = { + fields: [], + rows: [], + columns: [], + color: [], + opacity: [], + size: [] + } + makeAutoObservable(this); + this.reactions.push(reaction(() => commonStore.currentDataset, (dataset) => { + this.initState(); + this.draggableFieldState.fields = dataset.rawFields.map((f) => ({ + id: f.key, + name: f.key, + type: f.analyticType === 'dimension' ? 'D' : 'M', + aggName: f.analyticType === 'measure' ? 'sum' : undefined, + })) + })) + } + public get viewDimensions (): IViewField[] { + const { draggableFieldState } = this; + const state = toJS(draggableFieldState); + const fields: IViewField[] = []; + (Object.keys(state) as (keyof DraggableFieldState)[]) + .filter(dkey => dkey !== 'fields') + .forEach(dkey => { + fields.push(...draggableFieldState[dkey].filter(f => f.type === 'D')) + }) + return fields; + } + public get viewMeasures (): IViewField[] { + const { draggableFieldState } = this; + const state = toJS(draggableFieldState); + const fields: IViewField[] = []; + (Object.keys(state) as (keyof DraggableFieldState)[]) + .filter(dkey => dkey !== 'fields') + .forEach(dkey => { + fields.push(...draggableFieldState[dkey].filter(f => f.type === 'M')) + }) + return fields; + } + public initState () { + this.draggableFieldState = { + fields: [], + rows: [], + columns: [], + color: [], + opacity: [], + size: [] + } + } + public reorderField(stateKey: keyof DraggableFieldState, sourceIndex: number, destinationIndex: number) { + if (stateKey === 'fields') return; + if (sourceIndex === destinationIndex) return; + const fields = this.draggableFieldState[stateKey]; + const [field] = fields.splice(sourceIndex, 1); + fields.splice(destinationIndex, 0, field); + } + public moveField(sourceKey: keyof DraggableFieldState, sourceIndex: number, destinationKey: keyof DraggableFieldState, destinationIndex: number) { + let movingField: IViewField; + if (sourceKey === 'fields') { + movingField = this.draggableFieldState[sourceKey][sourceIndex] + } else { + [movingField] = this.draggableFieldState[sourceKey].splice(sourceIndex, 1); + } + if (destinationKey === 'fields')return; + this.draggableFieldState[destinationKey].splice(destinationIndex, 1, movingField) + } + public removeField(sourceKey: keyof DraggableFieldState, sourceIndex: number) { + if (sourceKey === 'fields')return; + this.draggableFieldState[sourceKey].splice(sourceIndex, 1); + } + public setFieldAggregator (stateKey: keyof DraggableFieldState, index: number, aggName: string) { + const fields = this.draggableFieldState[stateKey] + if (fields[index]) { + fields[index].aggName = aggName; + } + } + public destroy () { + this.reactions.forEach(rec => { + rec(); + }) + } +} \ No newline at end of file diff --git a/packages/graphic-walker/src/visualSettings/index.tsx b/packages/graphic-walker/src/visualSettings/index.tsx new file mode 100644 index 00000000..96601404 --- /dev/null +++ b/packages/graphic-walker/src/visualSettings/index.tsx @@ -0,0 +1,42 @@ +import { observer } from 'mobx-react-lite'; +import React from 'react'; +import { Container } from '../components/container'; +import { LiteForm } from '../components/liteForm'; +import { GEMO_TYPES } from '../config'; +import { useGlobalStore } from '../store'; + +interface VisualSettinsProps { + +} +const VisualSettings: React.FC = props => { + const { commonStore } = useGlobalStore(); + const { visualConfig } = commonStore; + return + +
+ { + commonStore.setVisualConfig('defaultAggregated', e.target.checked); + }} /> + +
+
+ + +
+
+
+} + +export default observer(VisualSettings); \ No newline at end of file diff --git a/packages/graphic-walker/src/workers/explainer.worker.js b/packages/graphic-walker/src/workers/explainer.worker.js index 7eaedd60..888f555f 100644 --- a/packages/graphic-walker/src/workers/explainer.worker.js +++ b/packages/graphic-walker/src/workers/explainer.worker.js @@ -8,9 +8,10 @@ const state = { }; function preAnalysis (props) { - const { dimensions, measures, dataSource } = props; // as ReqData; + const { fields, dataSource } = props; // as ReqData; const de = new DataExplainer(dataSource); - de.setDimensions(dimensions).setMeasures(measures).preAnalysis(); + de.setFields(fields); + de.preAnalysis(); state.de = de; return true } diff --git a/packages/graphic-walker/tailwind.config.js b/packages/graphic-walker/tailwind.config.js new file mode 100644 index 00000000..430e63e0 --- /dev/null +++ b/packages/graphic-walker/tailwind.config.js @@ -0,0 +1,18 @@ +module.exports = { + purge: [ + "./src/**/*.tsx" + ], + darkMode: false, // or 'media' or 'class' + theme: { + minWidth: { + '96': '96px' + }, + extend: {}, + }, + variants: { + extend: { + 'backgroundColor': ['disabled'] + }, + }, + plugins: [], +} diff --git a/yarn.lock b/yarn.lock index c5655224..e357df54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1396,14 +1396,6 @@ "@uifabric/set-version" "^7.0.24" tslib "^1.10.0" -"@fluentui/date-time-utilities@^8.2.2": - version "8.2.2" - resolved "https://registry.nlark.com/@fluentui/date-time-utilities/download/@fluentui/date-time-utilities-8.2.2.tgz#535d5bb6ee7ccfa8cc774c790e31d3d5d4edbad6" - integrity sha1-U11btu58z6jMd0x5DjHT1dTtutY= - dependencies: - "@fluentui/set-version" "^8.1.4" - tslib "^2.1.0" - "@fluentui/dom-utilities@^1.1.2": version "1.1.2" resolved "https://registry.nlark.com/@fluentui/dom-utilities/download/@fluentui/dom-utilities-1.1.2.tgz#1a53e51e1ab1d40696ae7d355a970c68d496845f" @@ -1412,34 +1404,6 @@ "@uifabric/set-version" "^7.0.24" tslib "^1.10.0" -"@fluentui/dom-utilities@^2.1.4": - version "2.1.4" - resolved "https://registry.nlark.com/@fluentui/dom-utilities/download/@fluentui/dom-utilities-2.1.4.tgz?cache=0&sync_timestamp=1627978008693&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40fluentui%2Fdom-utilities%2Fdownload%2F%40fluentui%2Fdom-utilities-2.1.4.tgz#a8eeaf906cc19f547ae40c662d2776cb2540ea11" - integrity sha1-qO6vkGzBn1R65AxmLSd2yyVA6hE= - dependencies: - "@fluentui/set-version" "^8.1.4" - tslib "^2.1.0" - -"@fluentui/font-icons-mdl2@^8.1.9": - version "8.1.9" - resolved "https://registry.nlark.com/@fluentui/font-icons-mdl2/download/@fluentui/font-icons-mdl2-8.1.9.tgz#fa22050d3d8a22a4247ebff5513f617dd757d488" - integrity sha1-+iIFDT2KIqQkfr/1UT9hfddX1Ig= - dependencies: - "@fluentui/set-version" "^8.1.4" - "@fluentui/style-utilities" "^8.3.0" - tslib "^2.1.0" - -"@fluentui/foundation-legacy@^8.1.9": - version "8.1.9" - resolved "https://registry.nlark.com/@fluentui/foundation-legacy/download/@fluentui/foundation-legacy-8.1.9.tgz#2e31f4db71f3f0f799b78a2740978cee2fe27559" - integrity sha1-LjH023Hz8PeZt4onQJeM7i/idVk= - dependencies: - "@fluentui/merge-styles" "^8.1.4" - "@fluentui/set-version" "^8.1.4" - "@fluentui/style-utilities" "^8.3.0" - "@fluentui/utilities" "^8.3.0" - tslib "^2.1.0" - "@fluentui/keyboard-key@^0.2.12": version "0.2.17" resolved "https://registry.nlark.com/@fluentui/keyboard-key/download/@fluentui/keyboard-key-0.2.17.tgz#61c037c3a596986926ad8812b58e9e5cebf9f972" @@ -1447,21 +1411,6 @@ dependencies: tslib "^1.10.0" -"@fluentui/keyboard-key@^0.3.4": - version "0.3.4" - resolved "https://registry.nlark.com/@fluentui/keyboard-key/download/@fluentui/keyboard-key-0.3.4.tgz#27c95ea9d43d91cc9c64c318feb10986250584cd" - integrity sha1-J8leqdQ9kcycZMMY/rEJhiUFhM0= - dependencies: - tslib "^2.1.0" - -"@fluentui/merge-styles@^8.1.4": - version "8.1.4" - resolved "https://registry.nlark.com/@fluentui/merge-styles/download/@fluentui/merge-styles-8.1.4.tgz#d08035eee47945f48d991ed2555e432d49e892b5" - integrity sha1-0IA17uR5RfSNmR7SVV5DLUnokrU= - dependencies: - "@fluentui/set-version" "^8.1.4" - tslib "^2.1.0" - "@fluentui/react-focus@^7.17.6": version "7.17.6" resolved "https://registry.nlark.com/@fluentui/react-focus/download/@fluentui/react-focus-7.17.6.tgz#aa23413c56d27615fdc8363bf8b8c70d5817c929" @@ -1474,28 +1423,6 @@ "@uifabric/utilities" "^7.33.5" tslib "^1.10.0" -"@fluentui/react-focus@^8.1.11": - version "8.1.11" - resolved "https://registry.nlark.com/@fluentui/react-focus/download/@fluentui/react-focus-8.1.11.tgz#ced96a040858e36e4acbd493054c3a6f997dccc0" - integrity sha1-ztlqBAhY425Ky9STBUw6b5l9zMA= - dependencies: - "@fluentui/keyboard-key" "^0.3.4" - "@fluentui/merge-styles" "^8.1.4" - "@fluentui/set-version" "^8.1.4" - "@fluentui/style-utilities" "^8.3.0" - "@fluentui/utilities" "^8.3.0" - tslib "^2.1.0" - -"@fluentui/react-hooks@^8.2.7": - version "8.2.7" - resolved "https://registry.nlark.com/@fluentui/react-hooks/download/@fluentui/react-hooks-8.2.7.tgz#7521dd16c41b8acf12a7e67142d5bd13da2dbeed" - integrity sha1-dSHdFsQbis8Sp+ZxQtW9E9otvu0= - dependencies: - "@fluentui/react-window-provider" "^2.1.4" - "@fluentui/set-version" "^8.1.4" - "@fluentui/utilities" "^8.3.0" - tslib "^2.1.0" - "@fluentui/react-window-provider@^1.0.2": version "1.0.2" resolved "https://registry.nlark.com/@fluentui/react-window-provider/download/@fluentui/react-window-provider-1.0.2.tgz#634f1f2e77fca9b3e8dbff9599d0c86d6c77dd73" @@ -1504,52 +1431,6 @@ "@uifabric/set-version" "^7.0.24" tslib "^1.10.0" -"@fluentui/react-window-provider@^2.1.4": - version "2.1.4" - resolved "https://registry.nlark.com/@fluentui/react-window-provider/download/@fluentui/react-window-provider-2.1.4.tgz?cache=0&sync_timestamp=1627978008240&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40fluentui%2Freact-window-provider%2Fdownload%2F%40fluentui%2Freact-window-provider-2.1.4.tgz#2e8368fd85f9e10062c726b060b146ffc1f916b3" - integrity sha1-LoNo/YX54QBixyawYLFG/8H5FrM= - dependencies: - "@fluentui/set-version" "^8.1.4" - tslib "^2.1.0" - -"@fluentui/react@^8.29.0": - version "8.29.0" - resolved "https://registry.nlark.com/@fluentui/react/download/@fluentui/react-8.29.0.tgz#e1e233315a541ce36edf970d5938b8ed448011bb" - integrity sha1-4eIzMVpUHONu35cNWTi47USAEbs= - dependencies: - "@fluentui/date-time-utilities" "^8.2.2" - "@fluentui/font-icons-mdl2" "^8.1.9" - "@fluentui/foundation-legacy" "^8.1.9" - "@fluentui/merge-styles" "^8.1.4" - "@fluentui/react-focus" "^8.1.11" - "@fluentui/react-hooks" "^8.2.7" - "@fluentui/react-window-provider" "^2.1.4" - "@fluentui/set-version" "^8.1.4" - "@fluentui/style-utilities" "^8.3.0" - "@fluentui/theme" "^2.2.2" - "@fluentui/utilities" "^8.3.0" - "@microsoft/load-themed-styles" "^1.10.26" - tslib "^2.1.0" - -"@fluentui/set-version@^8.1.4": - version "8.1.4" - resolved "https://registry.nlark.com/@fluentui/set-version/download/@fluentui/set-version-8.1.4.tgz#89fa88223f421981427dfd5372d46210045354e8" - integrity sha1-ifqIIj9CGYFCff1TctRiEARTVOg= - dependencies: - tslib "^2.1.0" - -"@fluentui/style-utilities@^8.3.0": - version "8.3.0" - resolved "https://registry.nlark.com/@fluentui/style-utilities/download/@fluentui/style-utilities-8.3.0.tgz#dcc76b310da0e4366a249c7e9c5ecedcfd212f33" - integrity sha1-3MdrMQ2g5DZqJJx+nF7O3P0hLzM= - dependencies: - "@fluentui/merge-styles" "^8.1.4" - "@fluentui/set-version" "^8.1.4" - "@fluentui/theme" "^2.2.2" - "@fluentui/utilities" "^8.3.0" - "@microsoft/load-themed-styles" "^1.10.26" - tslib "^2.1.0" - "@fluentui/theme@^1.7.4": version "1.7.4" resolved "https://registry.nlark.com/@fluentui/theme/download/@fluentui/theme-1.7.4.tgz#8582bab5a7445585c631d05d44b5ebb56f18b6ba" @@ -1560,26 +1441,6 @@ "@uifabric/utilities" "^7.33.5" tslib "^1.10.0" -"@fluentui/theme@^2.2.2": - version "2.2.2" - resolved "https://registry.nlark.com/@fluentui/theme/download/@fluentui/theme-2.2.2.tgz#5a381d9904424f161a32383835d4beaf6e237b98" - integrity sha1-WjgdmQRCTxYaMjg4NdS+r24je5g= - dependencies: - "@fluentui/merge-styles" "^8.1.4" - "@fluentui/set-version" "^8.1.4" - "@fluentui/utilities" "^8.3.0" - tslib "^2.1.0" - -"@fluentui/utilities@^8.3.0": - version "8.3.0" - resolved "https://registry.nlark.com/@fluentui/utilities/download/@fluentui/utilities-8.3.0.tgz#cee8088424b5632fd433b7caae863266f1b77ec9" - integrity sha1-zugIhCS1Yy/UM7fKroYyZvG3fsk= - dependencies: - "@fluentui/dom-utilities" "^2.1.4" - "@fluentui/merge-styles" "^8.1.4" - "@fluentui/set-version" "^8.1.4" - tslib "^2.1.0" - "@formatjs/intl-unified-numberformat@^3.2.0": version "3.3.7" resolved "https://registry.npm.taobao.org/@formatjs/intl-unified-numberformat/download/@formatjs/intl-unified-numberformat-3.3.7.tgz#9995a24568908188e716d81a1de5b702b2ee00e2" @@ -1624,6 +1485,11 @@ dependencies: "@hapi/hoek" "^8.3.0" +"@heroicons/react@^1.0.4": + version "1.0.4" + resolved "https://registry.nlark.com/@heroicons/react/download/@heroicons/react-1.0.4.tgz#11847eb2ea5510419d7ada9ff150a33af0ad0863" + integrity sha1-EYR+supVEEGdetqf8VCjOvCtCGM= + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.nlark.com/@istanbuljs/load-nyc-config/download/@istanbuljs/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -2039,7 +1905,7 @@ "@svgr/plugin-svgo" "^5.4.0" loader-utils "^2.0.0" -"@tableau/tableau-ui@^3.0.0", "@tableau/tableau-ui@^3.2.0": +"@tableau/tableau-ui@^3.0.0": version "3.2.0" resolved "https://registry.nlark.com/@tableau/tableau-ui/download/@tableau/tableau-ui-3.2.0.tgz#25277a07111e281042d70cd610e52ba1104aaf25" integrity sha1-JSd6BxEeKBBC1wzWEOUroRBKryU= @@ -2826,7 +2692,16 @@ acorn-jsx@^5.3.1: resolved "https://registry.nlark.com/acorn-jsx/download/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" integrity sha1-/IZh4Rt6wVOcR9v+oucrOvNNJns= -acorn-walk@^7.1.1: +acorn-node@^1.6.1: + version "1.8.2" + resolved "https://registry.npm.taobao.org/acorn-node/download/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha1-EUyV1kU55T3t4j3oudlt98euKvg= + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0, acorn-walk@^7.1.1: version "7.2.0" resolved "https://registry.nlark.com/acorn-walk/download/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w= @@ -2836,7 +2711,7 @@ acorn@^6.4.1: resolved "https://registry.nlark.com/acorn/download/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha1-NYZv1xBSjpLeEM8GAWSY5H454eY= -acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0: +acorn@^7.0.0, acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0: version "7.4.1" resolved "https://registry.nlark.com/acorn/download/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo= @@ -3003,6 +2878,11 @@ aproba@^1.1.1: resolved "https://registry.nlark.com/aproba/download/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha1-aALmJk79GMeQobDVF/DyYnvyyUo= +arg@^5.0.1: + version "5.0.1" + resolved "https://registry.nlark.com/arg/download/arg-5.0.1.tgz?cache=0&sync_timestamp=1629166537485&other_urls=https%3A%2F%2Fregistry.nlark.com%2Farg%2Fdownload%2Farg-5.0.1.tgz#eb0c9a8f77786cad2af8ff2b862899842d7b6adb" + integrity sha1-6wyaj3d4bK0q+P8rhiiZhC17ats= + argparse@^1.0.7: version "1.0.10" resolved "https://registry.nlark.com/argparse/download/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -3202,6 +3082,18 @@ atob@^2.1.2: resolved "https://registry.nlark.com/atob/download/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k= +autoprefixer@^10.3.5: + version "10.3.5" + resolved "https://registry.nlark.com/autoprefixer/download/autoprefixer-10.3.5.tgz?cache=0&sync_timestamp=1632290934335&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fautoprefixer%2Fdownload%2Fautoprefixer-10.3.5.tgz#762e6c13e30c5a0e650bf81d9ffd5713f1c8f344" + integrity sha1-di5sE+MMWg5lC/gdn/1XE/HI80Q= + dependencies: + browserslist "^4.17.1" + caniuse-lite "^1.0.30001259" + fraction.js "^4.1.1" + nanocolors "^0.1.5" + normalize-range "^0.1.2" + postcss-value-parser "^4.1.0" + autoprefixer@^9.6.1: version "9.8.6" resolved "https://registry.nlark.com/autoprefixer/download/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" @@ -3696,6 +3588,17 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4 escalade "^3.1.1" node-releases "^1.1.71" +browserslist@^4.17.1: + version "4.17.1" + resolved "https://registry.nlark.com/browserslist/download/browserslist-4.17.1.tgz?cache=0&sync_timestamp=1632288361873&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbrowserslist%2Fdownload%2Fbrowserslist-4.17.1.tgz#a98d104f54af441290b7d592626dd541fa642eb9" + integrity sha1-qY0QT1SvRBKQt9WSYm3VQfpkLrk= + dependencies: + caniuse-lite "^1.0.30001259" + electron-to-chromium "^1.3.846" + escalade "^3.1.1" + nanocolors "^0.1.5" + node-releases "^1.1.76" + bser@2.1.1: version "2.1.1" resolved "https://registry.npm.taobao.org/bser/download/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -3742,7 +3645,7 @@ bytes@3.0.0: resolved "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= -bytes@3.1.0: +bytes@3.1.0, bytes@^3.0.0: version "3.1.0" resolved "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY= @@ -3846,6 +3749,11 @@ camel-case@^4.1.1: pascal-case "^3.1.2" tslib "^2.0.3" +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.npm.taobao.org/camelcase-css/download/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha1-7pePaUeRTMMMa0R0G27R338EP9U= + camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -3876,6 +3784,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, can resolved "https://registry.nlark.com/caniuse-lite/download/caniuse-lite-1.0.30001241.tgz#cd3fae47eb3d7691692b406568d7a3e5b23c7598" integrity sha1-zT+uR+s9dpFpK0BlaNej5bI8dZg= +caniuse-lite@^1.0.30001259: + version "1.0.30001259" + resolved "https://registry.nlark.com/caniuse-lite/download/caniuse-lite-1.0.30001259.tgz?cache=0&sync_timestamp=1632203439345&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcaniuse-lite%2Fdownload%2Fcaniuse-lite-1.0.30001259.tgz#ae21691d3da9c4be6144403ac40f71d9f6efd790" + integrity sha1-riFpHT2pxL5hREA6xA9x2fbv15A= + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.nlark.com/capture-exit/download/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -3918,6 +3831,14 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.nlark.com/chalk/download/chalk-4.1.2.tgz?cache=0&sync_timestamp=1627646655305&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha1-qsTit3NKdAhnrrFr8CqtVWoeegE= + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.nlark.com/char-regex/download/char-regex-1.0.2.tgz?cache=0&sync_timestamp=1622809103243&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchar-regex%2Fdownload%2Fchar-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -3962,7 +3883,7 @@ chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.4.1: +chokidar@^3.4.1, chokidar@^3.5.2: version "3.5.2" resolved "https://registry.nlark.com/chokidar/download/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" integrity sha1-26OXb8rbAW9m/TZQIdkWANAcHnU= @@ -4158,6 +4079,14 @@ color-string@^1.5.4: color-name "^1.0.0" simple-swizzle "^0.2.2" +color-string@^1.6.0: + version "1.6.0" + resolved "https://registry.nlark.com/color-string/download/color-string-1.6.0.tgz?cache=0&sync_timestamp=1626503533872&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcolor-string%2Fdownload%2Fcolor-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312" + integrity sha1-w5FfYf4mdnLLfh4GTJ1pIhn2wxI= + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color@^3.0.0: version "3.1.3" resolved "https://registry.npm.taobao.org/color/download/color-3.1.3.tgz?cache=0&sync_timestamp=1602228725017&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolor%2Fdownload%2Fcolor-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" @@ -4166,6 +4095,14 @@ color@^3.0.0: color-convert "^1.9.1" color-string "^1.5.4" +color@^4.0.1: + version "4.0.1" + resolved "https://registry.nlark.com/color/download/color-4.0.1.tgz?cache=0&sync_timestamp=1628104040071&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcolor%2Fdownload%2Fcolor-4.0.1.tgz#21df44cd10245a91b1ccf5ba031609b0e10e7d67" + integrity sha1-Id9EzRAkWpGxzPW6AxYJsOEOfWc= + dependencies: + color-convert "^2.0.1" + color-string "^1.6.0" + colorette@^1.2.1, colorette@^1.2.2: version "1.2.2" resolved "https://registry.nlark.com/colorette/download/colorette-1.2.2.tgz?cache=0&sync_timestamp=1618846981554&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcolorette%2Fdownload%2Fcolorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" @@ -4188,6 +4125,11 @@ commander@^4.1.1: resolved "https://registry.nlark.com/commander/download/commander-4.1.1.tgz?cache=0&sync_timestamp=1624609539421&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcommander%2Fdownload%2Fcommander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha1-n9YCvZNilOnp70aj9NaWQESxgGg= +commander@^6.0.0: + version "6.2.1" + resolved "https://registry.nlark.com/commander/download/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha1-B5LraC37wyWZm7K4T93duhEKxzw= + common-tags@^1.8.0: version "1.8.0" resolved "https://registry.npm.taobao.org/common-tags/download/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" @@ -4408,6 +4350,17 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.nlark.com/cosmiconfig/download/cosmiconfig-7.0.1.tgz?cache=0&sync_timestamp=1629586119976&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcosmiconfig%2Fdownload%2Fcosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha1-cU11ZSLKzoZ4Z8y0R0xdAbuuXW0= + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + create-ecdh@^4.0.0: version "4.0.4" resolved "https://registry.npm.taobao.org/create-ecdh/download/create-ecdh-4.0.4.tgz?cache=0&sync_timestamp=1596557450797&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcreate-ecdh%2Fdownload%2Fcreate-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" @@ -4611,6 +4564,11 @@ css-tree@^1.1.2: mdn-data "2.0.14" source-map "^0.6.1" +css-unit-converter@^1.1.1: + version "1.1.2" + resolved "https://registry.nlark.com/css-unit-converter/download/css-unit-converter-1.1.2.tgz#4c77f5a1954e6dbff60695ecb214e3270436ab21" + integrity sha1-THf1oZVObb/2BpXsshTjJwQ2qyE= + css-what@^3.2.1: version "3.4.2" resolved "https://registry.nlark.com/css-what/download/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" @@ -5071,6 +5029,11 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/defined/download/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + del@^4.1.1: version "4.1.1" resolved "https://registry.npm.taobao.org/del/download/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" @@ -5130,6 +5093,20 @@ detect-port-alt@1.1.6: address "^1.0.1" debug "^2.6.0" +detective@^5.2.0: + version "5.2.0" + resolved "https://registry.npm.taobao.org/detective/download/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" + integrity sha1-/rKnfoW5BOzepFmtiXzJCpm9Kns= + dependencies: + acorn-node "^1.6.1" + defined "^1.0.0" + minimist "^1.1.1" + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.nlark.com/didyoumean/download/didyoumean-1.2.2.tgz?cache=0&sync_timestamp=1624543452248&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdidyoumean%2Fdownload%2Fdidyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha1-mJNG/+noObRVXs9WZu3qDT6K0Dc= + diff-sequences@^26.6.2: version "26.6.2" resolved "https://registry.nlark.com/diff-sequences/download/diff-sequences-26.6.2.tgz?cache=0&sync_timestamp=1624900057366&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdiff-sequences%2Fdownload%2Fdiff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" @@ -5156,6 +5133,11 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/dlv/download/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha1-XBmKihFFNZbnUUlNSYdLx3MvLnk= + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.npm.taobao.org/dns-equal/download/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -5335,6 +5317,11 @@ electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.723: resolved "https://registry.nlark.com/electron-to-chromium/download/electron-to-chromium-1.3.762.tgz#3fa4e3bcbda539b50e3aa23041627063a5cffe61" integrity sha1-P6TjvL2lObUOOqIwQWJwY6XP/mE= +electron-to-chromium@^1.3.846: + version "1.3.848" + resolved "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.3.848.tgz?cache=0&sync_timestamp=1632362659953&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Felectron-to-chromium%2Fdownload%2Felectron-to-chromium-1.3.848.tgz#94cc196e496f33c0d71cd98561448f10018584cc" + integrity sha1-lMwZbklvM8DXHNmFYUSPEAGFhMw= + elliptic@^6.5.3: version "6.5.4" resolved "https://registry.nlark.com/elliptic/download/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" @@ -5993,6 +5980,17 @@ fast-glob@^3.1.1: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.2.7: + version "3.2.7" + resolved "https://registry.nlark.com/fast-glob/download/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha1-/Wy3otfpqnp4RhEehaGW1rL3ZqE= + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-patch@^3.0.0-1: version "3.0.0-1" resolved "https://registry.npm.taobao.org/fast-json-patch/download/fast-json-patch-3.0.0-1.tgz#4c68f2e7acfbab6d29d1719c44be51899c93dabb" @@ -6267,6 +6265,11 @@ forwarded@0.2.0: resolved "https://registry.nlark.com/forwarded/download/forwarded-0.2.0.tgz?cache=0&sync_timestamp=1622503508967&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fforwarded%2Fdownload%2Fforwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha1-ImmTZCiq1MFcfr6XeahL8LKoGBE= +fraction.js@^4.1.1: + version "4.1.1" + resolved "https://registry.nlark.com/fraction.js/download/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff" + integrity sha1-rE5SBHPa5nAS1hiquR7aCby0AP8= + fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.nlark.com/fragment-cache/download/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -6292,6 +6295,15 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.nlark.com/fs-extra/download/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha1-n/YbZV3eU/s0qC34S7IUzoAuF8E= + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^7.0.0: version "7.0.1" resolved "https://registry.nlark.com/fs-extra/download/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -6450,6 +6462,13 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.1" + resolved "https://registry.nlark.com/glob-parent/download/glob-parent-6.0.1.tgz?cache=0&sync_timestamp=1626760165717&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-6.0.1.tgz#42054f685eb6a44e7a7d189a96efa40a54971aa7" + integrity sha1-QgVPaF62pE56fRialu+kClSXGqc= + dependencies: + is-glob "^4.0.1" + glob@7.1.3: version "7.1.3" resolved "https://registry.nlark.com/glob/download/glob-7.1.3.tgz?cache=0&sync_timestamp=1620337382269&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob%2Fdownload%2Fglob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -6462,6 +6481,18 @@ glob@7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.0.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/glob/download/glob-7.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fglob%2Fdownload%2Fglob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha1-0VU1r3cy4C6Uj0xBYovZECk/YCM= + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.7" resolved "https://registry.nlark.com/glob/download/glob-7.1.7.tgz?cache=0&sync_timestamp=1620337382269&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob%2Fdownload%2Fglob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" @@ -6749,6 +6780,11 @@ html-minifier-terser@^5.0.1: relateurl "^0.2.7" terser "^4.6.3" +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.nlark.com/html-tags/download/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha1-e15vfmZen7QfMAB+2eDUHpf7IUA= + html-to-react@^1.3.4: version "1.4.5" resolved "https://registry.npm.taobao.org/html-to-react/download/html-to-react-1.4.5.tgz#59091c11021d1ef315ef738460abb6a4a41fe1ce" @@ -6966,6 +7002,13 @@ import-cwd@^2.0.0: dependencies: import-from "^2.1.0" +import-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/import-cwd/download/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92" + integrity sha1-IIRVR3GAFRJuqbNna3WS+4vUz5I= + dependencies: + import-from "^3.0.0" + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz?cache=0&sync_timestamp=1608469579940&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -6989,6 +7032,13 @@ import-from@^2.1.0: dependencies: resolve-from "^3.0.0" +import-from@^3.0.0: + version "3.0.0" + resolved "https://registry.nlark.com/import-from/download/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" + integrity sha1-BVz+w4zVon2AV8pRN219O/CJGWY= + dependencies: + resolve-from "^5.0.0" + import-local@^2.0.0: version "2.0.0" resolved "https://registry.nlark.com/import-local/download/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" @@ -7229,7 +7279,7 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-color-stop@^1.0.0: +is-color-stop@^1.0.0, is-color-stop@^1.1.0: version "1.1.0" resolved "https://registry.nlark.com/is-color-stop/download/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= @@ -8279,6 +8329,11 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lilconfig@^2.0.3: + version "2.0.3" + resolved "https://registry.nlark.com/lilconfig/download/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd" + integrity sha1-aPMAXpIdr70qKvtIN5mGqm0lef0= + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.nlark.com/lines-and-columns/download/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -8404,6 +8459,11 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" +lodash.topath@^4.5.2: + version "4.5.2" + resolved "https://registry.npm.taobao.org/lodash.topath/download/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" + integrity sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak= + lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.nlark.com/lodash.truncate/download/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -8805,6 +8865,11 @@ mobx-react-lite@^3.2.0: resolved "https://registry.npm.taobao.org/mobx-react-lite/download/mobx-react-lite-3.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmobx-react-lite%2Fdownload%2Fmobx-react-lite-3.2.0.tgz#331d7365a6b053378dfe9c087315b4e41c5df69f" integrity sha1-Mx1zZaawUzeN/pwIcxW05Bxd9p8= +mobx-react-lite@^3.2.1: + version "3.2.1" + resolved "https://registry.nlark.com/mobx-react-lite/download/mobx-react-lite-3.2.1.tgz#c549a3722f1eae51a78b12f839311614d5689c58" + integrity sha1-xUmjci8erlGnixL4OTEWFNVonFg= + mobx-utils@^6.0.4: version "6.0.4" resolved "https://registry.npm.taobao.org/mobx-utils/download/mobx-utils-6.0.4.tgz#5283a466ece8de0ac36ae3cfa1b1c032ec302b37" @@ -8815,6 +8880,11 @@ mobx@^6.3.2: resolved "https://registry.nlark.com/mobx/download/mobx-6.3.2.tgz#125590961f702a572c139ab69392bea416d2e51b" integrity sha1-ElWQlh9wKlcsE5q2k5K+pBbS5Rs= +mobx@^6.3.3: + version "6.3.3" + resolved "https://registry.nlark.com/mobx/download/mobx-6.3.3.tgz#a3006c56243b1c7ea4ee671a66f963b9f43cf1af" + integrity sha1-owBsViQ7HH6k7mcaZvljufQ88a8= + mocha@^6.2.0: version "6.2.3" resolved "https://registry.nlark.com/mocha/download/mocha-6.2.3.tgz#e648432181d8b99393410212664450a4c1e31912" @@ -8844,6 +8914,11 @@ mocha@^6.2.0: yargs-parser "13.1.2" yargs-unparser "1.6.0" +modern-normalize@^1.1.0: + version "1.1.0" + resolved "https://registry.nlark.com/modern-normalize/download/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7" + integrity sha1-2o6AFA2SIUJr1PclxuESg9NPkLc= + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.nlark.com/move-concurrently/download/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -8894,11 +8969,21 @@ nan@^2.12.1: resolved "https://registry.nlark.com/nan/download/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha1-9TdkAGlRaPTMaUrJOT0MlYXu6hk= +nanocolors@^0.1.5: + version "0.1.6" + resolved "https://registry.nlark.com/nanocolors/download/nanocolors-0.1.6.tgz#bc2350d3edfdbfadd7ac018c855ae7c13905a6ad" + integrity sha1-vCNQ0+39v63XrAGMhVrnwTkFpq0= + nanoid@^3.1.23: version "3.1.23" resolved "https://registry.nlark.com/nanoid/download/nanoid-3.1.23.tgz?cache=0&sync_timestamp=1620673983269&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnanoid%2Fdownload%2Fnanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" integrity sha1-90QIbOfCvEfuCoRyV01ceOQYOoE= +nanoid@^3.1.25: + version "3.1.25" + resolved "https://registry.nlark.com/nanoid/download/nanoid-3.1.25.tgz?cache=0&sync_timestamp=1628771923493&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnanoid%2Fdownload%2Fnanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha1-CcoydHwOVD8OGBS303k0d/nI4VI= + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -8956,6 +9041,13 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" +node-emoji@^1.11.0: + version "1.11.0" + resolved "https://registry.nlark.com/node-emoji/download/node-emoji-1.11.0.tgz?cache=0&sync_timestamp=1628672555671&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnode-emoji%2Fdownload%2Fnode-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" + integrity sha1-aaAVDmlG4vEV6dfqTfeXHiYoMBw= + dependencies: + lodash "^4.17.21" + node-environment-flags@1.0.5: version "1.0.5" resolved "https://registry.nlark.com/node-environment-flags/download/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" @@ -9030,6 +9122,11 @@ node-releases@^1.1.61, node-releases@^1.1.71: resolved "https://registry.nlark.com/node-releases/download/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" integrity sha1-3U6B3dUnf/hGuAtSu0DEnt96eyA= +node-releases@^1.1.76: + version "1.1.76" + resolved "https://registry.nlark.com/node-releases/download/node-releases-1.1.76.tgz?cache=0&sync_timestamp=1632151316505&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnode-releases%2Fdownload%2Fnode-releases-1.1.76.tgz#df245b062b0cafbd5282ab6792f7dccc2d97f36e" + integrity sha1-3yRbBisMr71SgqtnkvfczC2X824= + normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.nlark.com/normalize-package-data/download/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -9134,6 +9231,11 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-hash@^2.2.0: + version "2.2.0" + resolved "https://registry.nlark.com/object-hash/download/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha1-WtUYWB7vxEO9djRyuP8unCwNVKU= + object-inspect@^1.10.3, object-inspect@^1.9.0: version "1.10.3" resolved "https://registry.nlark.com/object-inspect/download/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" @@ -9923,6 +10025,14 @@ postcss-initial@^3.0.0: dependencies: postcss "^7.0.2" +postcss-js@^3.0.3: + version "3.0.3" + resolved "https://registry.nlark.com/postcss-js/download/postcss-js-3.0.3.tgz#2f0bd370a2e8599d45439f6970403b5873abda33" + integrity sha1-LwvTcKLoWZ1FQ59pcEA7WHOr2jM= + dependencies: + camelcase-css "^2.0.1" + postcss "^8.1.6" + postcss-lab-function@^2.0.1: version "2.0.1" resolved "https://registry.npm.taobao.org/postcss-lab-function/download/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" @@ -9940,6 +10050,15 @@ postcss-load-config@^2.0.0: cosmiconfig "^5.0.0" import-cwd "^2.0.0" +postcss-load-config@^3.1.0: + version "3.1.0" + resolved "https://registry.nlark.com/postcss-load-config/download/postcss-load-config-3.1.0.tgz#d39c47091c4aec37f50272373a6a648ef5e97829" + integrity sha1-05xHCRxK7Df1AnI3OmpkjvXpeCk= + dependencies: + import-cwd "^3.0.0" + lilconfig "^2.0.3" + yaml "^1.10.2" + postcss-loader@3.0.0: version "3.0.0" resolved "https://registry.nlark.com/postcss-loader/download/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" @@ -10059,6 +10178,13 @@ postcss-modules-values@^3.0.0: icss-utils "^4.0.0" postcss "^7.0.6" +postcss-nested@5.0.6: + version "5.0.6" + resolved "https://registry.nlark.com/postcss-nested/download/postcss-nested-5.0.6.tgz?cache=0&sync_timestamp=1627468122159&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-nested%2Fdownload%2Fpostcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" + integrity sha1-RmND9/yNPUavPn26P81H0FKpRbw= + dependencies: + postcss-selector-parser "^6.0.6" + postcss-nesting@^7.0.0: version "7.0.1" resolved "https://registry.nlark.com/postcss-nesting/download/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" @@ -10308,7 +10434,7 @@ postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.6: version "6.0.6" resolved "https://registry.nlark.com/postcss-selector-parser/download/postcss-selector-parser-6.0.6.tgz?cache=0&sync_timestamp=1620752924836&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" integrity sha1-LFu6gXSsL2mBq2MaQqsO5UrzMuo= @@ -10334,7 +10460,7 @@ postcss-unique-selectors@^4.0.1: postcss "^7.0.0" uniqs "^2.0.0" -postcss-value-parser@^3.0.0: +postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0: version "3.3.1" resolved "https://registry.nlark.com/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha1-n/giVH4okyE88cMO+lGsX9G6goE= @@ -10371,6 +10497,15 @@ postcss@^8.1.0: nanoid "^3.1.23" source-map-js "^0.6.2" +postcss@^8.1.6, postcss@^8.2.1, postcss@^8.3.7: + version "8.3.7" + resolved "https://registry.nlark.com/postcss/download/postcss-8.3.7.tgz?cache=0&sync_timestamp=1632290182939&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss%2Fdownload%2Fpostcss-8.3.7.tgz#ec88563588c8da8e58e7226f7633b51ae221eeda" + integrity sha1-7IhWNYjI2o5Y5yJvdjO1GuIh7to= + dependencies: + nanocolors "^0.1.5" + nanoid "^3.1.25" + source-map-js "^0.6.2" + postcss@^8.3.6: version "8.3.6" resolved "https://registry.nlark.com/postcss/download/postcss-8.3.6.tgz?cache=0&sync_timestamp=1626882933935&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fpostcss%2Fdownload%2Fpostcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" @@ -10418,6 +10553,11 @@ pretty-format@^26.0.0, pretty-format@^26.6.0, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" +pretty-hrtime@^1.0.3: + version "1.0.3" + resolved "https://registry.nlark.com/pretty-hrtime/download/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -10552,6 +10692,16 @@ pure-color@^1.2.0: resolved "https://registry.npm.taobao.org/pure-color/download/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4= +purgecss@^4.0.3: + version "4.0.3" + resolved "https://registry.npm.taobao.org/purgecss/download/purgecss-4.0.3.tgz#8147b429f9c09db719e05d64908ea8b672913742" + integrity sha1-gUe0KfnAnbcZ4F1kkI6otnKRN0I= + dependencies: + commander "^6.0.0" + glob "^7.0.0" + postcss "^8.2.1" + postcss-selector-parser "^6.0.2" + q@^1.1.2: version "1.5.1" resolved "https://registry.nlark.com/q/download/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -10607,6 +10757,11 @@ queue-microtask@^1.2.2: resolved "https://registry.npm.taobao.org/queue-microtask/download/queue-microtask-1.2.3.tgz?cache=0&sync_timestamp=1616391471040&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fqueue-microtask%2Fdownload%2Fqueue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha1-SSkii7xyTfrEPg77BYyve2z7YkM= +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.nlark.com/quick-lru/download/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha1-NmST5rPkKjpoheLpnRj4D7eoyTI= + raf-schd@^4.0.2: version "4.0.3" resolved "https://registry.npm.taobao.org/raf-schd/download/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" @@ -10999,6 +11154,14 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +reduce-css-calc@^2.1.8: + version "2.1.8" + resolved "https://registry.npm.taobao.org/reduce-css-calc/download/reduce-css-calc-2.1.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freduce-css-calc%2Fdownload%2Freduce-css-calc-2.1.8.tgz#7ef8761a28d614980dc0c982f772c93f7a99de03" + integrity sha1-fvh2GijWFJgNwMmC93LJP3qZ3gM= + dependencies: + css-unit-converter "^1.1.1" + postcss-value-parser "^3.3.0" + redux@^4.0.0, redux@^4.0.4: version "4.1.0" resolved "https://registry.nlark.com/redux/download/redux-4.1.0.tgz?cache=0&sync_timestamp=1619286844146&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fredux%2Fdownload%2Fredux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4" @@ -12304,6 +12467,44 @@ table@^6.0.9: string-width "^4.2.0" strip-ansi "^6.0.0" +tailwindcss@^2.2.15: + version "2.2.15" + resolved "https://registry.npmmirror.com/tailwindcss/download/tailwindcss-2.2.15.tgz#8bee3ebe68b988c050508ce20633f35b040dd9fe" + integrity sha1-i+4+vmi5iMBQUIziBjPzWwQN2f4= + dependencies: + arg "^5.0.1" + bytes "^3.0.0" + chalk "^4.1.2" + chokidar "^3.5.2" + color "^4.0.1" + cosmiconfig "^7.0.1" + detective "^5.2.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.7" + fs-extra "^10.0.0" + glob-parent "^6.0.1" + html-tags "^3.1.0" + is-color-stop "^1.1.0" + is-glob "^4.0.1" + lodash "^4.17.21" + lodash.topath "^4.5.2" + modern-normalize "^1.1.0" + node-emoji "^1.11.0" + normalize-path "^3.0.0" + object-hash "^2.2.0" + postcss-js "^3.0.3" + postcss-load-config "^3.1.0" + postcss-nested "5.0.6" + postcss-selector-parser "^6.0.6" + postcss-value-parser "^4.1.0" + pretty-hrtime "^1.0.3" + purgecss "^4.0.3" + quick-lru "^5.1.1" + reduce-css-calc "^2.1.8" + resolve "^1.20.0" + tmp "^0.2.1" + tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" resolved "https://registry.nlark.com/tapable/download/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" @@ -12457,6 +12658,13 @@ tiny-invariant@^1.0.6: resolved "https://registry.npm.taobao.org/tiny-invariant/download/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha1-Y0xfjv3CdxS384bDXmdgmR0jCHU= +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.nlark.com/tmp/download/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha1-hFf8MDfc9HGcJRNnoa9lAO4czxQ= + dependencies: + rimraf "^3.0.0" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.npm.taobao.org/tmpl/download/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -12585,11 +12793,6 @@ tslib@^2.0.3, tslib@^2.2.0: resolved "https://registry.nlark.com/tslib/download/tslib-2.3.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftslib%2Fdownload%2Ftslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha1-gDuM2rPhK6WBpMpByIObuw2ssJ4= -tslib@^2.1.0: - version "2.3.1" - resolved "https://registry.nlark.com/tslib/download/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha1-6KM1rdXOrlGqJh0ypJAVjvBC7wE= - tslib@~2.0.3: version "2.0.3" resolved "https://registry.nlark.com/tslib/download/tslib-2.0.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftslib%2Fdownload%2Ftslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" @@ -13451,10 +13654,10 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" -visual-insights@0.6.2: - version "0.6.2" - resolved "https://registry.nlark.com/visual-insights/download/visual-insights-0.6.2.tgz?cache=0&sync_timestamp=1631964426593&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvisual-insights%2Fdownload%2Fvisual-insights-0.6.2.tgz#590a7339192c2b79ee6dcf4f6db06b1d505829db" - integrity sha1-WQpzORksK3nubc9PbbBrHVBYKds= +visual-insights@0.6.3: + version "0.6.3" + resolved "https://registry.nlark.com/visual-insights/download/visual-insights-0.6.3.tgz#ed398cf2b26946d03b49aea4c48ea857f6abddeb" + integrity sha1-7TmM8rJpRtA7Sa6kxI6oV/ar3es= dependencies: assert "^2.0.0" cube-core "^2.13.0" @@ -13992,7 +14195,7 @@ xmlchars@^2.2.0: resolved "https://registry.npm.taobao.org/xmlchars/download/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha1-Bg/hvLf5x2/ioX24apvDq4lCEMs= -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q= @@ -14017,7 +14220,7 @@ yallist@^4.0.0: resolved "https://registry.nlark.com/yallist/download/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI= -yaml@^1.10.0, yaml@^1.7.2: +yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: version "1.10.2" resolved "https://registry.nlark.com/yaml/download/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha1-IwHF/78StGfejaIzOkWeKeeSDks=