Update formatting

This commit is contained in:
Bogdan Lyashenko 2018-08-06 20:54:28 +02:00
parent ff73d22972
commit 2c74e91470
38 changed files with 2951 additions and 3117 deletions

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"printWidth": 100,
"parser": "babylon",
"singleQuote": true,
"tabWidth": 2
}

View File

@ -9,7 +9,8 @@
"start:client": "cd src/public && webpack --progress --colors --watch --env dev",
"start:server": "nodemon ./src/server/index.js",
"start:server-debug": "nodemon --inspect ./src/server/index.js",
"start:demo": "node ./src/server/index.js"
"start:demo": "node ./src/server/index.js",
"pretty": "prettier --write \"./src/public/js/**/*.js\""
},
"dependencies": {
"antd": "^3.5.0",
@ -44,6 +45,7 @@
"devDependencies": {
"babel-preset-stage-2": "^6.24.1",
"nodemon": "^1.17.3",
"prettier": "^1.14.0",
"webpack-cli": "^2.1.2"
},
"nodemonConfig": {

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -8,26 +8,23 @@ import SideBar from './components/side-bar/SideBarContainer';
import './App.css';
const App = () => {
return (
<div className="App-container">
<header className="App-header">
<DataBus />
<ViewsSwitches />
</header>
return (
<div className="App-container">
<header className="App-header">
<DataBus />
<ViewsSwitches />
</header>
<div className="App-body">
<TreeDiagram />
<SideBar />
</div>
<div className="App-body">
<TreeDiagram />
<SideBar />
</div>
<footer className="App-footer">
Bohdan Liashenko{' '}
<a href="https://github.com/Bogdan-Lyashenko/codecrumbs">
Project Github
</a>
</footer>
</div>
);
<footer className="App-footer">
Bohdan Liashenko <a href="https://github.com/Bogdan-Lyashenko/codecrumbs">Project Github</a>
</footer>
</div>
);
};
export default App;

View File

@ -4,14 +4,17 @@ import { toggleSwitch, fireButtonAction } from './store/actions';
import { CONTROLS_KEYS } from './store/constants';
const mapStateToProps = state => {
const { switches, checkedState, disabledState } = state.viewSwitches;
const { switches, checkedState, disabledState } = state.viewSwitches;
return { switches, checkedState, disabledState };
return { switches, checkedState, disabledState };
};
const mapDispatchToProps = {
toggleSwitch,
fireButtonAction
toggleSwitch,
fireButtonAction
};
export default connect(mapStateToProps, mapDispatchToProps)(ViewSwitchList);
export default connect(
mapStateToProps,
mapDispatchToProps
)(ViewSwitchList);

View File

@ -4,77 +4,65 @@ import './ViewSwitchList.css';
import { VIEW_TYPES } from '../store/constants';
class ViewsSwitchList extends React.Component {
renderChildren(controls) {
const {
toggleSwitch,
checkedState,
disabledState,
fireButtonAction
} = this.props;
renderChildren(controls) {
const { toggleSwitch, checkedState, disabledState, fireButtonAction } = this.props;
return (
<div className="ViewSwitchList-small-group">
{controls.map((item, i) => {
return (
<div
key={item.key}
className="ViewSwitchList-small-item"
>
{item.type === VIEW_TYPES.BUTTON ? (
<Button
title={item.title}
size={'small'}
disabled={disabledState[item.key]}
onClick={() => fireButtonAction(item.key)}
>
<span title={item.title}>{item.name}</span>
</Button>
) : (
<Checkbox
checked={checkedState[item.key]}
onChange={e =>
toggleSwitch(item.key, e.target.checked)
}
>
<span title={item.title}>{item.name}</span>
</Checkbox>
)}
</div>
);
})}
return (
<div className="ViewSwitchList-small-group">
{controls.map((item, i) => {
return (
<div key={item.key} className="ViewSwitchList-small-item">
{item.type === VIEW_TYPES.BUTTON ? (
<Button
title={item.title}
size={'small'}
disabled={disabledState[item.key]}
onClick={() => fireButtonAction(item.key)}
>
<span title={item.title}>{item.name}</span>
</Button>
) : (
<Checkbox
checked={checkedState[item.key]}
onChange={e => toggleSwitch(item.key, e.target.checked)}
>
<span title={item.title}>{item.name}</span>
</Checkbox>
)}
</div>
);
}
);
})}
</div>
);
}
render() {
const { switches, toggleSwitch, checkedState } = this.props;
render() {
const { switches, toggleSwitch, checkedState } = this.props;
return (
<div className="ViewSwitchList-container">
{switches.map((item, i) => {
return (
<div className="ViewSwitchList-group" key={item.key}>
<div className="ViewSwitchList-big-item">
<span>{item.name + ' '}</span>
<Switch
size="small"
checked={checkedState[item.key]}
onChange={checked =>
toggleSwitch(item.key, checked)
}
/>
</div>
return (
<div className="ViewSwitchList-container">
{switches.map((item, i) => {
return (
<div className="ViewSwitchList-group" key={item.key}>
<div className="ViewSwitchList-big-item">
<span>{item.name + ' '}</span>
<Switch
size="small"
checked={checkedState[item.key]}
onChange={checked => toggleSwitch(item.key, checked)}
/>
</div>
{(checkedState[item.key] &&
item.children.length &&
this.renderChildren(item.children)) ||
null}
</div>
);
})}
{(checkedState[item.key] &&
item.children.length &&
this.renderChildren(item.children)) ||
null}
</div>
);
}
);
})}
</div>
);
}
}
export default ViewsSwitchList;

View File

@ -1,16 +1,16 @@
import { ACTIONS } from './constants';
export const toggleSwitch = (switchKey, checked) => ({
type: ACTIONS.TOGGLE_SWITCH,
payload: { switchKey, checked }
type: ACTIONS.TOGGLE_SWITCH,
payload: { switchKey, checked }
});
export const fireButtonAction = buttonKey => ({
type: ACTIONS.FIRE_BUTTON_ACTION,
payload: buttonKey
type: ACTIONS.FIRE_BUTTON_ACTION,
payload: buttonKey
});
export const setDisabledControl = (controlKey, disabled) => ({
type: ACTIONS.SET_DISABLED_CONTROL,
payload: { controlKey, disabled }
type: ACTIONS.SET_DISABLED_CONTROL,
payload: { controlKey, disabled }
});

View File

@ -1,21 +1,21 @@
export const ACTIONS = {
TOGGLE_SWITCH: 'SWITCHES_LIST.TOGGLE_SWITCH',
FIRE_BUTTON_ACTION: 'SWITCHES_LIST.FIRE_BUTTON_ACTION',
SET_DISABLED_CONTROL: 'SWITCHES_LIST.SET_DISABLED_CONTROL'
TOGGLE_SWITCH: 'SWITCHES_LIST.TOGGLE_SWITCH',
FIRE_BUTTON_ACTION: 'SWITCHES_LIST.FIRE_BUTTON_ACTION',
SET_DISABLED_CONTROL: 'SWITCHES_LIST.SET_DISABLED_CONTROL'
};
export const CONTROLS_KEYS = {
SOURCE: 'source',
SOURCE_COLLAPSE_TO_MIN: 'sourceCollapseToMin',
SOURCE_EXPAND_ALL: 'sourceExpandAll',
DEPENDENCIES: 'dependencies',
DEPENDENCIES_SHOW_ALL: 'dependenciesShowAll',
DEPENDENCIES_SHOW_ONE_MODULE: 'dependenciesShowOneModule',
CODE_CRUMBS: 'codeCrumbs',
CODE_CRUMBS_MINIMIZE: 'codeCrumbsMinimize',
CODE_CRUMBS_DETAILS: 'codeCrumbsDetails'
SOURCE: 'source',
SOURCE_COLLAPSE_TO_MIN: 'sourceCollapseToMin',
SOURCE_EXPAND_ALL: 'sourceExpandAll',
DEPENDENCIES: 'dependencies',
DEPENDENCIES_SHOW_ALL: 'dependenciesShowAll',
DEPENDENCIES_SHOW_ONE_MODULE: 'dependenciesShowOneModule',
CODE_CRUMBS: 'codeCrumbs',
CODE_CRUMBS_MINIMIZE: 'codeCrumbsMinimize',
CODE_CRUMBS_DETAILS: 'codeCrumbsDetails'
};
export const VIEW_TYPES = {
BUTTON: 'icon'
BUTTON: 'icon'
};

View File

@ -1,106 +1,106 @@
import { ACTIONS, CONTROLS_KEYS, VIEW_TYPES } from './constants';
const DefaultState = {
switches: [
switches: [
{
name: 'Source',
key: CONTROLS_KEYS.SOURCE,
children: [
{
name: 'Source',
key: CONTROLS_KEYS.SOURCE,
children: [
{
name: 'close all',
title: 'Close folders to 2nd Level',
key: CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN,
type: VIEW_TYPES.BUTTON
},
{
name: 'open all',
title: 'Open all folders',
key: CONTROLS_KEYS.SOURCE_EXPAND_ALL,
type: VIEW_TYPES.BUTTON
}
]
name: 'close all',
title: 'Close folders to 2nd Level',
key: CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN,
type: VIEW_TYPES.BUTTON
},
{
name: 'Dependencies',
key: CONTROLS_KEYS.DEPENDENCIES,
children: [
{
name: 'show all',
title: 'Show All dependencies',
key: CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL,
type: VIEW_TYPES.BUTTON
},
{
name: 'direct only',
title: 'Show One module dependencies',
key: CONTROLS_KEYS.DEPENDENCIES_SHOW_ONE_MODULE
}
]
},
{
name: 'CodeCrumbs',
key: CONTROLS_KEYS.CODE_CRUMBS,
children: [
{
name: 'minimize',
title: 'Minimize code crumbs',
key: CONTROLS_KEYS.CODE_CRUMBS_MINIMIZE
},
{
name: 'show details',
title: 'Show all Details',
key: CONTROLS_KEYS.CODE_CRUMBS_DETAILS
}
]
name: 'open all',
title: 'Open all folders',
key: CONTROLS_KEYS.SOURCE_EXPAND_ALL,
type: VIEW_TYPES.BUTTON
}
],
checkedState: {
[CONTROLS_KEYS.SOURCE]: true
]
},
disabledState: {
[CONTROLS_KEYS.SOURCE_EXPAND_ALL]: true,
[CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL]: true
{
name: 'Dependencies',
key: CONTROLS_KEYS.DEPENDENCIES,
children: [
{
name: 'show all',
title: 'Show All dependencies',
key: CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL,
type: VIEW_TYPES.BUTTON
},
{
name: 'direct only',
title: 'Show One module dependencies',
key: CONTROLS_KEYS.DEPENDENCIES_SHOW_ONE_MODULE
}
]
},
{
name: 'CodeCrumbs',
key: CONTROLS_KEYS.CODE_CRUMBS,
children: [
{
name: 'minimize',
title: 'Minimize code crumbs',
key: CONTROLS_KEYS.CODE_CRUMBS_MINIMIZE
},
{
name: 'show details',
title: 'Show all Details',
key: CONTROLS_KEYS.CODE_CRUMBS_DETAILS
}
]
}
],
checkedState: {
[CONTROLS_KEYS.SOURCE]: true
},
disabledState: {
[CONTROLS_KEYS.SOURCE_EXPAND_ALL]: true,
[CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL]: true
}
};
export default (state = DefaultState, action) => {
switch (action.type) {
case ACTIONS.TOGGLE_SWITCH:
const { switchKey, checked } = action.payload;
switch (action.type) {
case ACTIONS.TOGGLE_SWITCH:
const { switchKey, checked } = action.payload;
return {
...state,
checkedState: {
...state.checkedState,
[switchKey]: checked
}
};
break;
return {
...state,
checkedState: {
...state.checkedState,
[switchKey]: checked
}
};
break;
case ACTIONS.FIRE_BUTTON_ACTION:
const buttonKey = action.payload;
case ACTIONS.FIRE_BUTTON_ACTION:
const buttonKey = action.payload;
return {
...state,
disabledState: {
...state.disabledState,
[buttonKey]: true
}
};
return {
...state,
disabledState: {
...state.disabledState,
[buttonKey]: true
}
};
case ACTIONS.SET_DISABLED_CONTROL:
const { controlKey, disabled } = action.payload;
case ACTIONS.SET_DISABLED_CONTROL:
const { controlKey, disabled } = action.payload;
return {
...state,
disabledState: {
...state.disabledState,
[controlKey]: disabled
}
};
break;
return {
...state,
disabledState: {
...state.disabledState,
[controlKey]: disabled
}
};
break;
default:
return state;
}
default:
return state;
}
};

View File

@ -3,47 +3,44 @@ import { connect } from 'react-redux';
import { createConnection } from '../../utils/connection';
import { SOCKET_EVENT_TYPE } from '../../../../shared/constants';
import {
setInitialSourceData,
calcFilesTreeLayoutNodes
} from './store/actions';
import { setInitialSourceData, calcFilesTreeLayoutNodes } from './store/actions';
class DataBusContainer extends React.Component {
componentDidMount() {
createConnection(({ type, data }) => this.onSocketEvent(type, data));
componentDidMount() {
createConnection(({ type, data }) => this.onSocketEvent(type, data));
}
onSocketEvent(type, data) {
switch (type) {
case SOCKET_EVENT_TYPE.SYNC_SOURCE_FILES:
const { filesTree, filesList, dependenciesList } = data.body;
const { setInitialSourceData, calcFilesTreeLayoutNodes } = this.props;
setInitialSourceData({
filesTree,
filesList,
dependenciesList
});
calcFilesTreeLayoutNodes();
break;
default:
break;
}
}
onSocketEvent(type, data) {
switch (type) {
case SOCKET_EVENT_TYPE.SYNC_SOURCE_FILES:
const { filesTree, filesList, dependenciesList } = data.body;
const {
setInitialSourceData,
calcFilesTreeLayoutNodes
} = this.props;
setInitialSourceData({
filesTree,
filesList,
dependenciesList
});
calcFilesTreeLayoutNodes();
break;
default:
break;
}
}
render() {
return <div className="DataBus-container" />;
}
render() {
return <div className="DataBus-container" />;
}
}
const mapDispatchToProps = {
setInitialSourceData,
calcFilesTreeLayoutNodes
setInitialSourceData,
calcFilesTreeLayoutNodes
};
export default connect(null, mapDispatchToProps)(DataBusContainer);
export default connect(
null,
mapDispatchToProps
)(DataBusContainer);

View File

@ -2,50 +2,50 @@ import { ACTIONS } from './constants';
import { getTreeLayout } from '../../../utils/treeLayout';
export const setInitialSourceData = data => ({
type: ACTIONS.SET_INITIAL_SOURCE_DATA,
payload: data
type: ACTIONS.SET_INITIAL_SOURCE_DATA,
payload: data
});
export const calcFilesTreeLayoutNodes = () => (dispatch, getState) => {
const state = getState();
const { filesTree, closedFolders } = state.dataBus;
const { checkedState } = state.viewSwitches;
const state = getState();
const { filesTree, closedFolders } = state.dataBus;
const { checkedState } = state.viewSwitches;
if (!filesTree) return;
if (!filesTree) return;
return dispatch({
type: ACTIONS.UPDATE_FILES_TREE_LAYOUT_NODES,
payload: getTreeLayout(filesTree, {
includeFileChildren: checkedState.codeCrumbs,
closedFolders
})
});
return dispatch({
type: ACTIONS.UPDATE_FILES_TREE_LAYOUT_NODES,
payload: getTreeLayout(filesTree, {
includeFileChildren: checkedState.codeCrumbs,
closedFolders
})
});
};
export const selectFile = fileNode => ({
type: ACTIONS.SELECT_FILE,
payload: fileNode
type: ACTIONS.SELECT_FILE,
payload: fileNode
});
export const toggleFolder = folderNode => ({
type: ACTIONS.TOGGLE_FOLDER,
payload: folderNode
type: ACTIONS.TOGGLE_FOLDER,
payload: folderNode
});
export const openAllFolders = () => ({
type: ACTIONS.OPEN_ALL_FOLDERS
type: ACTIONS.OPEN_ALL_FOLDERS
});
export const closeAllFolders = () => ({
type: ACTIONS.CLOSE_ALL_FOLDERS
type: ACTIONS.CLOSE_ALL_FOLDERS
});
export const selectCodeCrumb = (fileNode, codeCrumb) => ({
type: ACTIONS.SELECT_CODE_CRUMB,
payload: { fileNode, codeCrumb }
type: ACTIONS.SELECT_CODE_CRUMB,
payload: { fileNode, codeCrumb }
});
export const setDependenciesEntryPoint = (fileNode) => ({
type: ACTIONS.SET_DEPENDENCIES_ENTRY_POINT,
payload: fileNode
export const setDependenciesEntryPoint = fileNode => ({
type: ACTIONS.SET_DEPENDENCIES_ENTRY_POINT,
payload: fileNode
});

View File

@ -1,10 +1,10 @@
export const ACTIONS = {
SET_INITIAL_SOURCE_DATA: 'DATA_BUS.SET_INITIAL_SOURCE_DATA',
UPDATE_FILES_TREE_LAYOUT_NODES: 'DATA_BUS.UPDATE_FILES_TREE_LAYOUT_NODES',
SELECT_FILE: 'DATA_BUS.SELECT_FILE',
TOGGLE_FOLDER: 'DATA_BUS.TOGGLE_FOLDER',
OPEN_ALL_FOLDERS: 'DATA_BUS.OPEN_ALL_FOLDERS',
CLOSE_ALL_FOLDERS: 'DATA_BUS.CLOSE_ALL_FOLDERS',
SELECT_CODE_CRUMB: 'DATA_BUS.SELECT_CODE_CRUMB',
SET_DEPENDENCIES_ENTRY_POINT: 'DATA_BUS.SET_DEPENDENCIES_ENTRY_POINT'
SET_INITIAL_SOURCE_DATA: 'DATA_BUS.SET_INITIAL_SOURCE_DATA',
UPDATE_FILES_TREE_LAYOUT_NODES: 'DATA_BUS.UPDATE_FILES_TREE_LAYOUT_NODES',
SELECT_FILE: 'DATA_BUS.SELECT_FILE',
TOGGLE_FOLDER: 'DATA_BUS.TOGGLE_FOLDER',
OPEN_ALL_FOLDERS: 'DATA_BUS.OPEN_ALL_FOLDERS',
CLOSE_ALL_FOLDERS: 'DATA_BUS.CLOSE_ALL_FOLDERS',
SELECT_CODE_CRUMB: 'DATA_BUS.SELECT_CODE_CRUMB',
SET_DEPENDENCIES_ENTRY_POINT: 'DATA_BUS.SET_DEPENDENCIES_ENTRY_POINT'
};

View File

@ -3,96 +3,90 @@ import { DIR_NODE_TYPE } from '../../../../../shared/constants';
import { ACTIONS } from './constants';
const DefaultState = {
filesTree: null,
filesList: null,
dependenciesList: null,
filesTree: null,
filesList: null,
dependenciesList: null,
filesTreeLayoutNodes: null,
closedFolders: {},
firstLevelFolders: {}
filesTreeLayoutNodes: null,
closedFolders: {},
firstLevelFolders: {}
};
export default (state = DefaultState, action) => {
switch (action.type) {
case ACTIONS.SET_INITIAL_SOURCE_DATA:
return {
...state,
...action.payload,
dependenciesRootEntryPoint: action.payload.dependenciesList[0],
isCurrentDependenciesEntryPointRoot: true,
switch (action.type) {
case ACTIONS.SET_INITIAL_SOURCE_DATA:
return {
...state,
...action.payload,
dependenciesRootEntryPoint: action.payload.dependenciesList[0],
isCurrentDependenciesEntryPointRoot: true,
firstLevelFolders: safeGet(
action.payload,
'filesTree.children',
[]
)
.filter(item => item.type === DIR_NODE_TYPE)
.reduce((res, item) => {
res[item.path] = item;
return res;
}, {})
};
firstLevelFolders: safeGet(action.payload, 'filesTree.children', [])
.filter(item => item.type === DIR_NODE_TYPE)
.reduce((res, item) => {
res[item.path] = item;
return res;
}, {})
};
case ACTIONS.UPDATE_FILES_TREE_LAYOUT_NODES:
return {
...state,
filesTreeLayoutNodes: action.payload
};
case ACTIONS.UPDATE_FILES_TREE_LAYOUT_NODES:
return {
...state,
filesTreeLayoutNodes: action.payload
};
case ACTIONS.SELECT_FILE:
return {
...state,
selectedCodeCrumb: null,
selectedFile: action.payload
};
case ACTIONS.SELECT_FILE:
return {
...state,
selectedCodeCrumb: null,
selectedFile: action.payload
};
case ACTIONS.TOGGLE_FOLDER:
const { closedFolders } = state;
const folderPath = action.payload.path;
case ACTIONS.TOGGLE_FOLDER:
const { closedFolders } = state;
const folderPath = action.payload.path;
return {
...state,
closedFolders: closedFolders[folderPath]
? { ...closedFolders, [folderPath]: null }
: { ...closedFolders, [folderPath]: action.payload }
};
return {
...state,
closedFolders: closedFolders[folderPath]
? { ...closedFolders, [folderPath]: null }
: { ...closedFolders, [folderPath]: action.payload }
};
case ACTIONS.OPEN_ALL_FOLDERS:
return {
...state,
closedFolders: {}
};
case ACTIONS.OPEN_ALL_FOLDERS:
return {
...state,
closedFolders: {}
};
case ACTIONS.CLOSE_ALL_FOLDERS:
return {
...state,
closedFolders: {
...state.closedFolders,
...state.firstLevelFolders
}
};
case ACTIONS.CLOSE_ALL_FOLDERS:
return {
...state,
closedFolders: {
...state.closedFolders,
...state.firstLevelFolders
}
};
case ACTIONS.SELECT_CODE_CRUMB:
const { fileNode, codeCrumb } = action.payload;
return {
...state,
selectedFile: fileNode,
selectedCodeCrumb: codeCrumb
};
case ACTIONS.SELECT_CODE_CRUMB:
const { fileNode, codeCrumb } = action.payload;
return {
...state,
selectedFile: fileNode,
selectedCodeCrumb: codeCrumb
};
case ACTIONS.SET_DEPENDENCIES_ENTRY_POINT:
const entry = action.payload;
const rootEntryPointModuleName =
state.dependenciesRootEntryPoint.moduleName;
case ACTIONS.SET_DEPENDENCIES_ENTRY_POINT:
const entry = action.payload;
const rootEntryPointModuleName = state.dependenciesRootEntryPoint.moduleName;
return {
...state,
dependenciesEntryPoint: entry,
isCurrentDependenciesEntryPointRoot:
entry && entry.path === rootEntryPointModuleName
};
return {
...state,
dependenciesEntryPoint: entry,
isCurrentDependenciesEntryPointRoot: entry && entry.path === rootEntryPointModuleName
};
default:
return state;
}
default:
return state;
}
};

View File

@ -2,22 +2,22 @@ import React from 'react';
import debounce from 'lodash.debounce';
class ResizeWrapper extends React.Component {
constructor(props) {
super(props);
this.handler = debounce(() => props.onResize());
}
constructor(props) {
super(props);
this.handler = debounce(() => props.onResize());
}
componentDidMount() {
window.addEventListener('resize', this.handler);
}
componentDidMount() {
window.addEventListener('resize', this.handler);
}
componentWillUnmount() {
window.addEventListener('resize', this.handler);
}
componentWillUnmount() {
window.addEventListener('resize', this.handler);
}
render() {
return null;
}
render() {
return null;
}
}
export default ResizeWrapper;

View File

@ -4,29 +4,26 @@ import SideBar from './component/SideBar';
import { selectFile } from '../data-bus/store/actions';
const SideBarContainer = ({ selectedFile, selectedCodeCrumb, onClose }) => {
if (!selectedFile) return null;
if (!selectedFile) return null;
//TODO: add animation slide
return (
<SideBar
file={selectedFile}
codeCrumb={selectedCodeCrumb}
onClose={onClose}
/>
);
//TODO: add animation slide
return <SideBar file={selectedFile} codeCrumb={selectedCodeCrumb} onClose={onClose} />;
};
const mapStateToProps = state => {
const { selectedFile, selectedCodeCrumb } = state.dataBus;
const { selectedFile, selectedCodeCrumb } = state.dataBus;
return {
selectedFile,
selectedCodeCrumb
};
return {
selectedFile,
selectedCodeCrumb
};
};
const mapDispatchToProps = dispatch => ({
onClose: () => dispatch(selectFile(null))
onClose: () => dispatch(selectFile(null))
});
export default connect(mapStateToProps, mapDispatchToProps)(SideBarContainer);
export default connect(
mapStateToProps,
mapDispatchToProps
)(SideBarContainer);

View File

@ -6,12 +6,12 @@ import { atomOneLight } from 'react-syntax-highlighter/styles/hljs';
//TODO: scrool to/highlight crumbed lines
//https://github.com/conorhastings/react-syntax-highlighter/blob/master/README.md
export default ({ code, crumbedLines = [] }) => (
<SyntaxHighlighter
language="javascript"
style={atomOneLight}
customStyle={{ fontSize: '13px' }}
showLineNumbers={true}
>
{code}
</SyntaxHighlighter>
<SyntaxHighlighter
language="javascript"
style={atomOneLight}
customStyle={{ fontSize: '13px' }}
showLineNumbers={true}
>
{code}
</SyntaxHighlighter>
);

View File

@ -6,37 +6,32 @@ import Code from './Code/Code';
//TODO: Add slide from right animation
export default ({ file, codeCrumb, onClose }) => {
const crumbedLines = !codeCrumb
? []
: codeCrumb.crumbedLineNode.loc.start.line;
const crumbedLines = !codeCrumb ? [] : codeCrumb.crumbedLineNode.loc.start.line;
return (
<div className="SideBar-container">
<div className="SideBar-header">
<div>{file.path}</div>
<a href="#" onClick={onClose}>
X
</a>
</div>
return (
<div className="SideBar-container">
<div className="SideBar-header">
<div>{file.path}</div>
<a href="#" onClick={onClose}>
X
</a>
</div>
<div className="SideBar-body">
{file.fileCode && (
<Tabs defaultActiveKey="1" onChange={() => {}}>
<TabPane tab="Code" key="1">
<Code
code={file.fileCode}
crumbedLines={crumbedLines}
/>
</TabPane>
<TabPane tab="FlowChart" key="2">
Content of Tab Pane 2
</TabPane>
<TabPane tab="Crumbs" key="3">
Content of Tab Pane 3
</TabPane>
</Tabs>
)}
</div>
</div>
);
<div className="SideBar-body">
{file.fileCode && (
<Tabs defaultActiveKey="1" onChange={() => {}}>
<TabPane tab="Code" key="1">
<Code code={file.fileCode} crumbedLines={crumbedLines} />
</TabPane>
<TabPane tab="FlowChart" key="2">
Content of Tab Pane 2
</TabPane>
<TabPane tab="Crumbs" key="3">
Content of Tab Pane 3
</TabPane>
</Tabs>
)}
</div>
</div>
);
};

View File

@ -1,40 +1,43 @@
import { connect } from 'react-redux';
import TreeDiagram from './component/TreeDiagram';
import {
selectCodeCrumb,
selectFile,
setDependenciesEntryPoint,
toggleFolder
selectCodeCrumb,
selectFile,
setDependenciesEntryPoint,
toggleFolder
} from '../data-bus/store/actions';
const mapStateToProps = state => {
const { checkedState } = state.viewSwitches;
const {
filesTreeLayoutNodes,
dependenciesList,
closedFolders,
dependenciesEntryPoint
} = state.dataBus;
const { checkedState } = state.viewSwitches;
const {
filesTreeLayoutNodes,
dependenciesList,
closedFolders,
dependenciesEntryPoint
} = state.dataBus;
return {
sourceDiagramOn: checkedState.source,
dependenciesDiagramOn: checkedState.dependencies,
dependenciesShowOneModule: checkedState.dependenciesShowOneModule,
codeCrumbsDiagramOn: checkedState.codeCrumbs,
codeCrumbsMinimize: checkedState.codeCrumbsMinimize,
codeCrumbsDetails: checkedState.codeCrumbsDetails,
filesTreeLayoutNodes,
dependenciesList,
closedFolders,
dependenciesEntryPoint
};
return {
sourceDiagramOn: checkedState.source,
dependenciesDiagramOn: checkedState.dependencies,
dependenciesShowOneModule: checkedState.dependenciesShowOneModule,
codeCrumbsDiagramOn: checkedState.codeCrumbs,
codeCrumbsMinimize: checkedState.codeCrumbsMinimize,
codeCrumbsDetails: checkedState.codeCrumbsDetails,
filesTreeLayoutNodes,
dependenciesList,
closedFolders,
dependenciesEntryPoint
};
};
const mapDispatchToProps = {
onCodeCrumbSelect: selectCodeCrumb,
onFileSelect: selectFile,
onFileIconClick: setDependenciesEntryPoint,
onFolderClick: toggleFolder
onCodeCrumbSelect: selectCodeCrumb,
onFileSelect: selectFile,
onFileIconClick: setDependenciesEntryPoint,
onFolderClick: toggleFolder
};
export default connect(mapStateToProps, mapDispatchToProps)(TreeDiagram);
export default connect(
mapStateToProps,
mapDispatchToProps
)(TreeDiagram);

View File

@ -1,165 +1,148 @@
import React from 'react';
import { withSvgDraw } from '../utils/SvgDraw';
import {
drawCodeCrumbEdge,
drawPartEdge,
drawCodeCrumbLoc,
drawPopOver
} from './drawHelpers';
import { drawCodeCrumbEdge, drawPartEdge, drawCodeCrumbLoc, drawPopOver } from './drawHelpers';
import { drawFileText, drawFileIcon } from '../SourceTree/drawHelpers';
import { getFilesList } from '../../../../utils/treeLayout';
import { createSet } from '../utils/SvgSet';
class CodeCrumbsTree extends React.Component {
componentDidMount() {
this.drawSet = createSet(this.props.primaryDraw);
this.drawTree();
}
componentDidMount() {
this.drawSet = createSet(this.props.primaryDraw);
this.drawTree();
}
componentDidUpdate() {
this.clearDraw();
this.drawTree();
}
componentDidUpdate() {
this.clearDraw();
this.drawTree();
}
componentWillUnmount() {
this.clearDraw();
}
componentWillUnmount() {
this.clearDraw();
}
shouldComponentUpdate(nextProps) {
return true;
//TODO: missing overlapping elements: text&icons
/*const oldProps = this.props;
shouldComponentUpdate(nextProps) {
return true;
//TODO: missing overlapping elements: text&icons
/*const oldProps = this.props;
return oldProps.filesTreeLayoutNodes !== nextProps.filesTreeLayoutNodes;*/
}
}
clearDraw() {
this.drawSet.clearAll();
}
clearDraw() {
this.drawSet.clearAll();
}
drawTree() {
const {
primaryDraw,
filesTreeLayoutNodes,
shiftToCenterPoint,
sourceDiagramOn,
dependenciesDiagramOn,
codeCrumbsMinimize,
codeCrumbsDetails,
onCodeCrumbSelect
} = this.props;
drawTree() {
const {
primaryDraw,
filesTreeLayoutNodes,
shiftToCenterPoint,
sourceDiagramOn,
dependenciesDiagramOn,
codeCrumbsMinimize,
codeCrumbsDetails,
onCodeCrumbSelect
} = this.props;
const { add } = this.drawSet;
const { add } = this.drawSet;
const filesList = getFilesList(filesTreeLayoutNodes);
filesList.forEach(node => {
const [nX, nY] = [node.y, node.x];
const filesList = getFilesList(filesTreeLayoutNodes);
filesList.forEach(node => {
const [nX, nY] = [node.y, node.x];
if (node.children) {
if (!sourceDiagramOn && !dependenciesDiagramOn) {
add(
drawFileText(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
name: node.data.name
})
);
if (node.children) {
if (!sourceDiagramOn && !dependenciesDiagramOn) {
add(
drawFileText(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
name: node.data.name
})
);
add(
drawFileIcon(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
codeCrumbsMinimize
})
);
add(
drawFileIcon(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
codeCrumbsMinimize
})
);
}
!codeCrumbsMinimize &&
add(
drawPartEdge(primaryDraw, shiftToCenterPoint, {
source: {
x: nX,
y: nY
},
parentName: node.data.name
})
);
!codeCrumbsMinimize &&
node.children.forEach((crumb, i, list) => {
const [cX, cY] = [crumb.y, crumb.x];
const singleCrumb = list.length === 1;
!singleCrumb &&
add(
drawCodeCrumbEdge(primaryDraw, shiftToCenterPoint, {
source: {
x: nX,
y: nY
},
target: {
x: cX,
y: cY
},
parentName: node.data.name
})
);
//TODO: refactor mess
const loc = crumb.data.crumbedLineNode.loc.start;
add(
drawCodeCrumbLoc(primaryDraw, shiftToCenterPoint, {
x: cX,
y: cY,
loc: `(${loc.line},${loc.column})`,
name: crumb.data.name,
singleCrumb,
onMouseOver() {
if (!crumb.data.params.details || codeCrumbsDetails) return null;
return drawPopOver(primaryDraw, shiftToCenterPoint, {
x: cX,
y: cY,
name: crumb.data.params.details,
singleCrumb
});
},
onClick() {
onCodeCrumbSelect(node.data, crumb.data);
}
})
);
!codeCrumbsMinimize &&
add(
drawPartEdge(primaryDraw, shiftToCenterPoint, {
source: {
x: nX,
y: nY
},
parentName: node.data.name
})
);
!codeCrumbsMinimize &&
node.children.forEach((crumb, i, list) => {
const [cX, cY] = [crumb.y, crumb.x];
const singleCrumb = list.length === 1;
!singleCrumb &&
add(
drawCodeCrumbEdge(
primaryDraw,
shiftToCenterPoint,
{
source: {
x: nX,
y: nY
},
target: {
x: cX,
y: cY
},
parentName: node.data.name
}
)
);
//TODO: refactor mess
const loc = crumb.data.crumbedLineNode.loc.start;
add(
drawCodeCrumbLoc(primaryDraw, shiftToCenterPoint, {
x: cX,
y: cY,
loc: `(${loc.line},${loc.column})`,
name: crumb.data.name,
singleCrumb,
onMouseOver() {
if (
!crumb.data.params.details ||
codeCrumbsDetails
)
return null;
return drawPopOver(
primaryDraw,
shiftToCenterPoint,
{
x: cX,
y: cY,
name: crumb.data.params.details,
singleCrumb
}
);
},
onClick() {
onCodeCrumbSelect(node.data, crumb.data);
}
})
);
if (codeCrumbsDetails && crumb.data.params.details) {
add(
drawPopOver(primaryDraw, shiftToCenterPoint, {
x: cX,
y: cY,
name: crumb.data.params.details,
singleCrumb
})
);
}
});
if (codeCrumbsDetails && crumb.data.params.details) {
add(
drawPopOver(primaryDraw, shiftToCenterPoint, {
x: cX,
y: cY,
name: crumb.data.params.details,
singleCrumb
})
);
}
});
}
});
}
});
}
render() {
return null;
}
render() {
return null;
}
}
export default withSvgDraw(CodeCrumbsTree);

View File

@ -1,135 +1,113 @@
import { PURPLE_COLOR, BLUE_COLOR, SYMBOL_WIDTH } from '../../store/constants';
export const drawCodeCrumbEdge = (
draw,
shiftToCenterPoint,
{ target, source, parentName }
) => {
const nameWidth = SYMBOL_WIDTH * parentName.length;
const padding = 40;
const edgeTurnDistance = 20;
export const drawCodeCrumbEdge = (draw, shiftToCenterPoint, { target, source, parentName }) => {
const nameWidth = SYMBOL_WIDTH * parentName.length;
const padding = 40;
const edgeTurnDistance = 20;
const P1 = shiftToCenterPoint(source.x + nameWidth + padding, source.y);
const P1 = shiftToCenterPoint(source.x + nameWidth + padding, source.y);
const P2 = shiftToCenterPoint(target.x - edgeTurnDistance, source.y);
const P3 = shiftToCenterPoint(target.x - edgeTurnDistance, target.y);
const P4 = shiftToCenterPoint(target.x, target.y);
const P2 = shiftToCenterPoint(target.x - edgeTurnDistance, source.y);
const P3 = shiftToCenterPoint(target.x - edgeTurnDistance, target.y);
const P4 = shiftToCenterPoint(target.x, target.y);
const polyline = draw.polyline([
[P1.x, P1.y],
[P2.x, P2.y],
[P3.x, P3.y],
[P4.x, P4.y]
]);
const polyline = draw.polyline([[P1.x, P1.y], [P2.x, P2.y], [P3.x, P3.y], [P4.x, P4.y]]);
polyline.fill('none').stroke({
color: PURPLE_COLOR
});
polyline.fill('none').stroke({
color: PURPLE_COLOR
});
return polyline;
return polyline;
};
export const drawPartEdge = (
draw,
shiftToCenterPoint,
{ source, parentName }
) => {
const nameWidth = SYMBOL_WIDTH * parentName.length;
const padding = 17;
export const drawPartEdge = (draw, shiftToCenterPoint, { source, parentName }) => {
const nameWidth = SYMBOL_WIDTH * parentName.length;
const padding = 17;
const P1 = shiftToCenterPoint(source.x + nameWidth + padding, source.y);
const P2 = { x: P1.x + padding + 6, y: P1.y };
const P1 = shiftToCenterPoint(source.x + nameWidth + padding, source.y);
const P2 = { x: P1.x + padding + 6, y: P1.y };
const polyline = draw.polyline([[P1.x, P1.y], [P2.x, P2.y]]);
const polyline = draw.polyline([[P1.x, P1.y], [P2.x, P2.y]]);
polyline.fill('none').stroke({
color: PURPLE_COLOR
});
polyline.fill('none').stroke({
color: PURPLE_COLOR
});
const smallLine = draw
.line(P1.x, P1.y - 2, P1.x, P1.y + 2)
.stroke({ color: PURPLE_COLOR });
const smallLine = draw.line(P1.x, P1.y - 2, P1.x, P1.y + 2).stroke({ color: PURPLE_COLOR });
return [polyline, smallLine];
return [polyline, smallLine];
};
export const drawCodeCrumbLoc = (
draw,
shiftToCenterPoint,
{ x, y, name = '', loc, singleCrumb, onClick, onMouseOver }
draw,
shiftToCenterPoint,
{ x, y, name = '', loc, singleCrumb, onClick, onMouseOver }
) => {
const textPointShiftX = 3;
const textPointShiftY = 5;
const textPoint = shiftToCenterPoint(singleCrumb ? x - 20 : x, y);
const textPointShiftX = 3;
const textPointShiftY = 5;
const textPoint = shiftToCenterPoint(singleCrumb ? x - 20 : x, y);
const locWidth = loc.length * 6;
const locRec = draw
.rect(locWidth, 12)
.fill('#fff')
.stroke(PURPLE_COLOR)
.move(textPoint.x, textPoint.y - 6);
const locWidth = loc.length * 6;
const locRec = draw
.rect(locWidth, 12)
.fill('#fff')
.stroke(PURPLE_COLOR)
.move(textPoint.x, textPoint.y - 6);
const locText = draw.text(loc);
locText
.font({ fill: '#595959', family: 'Menlo', size: '8px' })
.style({ cursor: 'pointer' })
.move(textPoint.x + textPointShiftX, textPoint.y - textPointShiftY);
const locText = draw.text(loc);
locText
.font({ fill: '#595959', family: 'Menlo', size: '8px' })
.style({ cursor: 'pointer' })
.move(textPoint.x + textPointShiftX, textPoint.y - textPointShiftY);
if (onMouseOver) {
let popOver = null;
locText.on('mouseover', () => {
popOver = onMouseOver();
});
locText.on('mouseout', () => {
popOver && popOver[0].remove() && popOver[1].remove();
});
}
if (onClick) {
locText.on('click', onClick);
}
if (name) {
const nameText = draw.text(':' + name);
nameText.font({ fill: '#595959', family: 'Menlo', size: '12px' });
//TODO: refactor to use one way, plus or minus
nameText.move(
textPoint.x + textPointShiftX + locWidth - 1,
textPoint.y - textPointShiftY - 2
);
return [locRec, locText, nameText];
}
return [locRec, locText];
};
export const drawPopOver = (
draw,
shiftToCenterPoint,
{ x, y, name = '', singleCrumb }
) => {
const tPt = shiftToCenterPoint(x - 15 + (singleCrumb ? 0 : 20), y - 24);
const nameWidth = name.length * 6;
const nameHeight = 8;
const padding = 5;
const polyline = draw.polyline([
[tPt.x - padding, tPt.y + nameHeight + padding + 3],
[tPt.x - padding, tPt.y - padding],
[tPt.x + nameWidth + 2 * padding, tPt.y - padding],
[tPt.x + nameWidth + 2 * padding, tPt.y + nameHeight + padding],
[tPt.x - padding + 3, tPt.y + nameHeight + padding],
[tPt.x - padding, tPt.y + nameHeight + padding + 3]
]);
polyline.fill('#fff').stroke({
color: PURPLE_COLOR
if (onMouseOver) {
let popOver = null;
locText.on('mouseover', () => {
popOver = onMouseOver();
});
locText.on('mouseout', () => {
popOver && popOver[0].remove() && popOver[1].remove();
});
}
const text = draw.text(name);
text.font({ fill: '#595959', family: 'Menlo', size: '10px' });
text.move(tPt.x+2, tPt.y - 1);
if (onClick) {
locText.on('click', onClick);
}
return [text, polyline];
if (name) {
const nameText = draw.text(':' + name);
nameText.font({ fill: '#595959', family: 'Menlo', size: '12px' });
//TODO: refactor to use one way, plus or minus
nameText.move(textPoint.x + textPointShiftX + locWidth - 1, textPoint.y - textPointShiftY - 2);
return [locRec, locText, nameText];
}
return [locRec, locText];
};
export const drawPopOver = (draw, shiftToCenterPoint, { x, y, name = '', singleCrumb }) => {
const tPt = shiftToCenterPoint(x - 15 + (singleCrumb ? 0 : 20), y - 24);
const nameWidth = name.length * 6;
const nameHeight = 8;
const padding = 5;
const polyline = draw.polyline([
[tPt.x - padding, tPt.y + nameHeight + padding + 3],
[tPt.x - padding, tPt.y - padding],
[tPt.x + nameWidth + 2 * padding, tPt.y - padding],
[tPt.x + nameWidth + 2 * padding, tPt.y + nameHeight + padding],
[tPt.x - padding + 3, tPt.y + nameHeight + padding],
[tPt.x - padding, tPt.y + nameHeight + padding + 3]
]);
polyline.fill('#fff').stroke({
color: PURPLE_COLOR
});
const text = draw.text(name);
text.font({ fill: '#595959', family: 'Menlo', size: '10px' });
text.move(tPt.x + 2, tPt.y - 1);
return [text, polyline];
};

View File

@ -5,125 +5,104 @@ import { getFilesList } from '../../../../utils/treeLayout';
import { withSvgDraw } from '../utils/SvgDraw';
class DependenciesTree extends React.Component {
componentDidMount() {
this.drawTree();
}
componentDidMount() {
this.drawTree();
}
componentDidUpdate() {
const { primaryDraw } = this.props;
componentDidUpdate() {
const { primaryDraw } = this.props;
primaryDraw.clear();
this.drawTree();
}
//move to utils
findNodeByPathName = (list = [], pathName) => {
return list.find(l => l.data.path === pathName);
primaryDraw.clear();
this.drawTree();
}
//move to utils
findNodeByPathName = (list = [], pathName) => {
return list.find(l => l.data.path === pathName);
};
getFilteredDependenciesList() {
const { dependenciesList, dependenciesEntryPoint, dependenciesShowOneModule } = this.props;
const entryPoint = dependenciesEntryPoint || {
path: dependenciesList[0].moduleName
};
getFilteredDependenciesList() {
const {
dependenciesList,
dependenciesEntryPoint,
dependenciesShowOneModule
} = this.props;
const entryPoint = dependenciesEntryPoint || {
path: dependenciesList[0].moduleName
};
if (dependenciesShowOneModule) {
return [
dependenciesList.find(d => d.moduleName === entryPoint.path)
];
}
return this.collectDependencies(entryPoint.path, dependenciesList);
if (dependenciesShowOneModule) {
return [dependenciesList.find(d => d.moduleName === entryPoint.path)];
}
collectDependencies(entryModuleName, dependenciesList) {
let queue = [].concat(entryModuleName),
store = [];
return this.collectDependencies(entryPoint.path, dependenciesList);
}
while (queue.length) {
let moduleName = queue.shift(),
entryModule = dependenciesList.find(
d => d.moduleName === moduleName
);
collectDependencies(entryModuleName, dependenciesList) {
let queue = [].concat(entryModuleName),
store = [];
store.push(entryModule);
while (queue.length) {
let moduleName = queue.shift(),
entryModule = dependenciesList.find(d => d.moduleName === moduleName);
const nodeBody = entryModule.importedModuleNames;
if (nodeBody) {
queue = [...queue, ...nodeBody];
}
}
store.push(entryModule);
return store;
const nodeBody = entryModule.importedModuleNames;
if (nodeBody) {
queue = [...queue, ...nodeBody];
}
}
drawTree() {
const {
primaryDraw,
filesTreeLayoutNodes,
shiftToCenterPoint,
sourceDiagramOn
} = this.props;
return store;
}
const moduleFilesList = getFilesList(filesTreeLayoutNodes);
const filteredDependenciesList = this.getFilteredDependenciesList();
drawTree() {
const { primaryDraw, filesTreeLayoutNodes, shiftToCenterPoint, sourceDiagramOn } = this.props;
filteredDependenciesList.forEach(
({ moduleName, importedModuleNames }) => {
const moduleNode = this.findNodeByPathName(
moduleFilesList,
moduleName
);
const moduleFilesList = getFilesList(filesTreeLayoutNodes);
const filteredDependenciesList = this.getFilteredDependenciesList();
if (!moduleNode) return;
filteredDependenciesList.forEach(({ moduleName, importedModuleNames }) => {
const moduleNode = this.findNodeByPathName(moduleFilesList, moduleName);
const [mX, mY] = [moduleNode.y, moduleNode.x];
if (!moduleNode) return;
if (!sourceDiagramOn) {
drawFileText(primaryDraw, shiftToCenterPoint, {
x: mX,
y: mY,
name: moduleNode.data.name
});
drawFileIcon(primaryDraw, shiftToCenterPoint, {
x: mX,
y: mY
});
}
const [mX, mY] = [moduleNode.y, moduleNode.x];
importedModuleNames.reduce((prevSource, name) => {
const importedNode = this.findNodeByPathName(
moduleFilesList,
name
);
if (!sourceDiagramOn) {
drawFileText(primaryDraw, shiftToCenterPoint, {
x: mX,
y: mY,
name: moduleNode.data.name
});
drawFileIcon(primaryDraw, shiftToCenterPoint, {
x: mX,
y: mY
});
}
if (!importedNode) return;
importedModuleNames.reduce((prevSource, name) => {
const importedNode = this.findNodeByPathName(moduleFilesList, name);
const [iX, iY] = [importedNode.y, importedNode.x];
//TODO: implementation iterations:
//1) done: first with sharp angles + overlay
//2) done: without overlaying, not fot all cases
//3) rounded angles
const source = { x: iX, y: iY };
drawDependenciesEdge(primaryDraw, shiftToCenterPoint, {
source,
target: { x: mX, y: mY },
prevSource
});
if (!importedNode) return;
return source;
}, null);
}
);
}
const [iX, iY] = [importedNode.y, importedNode.x];
//TODO: implementation iterations:
//1) done: first with sharp angles + overlay
//2) done: without overlaying, not fot all cases
//3) rounded angles
const source = { x: iX, y: iY };
drawDependenciesEdge(primaryDraw, shiftToCenterPoint, {
source,
target: { x: mX, y: mY },
prevSource
});
render() {
return null;
}
return source;
}, null);
});
}
render() {
return null;
}
}
export default withSvgDraw(DependenciesTree);

View File

@ -4,95 +4,83 @@ import { BLUE_COLOR, PURPLE_COLOR } from '../../store/constants';
const COLOR = BLUE_COLOR;
export const drawDependenciesEdge = (
draw,
shiftToCenterPoint,
{ source, target, prevSource }
) => {
const padding = 30;
const halfPadding = padding / 2 - 5;
export const drawDependenciesEdge = (draw, shiftToCenterPoint, { source, target, prevSource }) => {
const padding = 30;
const halfPadding = padding / 2 - 5;
const sourcePt = shiftToCenterPoint(
target.y > source.y ? source.x + 10 : source.x + 8,
target.y > source.y ? source.y + 7 : source.y - 12
);
drawSourceDotLine(draw, sourcePt);
const sourcePt = shiftToCenterPoint(
target.y > source.y ? source.x + 10 : source.x + 8,
target.y > source.y ? source.y + 7 : source.y - 12
);
drawSourceDotLine(draw, sourcePt);
if (!prevSource) {
const targetPt = shiftToCenterPoint(target.x, target.y);
if (!prevSource) {
const targetPt = shiftToCenterPoint(target.x, target.y);
const P1 = { x: sourcePt.x, y: targetPt.y + padding - 6};
const P2 = { x: targetPt.x - halfPadding, y: targetPt.y + padding -6 };
const P3 = { x: targetPt.x - halfPadding, y: targetPt.y };
const P1 = { x: sourcePt.x, y: targetPt.y + padding - 6 };
const P2 = { x: targetPt.x - halfPadding, y: targetPt.y + padding - 6 };
const P3 = { x: targetPt.x - halfPadding, y: targetPt.y };
drawConnectionLine(draw, [
[sourcePt.x, sourcePt.y],
[P1.x, P1.y],
[P2.x, P2.y],
[P3.x, P3.y],
[targetPt.x, targetPt.y]
]);
drawConnectionLine(draw, [
[sourcePt.x, sourcePt.y],
[P1.x, P1.y],
[P2.x, P2.y],
[P3.x, P3.y],
[targetPt.x, targetPt.y]
]);
drawArrow(draw, shiftToCenterPoint, target.x, target.y + 6);
} else {
if (prevSource.x < sourcePt.x) { //TODO: handle other cases
const prevSourcePt = shiftToCenterPoint(prevSource.x, prevSource.y);
drawArrow(draw, shiftToCenterPoint, target.x, target.y + 6);
} else {
if (prevSource.x < sourcePt.x) {
//TODO: handle other cases
const prevSourcePt = shiftToCenterPoint(prevSource.x, prevSource.y);
const P1 = { x: sourcePt.x, y: sourcePt.y + halfPadding -3};
const P2 = {
x: prevSourcePt.x + halfPadding,
y: sourcePt.y + halfPadding-3
};
const P1 = { x: sourcePt.x, y: sourcePt.y + halfPadding - 3 };
const P2 = {
x: prevSourcePt.x + halfPadding,
y: sourcePt.y + halfPadding - 3
};
drawConnectionLine(draw, [
[sourcePt.x, sourcePt.y],
[P1.x, P1.y],
[P2.x, P2.y]
]);
drawConnectionLine(draw, [[sourcePt.x, sourcePt.y], [P1.x, P1.y], [P2.x, P2.y]]);
drawDot(draw, P2)
}
drawDot(draw, P2);
}
}
};
export const drawDot = (draw, { x, y }) => {
const radius = 4;
const halfRadius = radius / 2;
const radius = 4;
const halfRadius = radius / 2;
draw
.circle(radius)
.fill(BLUE_COLOR)
.move(x - halfRadius, y - halfRadius);
draw
.circle(radius)
.fill(BLUE_COLOR)
.move(x - halfRadius, y - halfRadius);
};
const drawConnectionLine = (draw, points) => {
const polyline = draw.polyline(points);
const polyline = draw.polyline(points);
polyline.fill('none').stroke({
color: COLOR
});
polyline.fill('none').stroke({
color: COLOR
});
};
const drawSourceDotLine = (draw, { x, y }) => {
draw.line(x - 3, y, x + 3, y).stroke({ width: 1, color: COLOR });
draw.line(x - 3, y, x + 3, y).stroke({ width: 1, color: COLOR });
};
const drawArrow = (draw, shiftToCenterPoint, nX, nY) => {
const fileIconPath = 'resources/right-arrow.svg';
const fileIconSize = 7;
const fileIconPointShiftX = -4;
const fileIconPointShiftY = 9.5;
const fileIconPoint = shiftToCenterPoint(
nX + fileIconPointShiftX,
nY - fileIconPointShiftY
);
const fileIconPath = 'resources/right-arrow.svg';
const fileIconSize = 7;
const fileIconPointShiftX = -4;
const fileIconPointShiftY = 9.5;
const fileIconPoint = shiftToCenterPoint(nX + fileIconPointShiftX, nY - fileIconPointShiftY);
draw
.rect(5, 6)
.fill('#fff')
.move(fileIconPoint.x + 2, fileIconPoint.y);
draw
.rect(5, 6)
.fill('#fff')
.move(fileIconPoint.x + 2, fileIconPoint.y);
draw
.image(fileIconPath, fileIconSize, fileIconSize)
.move(fileIconPoint.x, fileIconPoint.y);
draw.image(fileIconPath, fileIconSize, fileIconSize).move(fileIconPoint.x, fileIconPoint.y);
};

View File

@ -1,147 +1,143 @@
import React from 'react';
import { withSvgDraw } from '../utils/SvgDraw';
import {
drawDot,
drawSourceEdge,
drawFileText,
drawFileIcon,
drawFolderText,
drawFolderIcon
drawDot,
drawSourceEdge,
drawFileText,
drawFileIcon,
drawFolderText,
drawFolderIcon
} from './drawHelpers';
import {
FILE_NODE_TYPE,
DIR_NODE_TYPE
} from '../../../../../../shared/constants';
import { FILE_NODE_TYPE, DIR_NODE_TYPE } from '../../../../../../shared/constants';
import { createSet } from '../utils/SvgSet';
class SourceTree extends React.Component {
componentDidMount() {
this.drawSet = createSet(this.props.primaryDraw);
this.drawTree();
}
componentDidMount() {
this.drawSet = createSet(this.props.primaryDraw);
this.drawTree();
}
componentDidUpdate() {
this.clearPrimaryDraw();
this.clearSecondaryDraw();
componentDidUpdate() {
this.clearPrimaryDraw();
this.clearSecondaryDraw();
this.drawTree();
}
this.drawTree();
}
componentWillUnmount() {
this.clearPrimaryDraw();
}
componentWillUnmount() {
this.clearPrimaryDraw();
}
clearPrimaryDraw() {
this.drawSet.clearAll();
}
clearPrimaryDraw() {
this.drawSet.clearAll();
}
clearSecondaryDraw() {
this.props.secondaryDraw.clear();
}
clearSecondaryDraw() {
this.props.secondaryDraw.clear();
}
drawTree() {
const {
primaryDraw,
secondaryDraw,
layoutNodes,
closedFolders,
shiftToCenterPoint,
dependenciesDiagramOn,
codeCrumbsMinimize,
onFileSelect,
onFileIconClick,
onFolderClick
} = this.props;
drawTree() {
const {
primaryDraw,
secondaryDraw,
layoutNodes,
closedFolders,
shiftToCenterPoint,
dependenciesDiagramOn,
codeCrumbsMinimize,
onFileSelect,
onFileIconClick,
onFolderClick
} = this.props;
const { add } = this.drawSet;
const { add } = this.drawSet;
//note: instance from d3-flex tree, not Array
layoutNodes.each(node => {
const [nX, nY] = [node.y, node.x];
const parent = node.parent;
//note: instance from d3-flex tree, not Array
layoutNodes.each(node => {
const [nX, nY] = [node.y, node.x];
const parent = node.parent;
if (parent && parent.data.type === DIR_NODE_TYPE) {
const [pX, pY] = [parent.y, parent.x];
if (parent && parent.data.type === DIR_NODE_TYPE) {
const [pX, pY] = [parent.y, parent.x];
drawSourceEdge(secondaryDraw, shiftToCenterPoint, {
disabled: dependenciesDiagramOn,
target: {
x: nX,
y: nY
},
source: {
x: pX,
y: pY
},
singleChild: parent.children.length === 1
});
}
if (node.data.type === FILE_NODE_TYPE) {
drawDot(secondaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
disabled: dependenciesDiagramOn
});
add(
drawFileText(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
purple: node.children && codeCrumbsMinimize,
name: node.data.name,
onClick() {
onFileSelect(node.data);
}
})
);
add(
drawFileIcon(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
purple: node.children && codeCrumbsMinimize,
onClick() {
dependenciesDiagramOn && onFileIconClick(node.data);
}
})
);
return;
}
if (node.data.type === DIR_NODE_TYPE) {
drawDot(secondaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
disabled: dependenciesDiagramOn
});
add(
drawFolderText(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
name: node.data.name,
disabled: dependenciesDiagramOn
})
);
add(
drawFolderIcon(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
disabled: dependenciesDiagramOn,
closed: closedFolders[node.data.path],
onClick() {
onFolderClick(node.data);
}
})
);
}
drawSourceEdge(secondaryDraw, shiftToCenterPoint, {
disabled: dependenciesDiagramOn,
target: {
x: nX,
y: nY
},
source: {
x: pX,
y: pY
},
singleChild: parent.children.length === 1
});
}
}
render() {
return null;
}
if (node.data.type === FILE_NODE_TYPE) {
drawDot(secondaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
disabled: dependenciesDiagramOn
});
add(
drawFileText(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
purple: node.children && codeCrumbsMinimize,
name: node.data.name,
onClick() {
onFileSelect(node.data);
}
})
);
add(
drawFileIcon(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
purple: node.children && codeCrumbsMinimize,
onClick() {
dependenciesDiagramOn && onFileIconClick(node.data);
}
})
);
return;
}
if (node.data.type === DIR_NODE_TYPE) {
drawDot(secondaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
disabled: dependenciesDiagramOn
});
add(
drawFolderText(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
name: node.data.name,
disabled: dependenciesDiagramOn
})
);
add(
drawFolderIcon(primaryDraw, shiftToCenterPoint, {
x: nX,
y: nY,
disabled: dependenciesDiagramOn,
closed: closedFolders[node.data.path],
onClick() {
onFolderClick(node.data);
}
})
);
}
});
}
render() {
return null;
}
}
export default withSvgDraw(SourceTree);

View File

@ -5,174 +5,136 @@ import { BLUE_COLOR, PURPLE_COLOR, SYMBOL_WIDTH } from '../../store/constants';
//create object instead
const ICONS_DIR = 'resources/';
export const drawDot = (
draw,
shiftToCenterPoint,
{ x, y, disabled, highlighted }
) => {
const radius = 5;
const halfRadius = radius / 2;
const circlePoint = shiftToCenterPoint(x - halfRadius, y - halfRadius);
export const drawDot = (draw, shiftToCenterPoint, { x, y, disabled, highlighted }) => {
const radius = 5;
const halfRadius = radius / 2;
const circlePoint = shiftToCenterPoint(x - halfRadius, y - halfRadius);
let color = '#BFBFBF';
if (disabled) {
color = '#ccc';
}
if (highlighted) {
color = BLUE_COLOR;
}
let color = '#BFBFBF';
if (disabled) {
color = '#ccc';
}
if (highlighted) {
color = BLUE_COLOR;
}
return draw
.circle(radius)
.fill(color)
.move(circlePoint.x, circlePoint.y);
return draw
.circle(radius)
.fill(color)
.move(circlePoint.x, circlePoint.y);
};
export const drawSourceEdge = (
draw,
shiftToCenterPoint,
{ target, source, disabled, singleChild }
draw,
shiftToCenterPoint,
{ target, source, disabled, singleChild }
) => {
const edgeTurnDistance = 20;
const edgeTurnDistance = 20;
const START_PT = shiftToCenterPoint(source.x, source.y);
const P2 = shiftToCenterPoint(target.x - edgeTurnDistance, source.y);
const P3 = shiftToCenterPoint(target.x - edgeTurnDistance, target.y);
const END_PT = shiftToCenterPoint(target.x, target.y);
const START_PT = shiftToCenterPoint(source.x, source.y);
const P2 = shiftToCenterPoint(target.x - edgeTurnDistance, source.y);
const P3 = shiftToCenterPoint(target.x - edgeTurnDistance, target.y);
const END_PT = shiftToCenterPoint(target.x, target.y);
const points = singleChild
? [[START_PT.x, START_PT.y], [END_PT.x, END_PT.y]]
: [
[START_PT.x, START_PT.y],
[P2.x, P2.y],
[P3.x, P3.y],
[END_PT.x, END_PT.y]
];
const points = singleChild
? [[START_PT.x, START_PT.y], [END_PT.x, END_PT.y]]
: [[START_PT.x, START_PT.y], [P2.x, P2.y], [P3.x, P3.y], [END_PT.x, END_PT.y]];
const polyline = draw.polyline(points);
const polyline = draw.polyline(points);
const color = !disabled ? '#BFBFBF' : '#ccc';
polyline.fill('none').stroke({
color
});
return polyline;
};
export const drawFileText = (draw, shiftToCenterPoint, { x, y, purple, name = '', onClick }) => {
const text = draw.text(name);
text.font({ fill: purple ? PURPLE_COLOR : '#595959', family: 'Menlo' });
const fileTextPointShiftX = 16;
const fileTextPointShiftY = 8;
const fileTextPoint = shiftToCenterPoint(x + fileTextPointShiftX, y - fileTextPointShiftY);
text.move(fileTextPoint.x, fileTextPoint.y);
if (onClick) {
text.style({ cursor: 'pointer' }).on('click', onClick);
}
return text;
};
export const drawFileIcon = (draw, shiftToCenterPoint, { x, y, purple, onClick }) => {
const fileIconPath = ICONS_DIR + (purple ? 'js-file-purple.svg' : 'js-file.svg');
const fileIconSize = 15;
const fileIconPointShiftX = 2;
const fileIconPointShiftY = 10;
const fileIconPoint = shiftToCenterPoint(x + fileIconPointShiftX, y - fileIconPointShiftY);
const icon = draw
.image(fileIconPath, fileIconSize, fileIconSize)
.move(fileIconPoint.x, fileIconPoint.y);
if (onClick) {
icon.style({ cursor: 'pointer' }).on('click', onClick);
}
return icon;
};
export const drawFolderText = (draw, shiftToCenterPoint, { x, y, name = '', disabled }) => {
const folderTextPointShiftX = 20;
const folderTextPointShiftY = 16;
const folderTextPoint = shiftToCenterPoint(x + folderTextPointShiftX, y - folderTextPointShiftY);
const fill = !disabled ? '#595959' : '#A9A8A8';
const text = draw.text(name);
text.font({ fill, family: 'Menlo' });
text.move(folderTextPoint.x, folderTextPoint.y);
return text;
};
export const drawFolderIcon = (draw, shiftToCenterPoint, { x, y, disabled, closed, onClick }) => {
const folderIconPath = `${ICONS_DIR}${closed ? 'closed-' : ''}folder${
disabled ? '-disabled' : ''
}.svg`;
const folderIconSize = closed ? 14 : 15;
const folderIconPointShiftX = closed ? 3 : 3;
const folderIconPointShiftY = closed ? 16 : 17;
const folderIconPoint = shiftToCenterPoint(x + folderIconPointShiftX, y - folderIconPointShiftY);
let polyline = null;
if (closed) {
polyline = draw.polyline([
folderIconPoint.x - 1,
folderIconPoint.y + 16,
folderIconPoint.x + 16,
folderIconPoint.y + 16,
folderIconPoint.x + 16,
folderIconPoint.y + 14
]);
const color = !disabled ? '#BFBFBF' : '#ccc';
polyline.fill('none').stroke({
color
color
});
}
return polyline;
};
export const drawFileText = (
draw,
shiftToCenterPoint,
{ x, y, purple, name = '', onClick }
) => {
const text = draw.text(name);
text.font({ fill: purple ? PURPLE_COLOR : '#595959', family: 'Menlo' });
const fileTextPointShiftX = 16;
const fileTextPointShiftY = 8;
const fileTextPoint = shiftToCenterPoint(
x + fileTextPointShiftX,
y - fileTextPointShiftY
);
text.move(fileTextPoint.x, fileTextPoint.y);
if (onClick) {
text.style({ cursor: 'pointer' }).on('click', onClick);
}
return text;
};
export const drawFileIcon = (
draw,
shiftToCenterPoint,
{ x, y, purple, onClick }
) => {
const fileIconPath =
ICONS_DIR + (purple ? 'js-file-purple.svg' : 'js-file.svg');
const fileIconSize = 15;
const fileIconPointShiftX = 2;
const fileIconPointShiftY = 10;
const fileIconPoint = shiftToCenterPoint(
x + fileIconPointShiftX,
y - fileIconPointShiftY
);
const icon = draw
.image(fileIconPath, fileIconSize, fileIconSize)
.move(fileIconPoint.x, fileIconPoint.y);
if (onClick) {
icon.style({ cursor: 'pointer' }).on('click', onClick);
}
return icon;
};
export const drawFolderText = (
draw,
shiftToCenterPoint,
{ x, y, name = '', disabled }
) => {
const folderTextPointShiftX = 20;
const folderTextPointShiftY = 16;
const folderTextPoint = shiftToCenterPoint(
x + folderTextPointShiftX,
y - folderTextPointShiftY
);
const fill = !disabled ? '#595959' : '#A9A8A8';
const text = draw.text(name);
text.font({ fill, family: 'Menlo' });
text.move(folderTextPoint.x, folderTextPoint.y);
return text;
};
export const drawFolderIcon = (
draw,
shiftToCenterPoint,
{ x, y, disabled, closed, onClick }
) => {
const folderIconPath = `${ICONS_DIR}${closed ? 'closed-' : ''}folder${
disabled ? '-disabled' : ''
}.svg`;
const folderIconSize = closed ? 14 : 15;
const folderIconPointShiftX = closed ? 3 : 3;
const folderIconPointShiftY = closed ? 16 : 17;
const folderIconPoint = shiftToCenterPoint(
x + folderIconPointShiftX,
y - folderIconPointShiftY
);
let polyline = null;
if (closed) {
polyline = draw.polyline([
folderIconPoint.x - 1,
folderIconPoint.y + 16,
folderIconPoint.x + 16,
folderIconPoint.y + 16,
folderIconPoint.x + 16,
folderIconPoint.y + 14
]);
const color = !disabled ? '#BFBFBF' : '#ccc';
polyline.fill('none').stroke({
color
});
}
const icon = draw
.image(folderIconPath, folderIconSize, folderIconSize)
.move(folderIconPoint.x, folderIconPoint.y);
if (onClick) {
icon.style({ cursor: 'pointer' }).on('click', onClick);
}
if (!polyline) return icon;
return [icon, polyline];
const icon = draw
.image(folderIconPath, folderIconSize, folderIconSize)
.move(folderIconPoint.x, folderIconPoint.y);
if (onClick) {
icon.style({ cursor: 'pointer' }).on('click', onClick);
}
if (!polyline) return icon;
return [icon, polyline];
};

View File

@ -5,118 +5,118 @@ import CodeCrumbsTree from './CodeCrumbsTree/CodeCrumbsTree';
import './TreeDiagram.css';
class TreeDiagram extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
this.setState({ layersReady: true });
}
componentDidMount() {
this.setState({ layersReady: true });
}
//cc: layers
renderLayers() {
return (
<div className="TreeDiagram-layers">
<div
data-name="sourceEdgesLayer"
className="TreeDiagram-layer"
ref={ref => (this.sourceEdgesLayer = ref)}
/>
<div
data-name="dependenciesEdgesLayer"
className="TreeDiagram-layer"
ref={ref => (this.dependenciesEdgesLayer = ref)}
/>
<div
data-name="iconsAndTextLayer"
className="TreeDiagram-layer"
ref={ref => (this.iconsAndTextLayer = ref)}
/>
</div>
);
}
//cc: layers
renderLayers() {
return (
<div className="TreeDiagram-layers">
<div
data-name="sourceEdgesLayer"
className="TreeDiagram-layer"
ref={ref => (this.sourceEdgesLayer = ref)}
/>
<div
data-name="dependenciesEdgesLayer"
className="TreeDiagram-layer"
ref={ref => (this.dependenciesEdgesLayer = ref)}
/>
<div
data-name="iconsAndTextLayer"
className="TreeDiagram-layer"
ref={ref => (this.iconsAndTextLayer = ref)}
/>
</div>
);
}
renderDiagrams() {
const {
filesTreeLayoutNodes,
dependenciesList,
closedFolders,
dependenciesEntryPoint,
renderDiagrams() {
const {
filesTreeLayoutNodes,
dependenciesList,
closedFolders,
dependenciesEntryPoint,
sourceDiagramOn,
dependenciesDiagramOn,
dependenciesShowOneModule,
codeCrumbsDiagramOn,
codeCrumbsMinimize,
codeCrumbsDetails,
sourceDiagramOn,
dependenciesDiagramOn,
dependenciesShowOneModule,
codeCrumbsDiagramOn,
codeCrumbsMinimize,
codeCrumbsDetails,
onFileSelect,
onFileIconClick,
onFolderClick,
onCodeCrumbSelect
} = this.props;
onFileSelect,
onFileIconClick,
onFolderClick,
onCodeCrumbSelect
} = this.props;
const sharedProps = {
sourceDiagramOn,
dependenciesDiagramOn,
codeCrumbsDiagramOn,
codeCrumbsMinimize,
codeCrumbsDetails
};
const sharedProps = {
sourceDiagramOn,
dependenciesDiagramOn,
codeCrumbsDiagramOn,
codeCrumbsMinimize,
codeCrumbsDetails
};
return (
<React.Fragment>
{filesTreeLayoutNodes &&
sourceDiagramOn && (
<SourceTree
layoutNodes={filesTreeLayoutNodes}
closedFolders={closedFolders}
secondaryLayer={this.sourceEdgesLayer}
primaryLayer={this.iconsAndTextLayer}
onFileSelect={onFileSelect}
onFileIconClick={onFileIconClick}
onFolderClick={onFolderClick}
{...sharedProps}
/>
)}
return (
<React.Fragment>
{filesTreeLayoutNodes &&
sourceDiagramOn && (
<SourceTree
layoutNodes={filesTreeLayoutNodes}
closedFolders={closedFolders}
secondaryLayer={this.sourceEdgesLayer}
primaryLayer={this.iconsAndTextLayer}
onFileSelect={onFileSelect}
onFileIconClick={onFileIconClick}
onFolderClick={onFolderClick}
{...sharedProps}
/>
)}
{dependenciesList &&
filesTreeLayoutNodes &&
dependenciesDiagramOn && (
<DependenciesTree
dependenciesList={dependenciesList}
filesTreeLayoutNodes={filesTreeLayoutNodes}
dependenciesEntryPoint={dependenciesEntryPoint}
dependenciesShowOneModule={dependenciesShowOneModule}
primaryLayer={this.dependenciesEdgesLayer}
{...sharedProps}
/>
)}
{dependenciesList &&
filesTreeLayoutNodes &&
dependenciesDiagramOn && (
<DependenciesTree
dependenciesList={dependenciesList}
filesTreeLayoutNodes={filesTreeLayoutNodes}
dependenciesEntryPoint={dependenciesEntryPoint}
dependenciesShowOneModule={dependenciesShowOneModule}
primaryLayer={this.dependenciesEdgesLayer}
{...sharedProps}
/>
)}
{filesTreeLayoutNodes &&
codeCrumbsDiagramOn && (
<CodeCrumbsTree
filesTreeLayoutNodes={filesTreeLayoutNodes}
primaryLayer={this.iconsAndTextLayer}
onCodeCrumbSelect={onCodeCrumbSelect}
{...sharedProps}
/>
)}
</React.Fragment>
);
}
{filesTreeLayoutNodes &&
codeCrumbsDiagramOn && (
<CodeCrumbsTree
filesTreeLayoutNodes={filesTreeLayoutNodes}
primaryLayer={this.iconsAndTextLayer}
onCodeCrumbSelect={onCodeCrumbSelect}
{...sharedProps}
/>
)}
</React.Fragment>
);
}
render() {
const { layersReady } = this.state;
render() {
const { layersReady } = this.state;
return (
<div className="TreeDiagram-container">
{this.renderLayers()}
{layersReady && this.renderDiagrams()}
</div>
);
}
return (
<div className="TreeDiagram-container">
{this.renderLayers()}
{layersReady && this.renderDiagrams()}
</div>
);
}
}
export default TreeDiagram;

View File

@ -5,81 +5,80 @@ import { buildShiftToPoint } from '../../../../utils/geometry';
const IconsAndTextLayer = 'iconsAndTextLayer';
const cachedSvgDraws = {};
const BOX_SIZE = {W: 1000, H: 800};
const BOX_SIZE = { W: 1000, H: 800 };
const DOT = {
x: 50,
y: 500
x: 50,
y: 500
};
const shiftToCenterPoint = buildShiftToPoint(DOT);
export const withSvgDraw = Component =>
class extends React.Component {
state = {};
class extends React.Component {
state = {};
createSvg(layer) {
const { width = BOX_SIZE.W, height = BOX_SIZE.H } = this.props;
createSvg(layer) {
const { width = BOX_SIZE.W, height = BOX_SIZE.H } = this.props;
return SVG(layer).size(width, height);
}
return SVG(layer).size(width, height);
}
getPrimaryDraw() {
const { primaryLayer } = this.props;
getPrimaryDraw() {
const { primaryLayer } = this.props;
const primaryLayerName = primaryLayer.dataset.name;
if (primaryLayerName !== IconsAndTextLayer) {
return this.createSvg(primaryLayer);
}
const primaryLayerName = primaryLayer.dataset.name;
if (primaryLayerName !== IconsAndTextLayer) {
return this.createSvg(primaryLayer);
}
if (cachedSvgDraws[primaryLayerName]) {
return cachedSvgDraws[primaryLayerName];
}
if (cachedSvgDraws[primaryLayerName]) {
return cachedSvgDraws[primaryLayerName];
}
cachedSvgDraws[primaryLayerName] = this.createSvg(primaryLayer);
return cachedSvgDraws[primaryLayerName];
}
cachedSvgDraws[primaryLayerName] = this.createSvg(primaryLayer);
return cachedSvgDraws[primaryLayerName];
}
componentDidMount() {
const { secondaryLayer } = this.props;
componentDidMount() {
const { secondaryLayer } = this.props;
let subState = {
primaryDraw: this.getPrimaryDraw()
};
let subState = {
primaryDraw: this.getPrimaryDraw()
};
if (secondaryLayer) {
subState = {
...subState,
secondaryDraw: this.createSvg(secondaryLayer)
};
}
if (secondaryLayer) {
subState = {
...subState,
secondaryDraw: this.createSvg(secondaryLayer)
};
}
this.setState(subState);
}
this.setState(subState);
}
componentWillUnmount() {
const { primaryLayer, secondaryLayer } = this.props;
componentWillUnmount() {
const { primaryLayer, secondaryLayer } = this.props;
if (primaryLayer.dataset.name !== IconsAndTextLayer) {
primaryLayer.removeChild(this.state.primaryDraw.node);
}
if (primaryLayer.dataset.name !== IconsAndTextLayer) {
primaryLayer.removeChild(this.state.primaryDraw.node);
}
secondaryLayer &&
secondaryLayer.removeChild(this.state.secondaryDraw.node);
}
secondaryLayer && secondaryLayer.removeChild(this.state.secondaryDraw.node);
}
render() {
const { primaryDraw, secondaryDraw } = this.state;
render() {
const { primaryDraw, secondaryDraw } = this.state;
return (
(primaryDraw && (
<Component
{...this.props}
primaryDraw={primaryDraw}
secondaryDraw={secondaryDraw}
shiftToCenterPoint={shiftToCenterPoint}
/>
)) ||
null
);
}
};
return (
(primaryDraw && (
<Component
{...this.props}
primaryDraw={primaryDraw}
secondaryDraw={secondaryDraw}
shiftToCenterPoint={shiftToCenterPoint}
/>
)) ||
null
);
}
};

View File

@ -1,16 +1,16 @@
export const createSet = draw => {
const drawSet = draw.set();
const drawSet = draw.set();
return {
add(list) {
drawSet.add.apply(drawSet, [].concat(list));
},
clearAll() {
drawSet.each(function() {
this.off();
this.remove();
});
drawSet.clear();
}
};
return {
add(list) {
drawSet.add.apply(drawSet, [].concat(list));
},
clearAll() {
drawSet.each(function() {
this.off();
this.remove();
});
drawSet.clear();
}
};
};

View File

@ -4,8 +4,8 @@ export const BLUE_COLOR = '#1890ff';
export const SYMBOL_WIDTH = 8.4;
export const LAYOUT_CONFIG = {
symbolWidth: SYMBOL_WIDTH,
nodeSizeX: 20,
nodeSizeY: 60,
spacing: 20
};
symbolWidth: SYMBOL_WIDTH,
nodeSizeX: 20,
nodeSizeY: 60,
spacing: 20
};

View File

@ -10,8 +10,8 @@ const MOUNT_NODE_ID = 'mount-node';
const store = getStore();
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById(MOUNT_NODE_ID)
<Provider store={store}>
<App />
</Provider>,
document.getElementById(MOUNT_NODE_ID)
);

View File

@ -7,15 +7,15 @@ import dataBus from '../components/data-bus/store/reducer';
import rootSaga from './sagas';
export default () => {
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
combineReducers({
viewSwitches,
dataBus
}),
applyMiddleware(thunk, sagaMiddleware)
);
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
combineReducers({
viewSwitches,
dataBus
}),
applyMiddleware(thunk, sagaMiddleware)
);
sagaMiddleware.run(rootSaga);
return store;
sagaMiddleware.run(rootSaga);
return store;
};

View File

@ -2,122 +2,108 @@ import every from 'lodash/every';
import { put, takeEvery, select, all } from 'redux-saga/effects';
import { ACTIONS as DATA_BUS_ACTIONS } from '../components/data-bus/store/constants';
import {
calcFilesTreeLayoutNodes,
openAllFolders,
closeAllFolders,
setDependenciesEntryPoint
calcFilesTreeLayoutNodes,
openAllFolders,
closeAllFolders,
setDependenciesEntryPoint
} from '../components/data-bus/store/actions';
import {
ACTIONS as SWITCHES_ACTIONS,
CONTROLS_KEYS
ACTIONS as SWITCHES_ACTIONS,
CONTROLS_KEYS
} from '../components/controls/ViewSwitches/store/constants';
import {
setDisabledControl,
toggleSwitch
setDisabledControl,
toggleSwitch
} from '../components/controls/ViewSwitches/store/actions';
function* reactOnSwitchToggle(action) {
const { switchKey } = action.payload;
const { switchKey } = action.payload;
if (switchKey === CONTROLS_KEYS.CODE_CRUMBS) {
yield put(calcFilesTreeLayoutNodes());
}
if (switchKey === CONTROLS_KEYS.CODE_CRUMBS) {
yield put(calcFilesTreeLayoutNodes());
}
if (switchKey === CONTROLS_KEYS.DEPENDENCIES_SHOW_ONE_MODULE) {
const isDisabled = yield isDependenciesShowAllDisabled();
yield put(
setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL, isDisabled)
);
}
if (switchKey === CONTROLS_KEYS.DEPENDENCIES_SHOW_ONE_MODULE) {
const isDisabled = yield isDependenciesShowAllDisabled();
yield put(setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL, isDisabled));
}
}
function* reactOnButtonAction(action) {
const buttonKey = action.payload;
const buttonKey = action.payload;
if (buttonKey === CONTROLS_KEYS.SOURCE_EXPAND_ALL) {
return yield all([
put(setDisabledControl(CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN)),
put(openAllFolders()),
put(calcFilesTreeLayoutNodes())
]);
}
if (buttonKey === CONTROLS_KEYS.SOURCE_EXPAND_ALL) {
return yield all([
put(setDisabledControl(CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN)),
put(openAllFolders()),
put(calcFilesTreeLayoutNodes())
]);
}
if (buttonKey === CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN) {
return yield all([
put(setDisabledControl(CONTROLS_KEYS.SOURCE_EXPAND_ALL)),
put(closeAllFolders()),
put(calcFilesTreeLayoutNodes())
]);
}
if (buttonKey === CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN) {
return yield all([
put(setDisabledControl(CONTROLS_KEYS.SOURCE_EXPAND_ALL)),
put(closeAllFolders()),
put(calcFilesTreeLayoutNodes())
]);
}
if (buttonKey === CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL) {
return yield all([
put(toggleSwitch(CONTROLS_KEYS.DEPENDENCIES_SHOW_ONE_MODULE)),
put(setDependenciesEntryPoint(null))
]);
}
if (buttonKey === CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL) {
return yield all([
put(toggleSwitch(CONTROLS_KEYS.DEPENDENCIES_SHOW_ONE_MODULE)),
put(setDependenciesEntryPoint(null))
]);
}
}
function* reactOnToggledFolder(action) {
const dataBusState = yield select(state => state.dataBus);
const { closedFolders, firstLevelFolders } = dataBusState;
const dataBusState = yield select(state => state.dataBus);
const { closedFolders, firstLevelFolders } = dataBusState;
yield all([
put(
setDisabledControl(
CONTROLS_KEYS.SOURCE_EXPAND_ALL,
every(Object.keys(closedFolders), item => !closedFolders[item])
)
),
yield all([
put(
setDisabledControl(
CONTROLS_KEYS.SOURCE_EXPAND_ALL,
every(Object.keys(closedFolders), item => !closedFolders[item])
)
),
put(
setDisabledControl(
CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN,
every(
Object.keys(firstLevelFolders),
item => closedFolders[item]
)
)
)
]);
put(
setDisabledControl(
CONTROLS_KEYS.SOURCE_COLLAPSE_TO_MIN,
every(Object.keys(firstLevelFolders), item => closedFolders[item])
)
)
]);
yield put(calcFilesTreeLayoutNodes());
yield put(calcFilesTreeLayoutNodes());
}
function* reactDependenciesEntryPointChange(action) {
if (!action.payload) {
return yield put(
setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL, true)
);
}
if (!action.payload) {
return yield put(setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL, true));
}
const isDisabled = yield isDependenciesShowAllDisabled();
yield put(
setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL, isDisabled)
);
const isDisabled = yield isDependenciesShowAllDisabled();
yield put(setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_SHOW_ALL, isDisabled));
}
function* isDependenciesShowAllDisabled() {
const isRoot = yield select(
state => state.dataBus.isCurrentDependenciesEntryPointRoot
);
const isRoot = yield select(state => state.dataBus.isCurrentDependenciesEntryPointRoot);
const dependenciesShowOneModule = yield select(
state => state.viewSwitches.checkedState.dependenciesShowOneModule
);
const dependenciesShowOneModule = yield select(
state => state.viewSwitches.checkedState.dependenciesShowOneModule
);
return isRoot && !dependenciesShowOneModule;
return isRoot && !dependenciesShowOneModule;
}
export default function* rootSaga() {
yield all([
takeEvery(SWITCHES_ACTIONS.TOGGLE_SWITCH, reactOnSwitchToggle),
takeEvery(SWITCHES_ACTIONS.FIRE_BUTTON_ACTION, reactOnButtonAction),
takeEvery(DATA_BUS_ACTIONS.TOGGLE_FOLDER, reactOnToggledFolder),
takeEvery(
DATA_BUS_ACTIONS.SET_DEPENDENCIES_ENTRY_POINT,
reactDependenciesEntryPointChange
)
]);
yield all([
takeEvery(SWITCHES_ACTIONS.TOGGLE_SWITCH, reactOnSwitchToggle),
takeEvery(SWITCHES_ACTIONS.FIRE_BUTTON_ACTION, reactOnButtonAction),
takeEvery(DATA_BUS_ACTIONS.TOGGLE_FOLDER, reactOnToggledFolder),
takeEvery(DATA_BUS_ACTIONS.SET_DEPENDENCIES_ENTRY_POINT, reactDependenciesEntryPointChange)
]);
}

View File

@ -1,14 +1,14 @@
export const createConnection = (onMessage, route = 'ws://127.0.0.1:2018/') => {
const ws = new WebSocket(route);
ws.onmessage = event => {
onMessage(JSON.parse(event.data));
};
const ws = new WebSocket(route);
ws.onmessage = event => {
onMessage(JSON.parse(event.data));
};
return msg => {
try {
ws.send(msg);
} catch (e) {
console.log(e);
}
};
return msg => {
try {
ws.send(msg);
} catch (e) {
console.log(e);
}
};
};

View File

@ -3,56 +3,53 @@ import babelTraverse from 'babel-traverse';
import * as d3flextree from 'd3-flextree';
import SVG from 'svg.js';
const astTest = () => {
const ast = babylon.parse(`
const ast = babylon.parse(`
//codecrumb
var a = 12;
var b = 8;//cc//aa
`);
babelTraverse(ast, {
enter(path) {
if (path.node && path.node.leadingComments || path.node.trailingComments) {
//debugger
console.log(path.node.leadingComments, path.node.trailingComments);
}
}
});
babelTraverse(ast, {
enter(path) {
if ((path.node && path.node.leadingComments) || path.node.trailingComments) {
//debugger
console.log(path.node.leadingComments, path.node.trailingComments);
}
}
});
};
const d3test = treeData => {
const draw = SVG('drawing').size(500, 500);
const draw = SVG('drawing').size(500, 500);
const layout = d3flextree.flextree({
children: data => {
return data.children;
},
nodeSize: node => [node.data.name.length, 40],
spacing: (nodeA, nodeB) => 150
});
const tree = layout.hierarchy(treeData);
const lt = layout(tree);
const layout = d3flextree.flextree({
children: data => {
return data.children;
},
nodeSize: node => [node.data.name.length, 40],
spacing: (nodeA, nodeB) => 150
});
const tree = layout.hierarchy(treeData);
const lt = layout(tree);
lt.each(node => {
draw
.circle(10)
.attr({ fill: '#f06' })
.move(node.x + 200, node.y + 200);
lt.each(node => {
draw
.circle(10)
.attr({ fill: '#f06' })
.move(node.x + 200, node.y + 200);
draw.text(node.data.name).move(node.x + 200, node.y + 200);
draw.text(node.data.name).move(node.x + 200, node.y + 200);
if (node.parent) {
let p = node.parent;
draw
.line(p.x + 200, p.y + 200, node.x + 200, node.y + 200)
.stroke({ width: 1 });
}
});
if (node.parent) {
let p = node.parent;
draw.line(p.x + 200, p.y + 200, node.x + 200, node.y + 200).stroke({ width: 1 });
}
});
};
export default p => {
//astTest();
//d3test(p);
//astTest();
//d3test(p);
};

View File

@ -1,5 +1,4 @@
export const buildShiftToPoint = shift => (x, y) => ({
x: shift.x + x,
y: shift.y + y
x: shift.x + x,
y: shift.y + y
});

View File

@ -1,46 +1,45 @@
export const getCurvedPath = (points, theme) => {
const pointStr = points
.map((point, i) => {
if (!i) return `M${point.x}, ${point.y}`;
const pointStr = points
.map((point, i) => {
if (!i) return `M${point.x}, ${point.y}`;
let previousPoint = points[i - 1];
let previousPoint = points[i - 1];
if (i <= 1) {
return getLinePointStr(point, previousPoint, theme.curveTurnRadius);
}
if (i <= 1) {
return getLinePointStr(point, previousPoint, theme.curveTurnRadius);
}
return `Q${previousPoint.x} ${previousPoint.y}
return `Q${previousPoint.x} ${previousPoint.y}
${getArcEndPointStr(point, previousPoint, theme.curveTurnRadius)}
${getLinePointStr(point, previousPoint, 2 * theme.curveTurnRadius)}`;
})
.join(' ');
})
.join(' ');
return pointStr;
return pointStr;
};
const getLinePointStr = (point, previousPoint, radius) => {
if (point.x === previousPoint.x) {
return `L${point.x} ${getShiftedByArcNextPointValue(point.y, previousPoint.y, radius)}`;
}
if (point.x === previousPoint.x) {
return `L${point.x} ${getShiftedByArcNextPointValue(point.y, previousPoint.y, radius)}`;
}
if (point.y === previousPoint.y) {
return `L${getShiftedByArcNextPointValue(point.x, previousPoint.x, radius)} ${point.y} `;
}
if (point.y === previousPoint.y) {
return `L${getShiftedByArcNextPointValue(point.x, previousPoint.x, radius)} ${point.y} `;
}
};
const getShiftedByArcNextPointValue = (pointValue, previousPointValue, radius) =>
pointValue > previousPointValue ? pointValue - radius : pointValue + radius;
pointValue > previousPointValue ? pointValue - radius : pointValue + radius;
const getArcEndPointStr = (point, previousPoint, radius) => {
if (point.x === previousPoint.x) {
return `${previousPoint.x} ${getArcEndPointValue(point.y, previousPoint.y, radius)}`;
}
if (point.x === previousPoint.x) {
return `${previousPoint.x} ${getArcEndPointValue(point.y, previousPoint.y, radius)}`;
}
if (point.y === previousPoint.y) {
return `${getArcEndPointValue(point.x, previousPoint.x, radius)} ${previousPoint.y}`;
}
if (point.y === previousPoint.y) {
return `${getArcEndPointValue(point.x, previousPoint.x, radius)} ${previousPoint.y}`;
}
};
const getArcEndPointValue = (pointValue, previousPointValue, radius) =>
pointValue > previousPointValue ? previousPointValue + radius : previousPointValue - radius;
pointValue > previousPointValue ? previousPointValue + radius : previousPointValue - radius;

View File

@ -3,55 +3,49 @@ import { FILE_NODE_TYPE, DIR_NODE_TYPE } from '../../../shared/constants';
import { LAYOUT_CONFIG } from '../components/tree-diagram/store/constants';
export const getTreeLayout = (
treeData,
{ includeFileChildren, config = LAYOUT_CONFIG, closedFolders }
treeData,
{ includeFileChildren, config = LAYOUT_CONFIG, closedFolders }
) => {
const layoutStructure = d3FlexTree.flextree({
children: data => {
if (data.type === DIR_NODE_TYPE) {
return !closedFolders[data.path] ? data.children : [];
}
const layoutStructure = d3FlexTree.flextree({
children: data => {
if (data.type === DIR_NODE_TYPE) {
return !closedFolders[data.path] ? data.children : [];
}
return includeFileChildren ? data.children : [];
},
nodeSize: node => {
let nameLength = node.data.name.length;
return includeFileChildren ? data.children : [];
},
nodeSize: node => {
let nameLength = node.data.name.length;
//cc: layout calc
if (node.parent && node.data.type === DIR_NODE_TYPE) {
const children = node.parent.children;
nameLength = children.reduce((max, item) => {
if (
item.data.type === DIR_NODE_TYPE &&
item.data.name.length > max
) {
return item.data.name.length;
}
//cc: layout calc
if (node.parent && node.data.type === DIR_NODE_TYPE) {
const children = node.parent.children;
nameLength = children.reduce((max, item) => {
if (item.data.type === DIR_NODE_TYPE && item.data.name.length > max) {
return item.data.name.length;
}
return max;
}, 0);
}
return max;
}, 0);
}
return [
config.nodeSizeX,
nameLength * config.symbolWidth + config.nodeSizeY
];
},
spacing: (nodeA, nodeB) => config.spacing
});
return [config.nodeSizeX, nameLength * config.symbolWidth + config.nodeSizeY];
},
spacing: (nodeA, nodeB) => config.spacing
});
const tree = layoutStructure.hierarchy(treeData);
return layoutStructure(tree);
const tree = layoutStructure.hierarchy(treeData);
return layoutStructure(tree);
};
export const getFilesList = layoutNodes => {
const list = [];
const list = [];
layoutNodes.each(node => {
if (node.data && node.data.type === FILE_NODE_TYPE) {
list.push(node);
}
});
layoutNodes.each(node => {
if (node.data && node.data.type === FILE_NODE_TYPE) {
list.push(node);
}
});
return list;
return list;
};

View File

@ -4687,6 +4687,10 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
prettier@^1.14.0:
version "1.14.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.0.tgz#847c235522035fd988100f1f43cf20a7d24f9372"
prettier@^1.5.3:
version "1.12.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325"