Browse Source

feat: eslint代码规范

master
yangpei 4 years ago
parent
commit
265e0ff322
  1. 22
      .eslintrc.js
  2. 3
      config/cli.jest.config.js
  3. 3
      config/core.jest.config.js
  4. 3
      config/editor.jest.config.js
  5. 3
      config/plugin.jest.config.js
  6. 15
      package-lock.json
  7. 12
      package.json
  8. 1
      packages/cli/package.json
  9. 1
      packages/cli/src/cmd/base/index.js
  10. 12
      packages/cli/src/cmd/dev/addPlugins.js
  11. 9
      packages/cli/src/cmd/dev/extractCodes.js
  12. 6
      packages/cli/src/cmd/dev/index.js
  13. 18
      packages/cli/src/cmd/dev/mergePkg.js
  14. 6
      packages/cli/src/cmd/dev/simplifyDSL.js
  15. 3
      packages/cli/src/cmd/dev/template/context.js
  16. 38
      packages/cli/src/cmd/dev/template/logic.js
  17. 2
      packages/cli/src/cmd/index.js
  18. 1
      packages/cli/src/cmd/init/index.js
  19. 4
      packages/cli/src/utils/getConfig.js
  20. 8
      packages/cli/src/utils/server/index.js
  21. 32
      packages/core/src/api/index.ts
  22. 30
      packages/core/src/common/baseCell/behavior.ts
  23. 52
      packages/core/src/common/baseCell/branch.ts
  24. 2
      packages/core/src/common/baseCell/index.ts
  25. 30
      packages/core/src/common/baseCell/start.ts
  26. 8
      packages/core/src/common/previewCell/behavior.ts
  27. 8
      packages/core/src/common/previewCell/branch.ts
  28. 2
      packages/core/src/common/previewCell/index.ts
  29. 6
      packages/core/src/common/previewCell/start.ts
  30. 41
      packages/core/src/common/shortcuts.ts
  31. 9
      packages/core/src/components/colorPicker/index.tsx
  32. 3
      packages/core/src/components/miniMapSimpleNode/index.tsx
  33. 2
      packages/core/src/components/xIcon/index.tsx
  34. 2
      packages/core/src/index.tsx
  35. 37
      packages/core/src/mods/flowChart/createFlowChart.ts
  36. 11
      packages/core/src/mods/flowChart/index.tsx
  37. 28
      packages/core/src/mods/flowChart/registerServerStorage.ts
  38. 22
      packages/core/src/mods/header/connectStatus/editModal.tsx
  39. 27
      packages/core/src/mods/header/connectStatus/index.tsx
  40. 4
      packages/core/src/mods/header/index.tsx
  41. 17
      packages/core/src/mods/layout/index.tsx
  42. 4
      packages/core/src/mods/settingBar/components/checkbox/index.tsx
  43. 16
      packages/core/src/mods/settingBar/components/code/index.tsx
  44. 2
      packages/core/src/mods/settingBar/components/input/index.tsx
  45. 20
      packages/core/src/mods/settingBar/components/json/index.tsx
  46. 13
      packages/core/src/mods/settingBar/index.tsx
  47. 17
      packages/core/src/mods/settingBar/mods/basic/index.tsx
  48. 17
      packages/core/src/mods/settingBar/mods/config/index.tsx
  49. 11
      packages/core/src/mods/sideBar/index.tsx
  50. 5
      packages/core/src/mods/toolBar/index.tsx
  51. 6
      packages/core/src/mods/toolBar/widgets/bgColor.tsx
  52. 6
      packages/core/src/mods/toolBar/widgets/bold.tsx
  53. 6
      packages/core/src/mods/toolBar/widgets/borderColor.tsx
  54. 6
      packages/core/src/mods/toolBar/widgets/bringToBack.tsx
  55. 6
      packages/core/src/mods/toolBar/widgets/bringToTop.tsx
  56. 2
      packages/core/src/mods/toolBar/widgets/common/makeBtnWidget.tsx
  57. 4
      packages/core/src/mods/toolBar/widgets/fitWindow.tsx
  58. 10
      packages/core/src/mods/toolBar/widgets/fontSize.tsx
  59. 26
      packages/core/src/mods/toolBar/widgets/horizontalAlign.tsx
  60. 2
      packages/core/src/mods/toolBar/widgets/index.tsx
  61. 6
      packages/core/src/mods/toolBar/widgets/italic.tsx
  62. 14
      packages/core/src/mods/toolBar/widgets/lineStyle.tsx
  63. 15
      packages/core/src/mods/toolBar/widgets/modifyStatus.tsx
  64. 6
      packages/core/src/mods/toolBar/widgets/redo.tsx
  65. 6
      packages/core/src/mods/toolBar/widgets/save.tsx
  66. 6
      packages/core/src/mods/toolBar/widgets/textColor.tsx
  67. 6
      packages/core/src/mods/toolBar/widgets/underline.tsx
  68. 6
      packages/core/src/mods/toolBar/widgets/undo.tsx
  69. 32
      packages/core/src/mods/toolBar/widgets/verticalAlign.tsx
  70. 18
      packages/core/src/mods/toolBar/widgets/zoom.tsx
  71. 8
      packages/core/src/utils/flowChartUtils.ts
  72. 5
      packages/core/src/utils/index.ts
  73. 4
      packages/plugin-store/src/index.ts

22
.eslintrc.js

@ -2,11 +2,10 @@ module.exports = {
extends: [
'standard',
'plugin:import/typescript',
'plugin:unicorn/recommended',
'prettier',
'prettier/react',
],
plugins: ['prettier', 'unicorn'],
plugins: ['prettier', 'react'],
env: {
node: true,
browser: true,
@ -15,13 +14,15 @@ module.exports = {
'import/no-extraneous-dependencies': ['error', { peerDependencies: true }],
'prettier/prettier': 'error',
// 修复 tsx 文件引用 tsx 文件报错的问题
'react/jsx-filename-extension': ['error', { extensions: ['.ts', '.tsx'] }],
'unicorn/prevent-abbreviations': 'off',
'react/jsx-filename-extension': ['warn', { extensions: ['.ts', '.tsx'] }],
"semi": [2, "always"],//语句强制分号结尾
"semi-spacing": [0, { "before": false, "after": true }],//分号前后空格
"no-var": 0,//禁用var,用let和const代替
"no-use-before-define": 2,//未定义前不能使用
"no-unused-expressions": 2,//禁止无用的表达式
"space-before-function-paren": 'off',
'comma-dangle': 'off',
'import/extensions': 'off',
},
overrides: [{
files: ['*.ts', '*.tsx'],
@ -35,15 +36,10 @@ module.exports = {
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'no-param-reassign': 'off',
'import/extensions': [
// airbnb 配置导致 tsx 文件引用一直报错
'error',
'ignorePackages',
{
ts: 'never',
tsx: 'never',
},
],
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-unused-vars': 0,
'@typescript-eslint/explicit-function-return-type': 0,
},
},],
};

3
config/cli.jest.config.js

@ -7,5 +7,6 @@ module.exports = {
moduleFileExtensions: ['js', 'json', 'jsx', 'node'],
testMatch: [
"<rootDir>/__tests__/cli/src/**/*.(spec|test).[jt]s?(x)"
]
],
preset: "jest-puppeteer"
};

3
config/core.jest.config.js

@ -7,5 +7,6 @@ module.exports = {
moduleFileExtensions: ['js', 'json', 'jsx', 'node'],
testMatch: [
"<rootDir>/__tests__/core/src/**/*.(spec|test).[jt]s?(x)"
]
],
preset: "jest-puppeteer"
};

3
config/editor.jest.config.js

@ -7,5 +7,6 @@ module.exports = {
moduleFileExtensions: ['js', 'json', 'jsx', 'node'],
testMatch: [
"<rootDir>/__tests__/json-schema-editor/src/**/*.(spec|test).[jt]s?(x)"
]
],
preset: "jest-puppeteer"
};

3
config/plugin.jest.config.js

@ -7,5 +7,6 @@ module.exports = {
moduleFileExtensions: ['js', 'json', 'jsx', 'node'],
testMatch: [
"<rootDir>/__tests__/plugin-store/src/**/*.(spec|test).[jt]s?(x)"
]
],
preset: "jest-puppeteer"
};

15
package-lock.json

@ -6936,10 +6936,9 @@
"dev": true
},
"eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"dev": true
"version": "4.0.7",
"resolved": "https://registry.npm.taobao.org/eventemitter3/download/eventemitter3-4.0.7.tgz?cache=0&sync_timestamp=1598517809015&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feventemitter3%2Fdownload%2Feventemitter3-4.0.7.tgz",
"integrity": "sha1-Lem2j2Uo1WRO9cWVJqG0oHMGFp8="
},
"events": {
"version": "3.1.0",
@ -10172,6 +10171,14 @@
"dev": true,
"requires": {
"eventemitter3": "^3.1.0"
},
"dependencies": {
"eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npm.taobao.org/eventemitter3/download/eventemitter3-3.1.2.tgz?cache=0&sync_timestamp=1598517809015&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feventemitter3%2Fdownload%2Feventemitter3-3.1.2.tgz",
"integrity": "sha1-LT1I+cNGaY/Og6hdfWZOmFNd9uc=",
"dev": true
}
}
},
"p-reduce": {

12
package.json

@ -2,9 +2,7 @@
"name": "root",
"private": true,
"scripts": {
"lint-eslint": "eslint --cache --ext .js,.jsx,.ts,.tsx ./packages/**/src",
"check-types": "tsc --noEmit",
"lint": "npm run lint-eslint & npm run check-types",
"lint": "eslint --cache --fix --ext .ts,tsx,js,jsx ./packages/**/src > ./.eslint-error.log; exit 0",
"test": "jest --coverage",
"e2e": "cypress open",
"doc": "dumi dev"
@ -32,30 +30,34 @@
"@rollup/plugin-strip": "^1.3.2",
"@rollup/plugin-url": "^4.0.2",
"@svgr/rollup": "^5.3.1",
"@types/jest": "^26.0.16",
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"cypress": "^6.0.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"eslint": "^6.8.0",
"eslint-config-airbnb": "^18.1.0",
"eslint-config-prettier": "^6.10.1",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^3.0.0",
"eslint-plugin-unicorn": "^18.0.1",
"eslint-plugin-standard": "^5.0.0",
"jest": "^26.6.3",
"jest-environment-jsdom-fourteen": "^1.0.1",
"jest-puppeteer": "^4.4.0",
"lerna": "^3.20.2",
"prettier": "^2.0.4",
"puppeteer": "^5.5.0",
"react-app-polyfill": "^2.0.0",
"rollup": "^2.6.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-size-snapshot": "^0.11.0",
"snazzy": "^9.0.0",
"standard": "^16.0.3",
"ts-jest": "^26.4.4",
"typescript": "^3.8.3"
},
"dependencies": {

1
packages/cli/package.json

@ -23,6 +23,7 @@
"body-parser": "^1.19.0",
"commander": "^6.0.0",
"cors": "^2.8.5",
"eventemitter3": "^4.0.7",
"express": "^4.17.1",
"fs-extra": "^9.0.1"
}

1
packages/cli/src/cmd/base/index.js

@ -1,5 +1,4 @@
class Base {
constructor({ config }) {
this._config = config;
return this;

12
packages/cli/src/cmd/dev/addPlugins.js

@ -1,22 +1,18 @@
const path = require('path');
const fs = require('fs-extra');
const INSERT_IMPORT_PLUGINS_COMMENT = '\/\/ import plugins here';
const INSERT_USE_PLUGINS_COMMENT = '\/\/ use plugins here';
const INSERT_IMPORT_PLUGINS_COMMENT = '// import plugins here';
const INSERT_USE_PLUGINS_COMMENT = '// use plugins here';
const setup = async (plugins = [], logicBasePath) => {
const entryFilePath = path.join(logicBasePath, 'index.js');
const codes = await fs.readFile(entryFilePath, 'utf8');
const modifiedContent = codes
.replace(new RegExp(INSERT_IMPORT_PLUGINS_COMMENT), () => {
return plugins
.map((plugin, index) => `import plugin${index} from '${plugin}';`)
.join('\n');
return plugins.map((plugin, index) => `import plugin${index} from '${plugin}';`).join('\n');
})
.replace(new RegExp(INSERT_USE_PLUGINS_COMMENT), () => {
return plugins
.map((_, index) => `logic.use(plugin${index});`)
.join('\n');
return plugins.map((_, index) => `logic.use(plugin${index});`).join('\n');
});
await fs.outputFile(entryFilePath, modifiedContent);
};

9
packages/cli/src/cmd/dev/extractCodes.js

@ -12,7 +12,7 @@ const writeEntryFile = async (basePath, fileIds) => {
const fileContent = [
imports.join('\n'),
`const nodeFns = {\n ${funcMaps.join(',\n ')}\n};`,
`export default nodeFns;`
'export default nodeFns;',
].join('\n');
const entryFilePath = path.join(basePath, 'index.js');
await fs.outputFile(entryFilePath, fileContent, { encoding: 'utf8', flag: 'w' });
@ -21,8 +21,11 @@ const writeEntryFile = async (basePath, fileIds) => {
const writeNodeCodes = async (basePath, dsl) => {
const fileIds = [];
const { cells = [] } = dsl;
const nodes = cells.filter(cell => cell.shape !== 'edge');
for(const {id, data: {code}} of nodes) {
const nodes = cells.filter((cell) => cell.shape !== 'edge');
for (const {
id,
data: { code },
} of nodes) {
fileIds.push(id);
const filePath = path.join(basePath, id + '.js');
await fs.outputFile(filePath, code, { encoding: 'utf8', flag: 'w' });

6
packages/cli/src/cmd/dev/index.js

@ -13,9 +13,7 @@ const CACHE_PATH = path.join(process.cwd(), './.cache');
const CACHE_DSL_FILE = path.join(CACHE_PATH, 'imove.dsl.json');
class Dev extends Base {
save = async (req, res) => {
async save(req, res) {
const { outputPath, plugins = [] } = this.config;
// check outputPath whether exsited
@ -44,7 +42,7 @@ class Dev extends Base {
}
}
connect = async (req, res) => {
async connect(req, res) {
const { projectName } = this.config;
const dsl = await fs.readJson(CACHE_DSL_FILE).catch(noop);
res.status(200).json({ projectName, dsl }).end();

18
packages/cli/src/cmd/dev/mergePkg.js

@ -2,23 +2,25 @@ const path = require('path');
const fs = require('fs-extra');
const builtinDependencies = {
"eventemitter3": "^4.0.7"
eventemitter3: '^4.0.7',
};
const extractDep = (dsl) => {
const mergedDependencies = {};
const { cells = [] } = dsl;
cells.filter(cell => cell.shape !== 'edge').forEach(cell => {
cells
.filter((cell) => cell.shape !== 'edge')
.forEach((cell) => {
const { dependencies } = cell.data || {};
try {
const json = JSON.parse(dependencies);
Object.keys(json).forEach(key => mergedDependencies[key] = json[key]);
} catch(err) {
console.log('extract dependencies failed, the error is:', err.message);
Object.keys(json).forEach((key) => (mergedDependencies[key] = json[key]));
} catch (error) {
console.log('extract dependencies failed, the error is:', error.message);
}
});
return mergedDependencies;
}
};
const setup = async (dsl, projectRootPath) => {
const pkgPath = path.join(projectRootPath, './package.json');
@ -28,10 +30,10 @@ const setup = async (dsl, projectRootPath) => {
if (!pkgJson.dependencies) {
pkgJson.dependencies = dslDependencies;
} else {
Object.keys(dslDependencies).forEach(key => {
Object.keys(dslDependencies).forEach((key) => {
pkgJson.dependencies[key] = dslDependencies[key];
});
Object.keys(builtinDependencies).forEach(key => {
Object.keys(builtinDependencies).forEach((key) => {
pkgJson.dependencies[key] = builtinDependencies[key];
});
}

6
packages/cli/src/cmd/dev/simplifyDSL.js

@ -3,20 +3,20 @@ const fs = require('fs-extra');
const extractObj = (obj = {}, keys = []) => {
const ret = {};
keys.forEach(key => ret[key] = obj[key]);
keys.forEach((key) => (ret[key] = obj[key]));
return ret;
};
const simplify = (dsl) => {
const { cells = [] } = dsl;
return {
cells: cells.map(cell => {
cells: cells.map((cell) => {
if (cell.shape === 'edge') {
return extractObj(cell, ['id', 'shape', 'source', 'target']);
} else {
return extractObj(cell, ['id', 'shape', 'data']);
}
})
}),
};
};

3
packages/cli/src/cmd/dev/template/context.js

@ -1,5 +1,4 @@
export default class Context {
constructor(opts) {
this._init(opts);
}
@ -38,7 +37,7 @@ export default class Context {
}
setContext(data = {}) {
Object.keys(data).forEach(key => {
Object.keys(data).forEach((key) => {
this.context[key] = data[key];
});
}

38
packages/cli/src/cmd/dev/template/logic.js

@ -2,17 +2,14 @@ import nodeFns from './nodeFns';
import Context from './context';
import EventEmitter from 'eventemitter3';
const LIFECYCLE = [
'ctxCreated'
];
const LIFECYCLE = new Set(['ctxCreated']);
const SHAPES = {
START: 'imove-start',
BRANCH: 'imove-branch',
BEHAVIOR: 'imove-behavior'
}
BEHAVIOR: 'imove-behavior',
};
export default class Logic extends EventEmitter {
constructor(opts = {}) {
super();
this.dsl = opts.dsl;
@ -24,23 +21,23 @@ export default class Logic extends EventEmitter{
}
get nodes() {
return this.cells.filter(cell => cell.shape !== 'edge');
return this.cells.filter((cell) => cell.shape !== 'edge');
}
get startNodes() {
return this.cells.filter(cell => cell.shape === SHAPES.START);
return this.cells.filter((cell) => cell.shape === SHAPES.START);
}
get edges() {
return this.cells.filter(cell => cell.shape === 'edge');
return this.cells.filter((cell) => cell.shape === 'edge');
}
_runLifecycleEvent(eventName, ctx) {
if(LIFECYCLE.indexOf(eventName) === -1) {
if (!LIFECYCLE.has(eventName)) {
return console.warn(`Lifecycle ${eventName} is not supported!`);
}
if (this.lifeCycleEvents[eventName]) {
this.lifeCycleEvents[eventName].forEach(fn => fn(ctx));
this.lifeCycleEvents[eventName].forEach((fn) => fn(ctx));
}
}
@ -69,7 +66,10 @@ export default class Logic extends EventEmitter{
const { ports } = curNode.data;
for (const key in ports) {
const { condition } = ports[key];
const ret = new Function('ctx', 'return ' + condition)(ctx);
const ret = ((ctx) => {
return condition;
})(ctx);
// const ret = new Function('ctx', 'return ' + condition)(ctx);
if (ret === Boolean(curRet)) {
matchedPort = key;
break;
@ -79,7 +79,7 @@ export default class Logic extends EventEmitter{
}
if (isMatched) {
// NOTE: not each edge both has source and target
const nextNode = this.nodes.find(item => item.id === edge.target.cell);
const nextNode = this.nodes.find((item) => item.id === edge.target.cell);
nextNode && nodes.push(nextNode);
}
}
@ -96,11 +96,11 @@ export default class Logic extends EventEmitter{
console.error('imove plugin must return an object.');
return;
}
for (let eventName in plugin) {
if(!plugin.hasOwnProperty(eventName)) {
for (const eventName in plugin) {
if (!Object.prototype.hasOwnProperty.call(plugin, eventName)) {
continue;
}
if(LIFECYCLE.indexOf(eventName) === -1) {
if (!LIFECYCLE.has(eventName)) {
console.warn(`Lifecycle ${eventName} is not supported in imove.`);
continue;
}
@ -120,16 +120,16 @@ export default class Logic extends EventEmitter{
}
const nextNodes = this._getNextNodes(ctx, curNode, curRet);
if (nextNodes.length > 0) {
nextNodes.forEach(async node => {
nextNodes.forEach(async (node) => {
await this._execNode(ctx, node, lastRet);
});
}
}
async invoke(trigger, data) {
let curNode = this._getStartNode(trigger);
const curNode = this._getStartNode(trigger);
if (!curNode) {
return Promise.reject(`Invoke failed! No logic-start named ${trigger} found!`);
return Promise.reject(new Error(`Invoke failed! No logic-start named ${trigger} found!`));
}
const ctx = this._createCtx({ payload: data });
await this._execNode(ctx, curNode);

2
packages/cli/src/cmd/index.js

@ -3,5 +3,5 @@ const Init = require('./init');
module.exports = {
dev: Dev,
init: Init
init: Init,
};

1
packages/cli/src/cmd/init/index.js

@ -6,7 +6,6 @@ const CONFIG_TPL_PATH = path.join(__dirname, './template/imove.config.js.tpl');
const OUTPUT_FILE_PATH = path.join(process.cwd(), 'imove.config.js');
class Init extends Base {
getProjectName() {
const pkgPath = path.join(this.projectPath, 'package.json');
const pkgJson = fs.readJSONSync(pkgPath);

4
packages/cli/src/utils/getConfig.js

@ -4,12 +4,12 @@ const fs = require('fs');
const CONFIG_FILE_NAME = 'imove.config.js';
const CONFIG_FILE_PATH = path.join(process.cwd(), CONFIG_FILE_NAME);
const DEFAULT_CONFIG = {
outputPath: path.join(process.cwd(), './src/logic/')
outputPath: path.join(process.cwd(), './src/logic/'),
};
const mergeConfig = (config, DEFAULT_CONFIG) => {
// TODO: merge config
return config;
}
};
const getConfig = () => {
const isConfigFileExisted = fs.existsSync(CONFIG_FILE_PATH);

8
packages/cli/src/utils/server/index.js

@ -1,5 +1,3 @@
const http = require('http');
const cors = require('cors');
const express = require('express');
const bodyParser = require('body-parser');
@ -8,8 +6,8 @@ const createServer = (port = 3500) => {
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
app.listen(port, () => {
@ -19,5 +17,5 @@ const createServer = (port = 3500) => {
};
module.exports = {
createServer
createServer,
};

32
packages/core/src/api/index.ts

@ -9,7 +9,7 @@ export interface ILocalConfig {
export enum ActionType {
create = 'create',
update = 'update',
remove = 'remove'
remove = 'remove',
}
export interface IModifyGraphAction {
@ -44,54 +44,54 @@ const request = (function() {
method,
headers: {
'Content-Type': 'application/json;charset=utf-8',
...headers
...headers,
},
data: params,
timeout: 3000
timeout: 3000,
});
};
})();
export const localConfig: ILocalConfig = {
ip: '127.0.0.1',
port: '3500'
}
port: '3500',
};
export const updateLocalConfig = (config: ILocalConfig) => {
localConfig.ip = config.ip || localConfig.ip;
localConfig.port = config.port || localConfig.port;
}
};
export const localConnect = () => {
return fetch(`http://${localConfig.ip}:${localConfig.port}/api/connect`, {
method: 'GET',
headers: {'content-type': 'application/json'}
headers: { 'content-type': 'application/json' },
});
}
};
export const localSave = (data: any) => {
fetch(`http://${localConfig.ip}:${localConfig.port}/api/save`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(data)
body: JSON.stringify(data),
});
}
};
export const queryGraph = (projectId: string) => {
return request({
url: '/api/queryGraph',
params: {
projectId
}
projectId,
},
});
}
};
export const modifyGraph = (projectId: string, actions: IModifyGraphAction[]) => {
return request({
url: '/api/modifyGraph',
params: {
projectId,
actions
}
actions,
},
});
}
};

30
packages/core/src/common/baseCell/behavior.ts

@ -9,11 +9,11 @@ const schema = {
attrs: {
body: {
fill: '#AACCF7',
stroke: '#5E9CEE'
stroke: '#5E9CEE',
},
label: {
fill: '#333'
}
fill: '#333',
},
},
ports: {
groups: {
@ -25,7 +25,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -37,7 +37,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -49,7 +49,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -61,7 +61,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -69,29 +69,29 @@ const schema = {
items: [
{
id: 'top',
group: 'top'
group: 'top',
},
{
id: 'right',
group: 'right'
group: 'right',
},
{
id: 'bottom',
group: 'bottom'
group: 'bottom',
},
{
id: 'left',
group: 'left'
}
]
group: 'left',
},
],
},
data: {
label: '处理',
configSchema: '{\n \n}',
configData: {},
dependencies: '{\n \n}',
code: 'export default async function(ctx) {\n \n}'
}
code: 'export default async function(ctx) {\n \n}',
},
};
export default schema;

52
packages/core/src/common/baseCell/branch.ts

@ -10,7 +10,7 @@ const schema = {
strokeWidth: 2,
stroke: '#333',
fill: '#FFFC7C',
refPoints: '0,10 10,0 20,10 10,20'
refPoints: '0,10 10,0 20,10 10,20',
},
label: {
refX: 0.5,
@ -19,8 +19,8 @@ const schema = {
fill: '#333',
fontSize: 14,
textAnchor: 'middle',
textVerticalAnchor: 'middle'
}
textVerticalAnchor: 'middle',
},
},
ports: {
groups: {
@ -32,7 +32,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -45,12 +45,12 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
label: {
position: 'right'
}
position: 'right',
},
},
bottom: {
zIndex: 999999999,
@ -61,12 +61,12 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
label: {
position: 'bottom'
}
position: 'bottom',
},
},
left: {
position: 'left',
@ -76,7 +76,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -84,31 +84,31 @@ const schema = {
items: [
{
id: 'top',
group: 'top'
group: 'top',
},
{
id: 'right',
group: 'right',
attrs: {
text: {
text: '是'
}
}
text: '是',
},
},
},
{
id: 'bottom',
group: 'bottom',
attrs: {
text: {
text: '否'
}
}
text: '否',
},
},
},
{
id: 'left',
group: 'left'
}
]
group: 'left',
},
],
},
data: {
label: '判断',
@ -117,14 +117,14 @@ const schema = {
dependencies: '{\n \n}',
ports: {
right: {
condition: 'true'
condition: 'true',
},
bottom: {
condition: 'false'
}
condition: 'false',
},
},
code: 'export default async function(ctx) {\n return true;\n}',
},
code: 'export default async function(ctx) {\n return true;\n}'
}
};
export default schema;

2
packages/core/src/common/baseCell/index.ts

@ -5,7 +5,7 @@ import behavior from './behavior';
const cellSchemaMap: { [key: string]: any } = {
'imove-start': start,
'imove-branch': branch,
'imove-behavior': behavior
'imove-behavior': behavior,
};
export default cellSchemaMap;

30
packages/core/src/common/baseCell/start.ts

@ -10,11 +10,11 @@ const schema = {
body: {
fill: '#333',
strokeWidth: 1,
stroke: '#333'
stroke: '#333',
},
label: {
fill: '#FFF'
}
fill: '#FFF',
},
},
ports: {
groups: {
@ -26,7 +26,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -38,7 +38,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -50,7 +50,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -62,7 +62,7 @@ const schema = {
magnet: true,
stroke: '#666',
strokeWidth: 1,
fill: '#fff'
fill: '#fff',
},
},
},
@ -70,21 +70,21 @@ const schema = {
items: [
{
id: 'top',
group: 'top'
group: 'top',
},
{
id: 'right',
group: 'right'
group: 'right',
},
{
id: 'bottom',
group: 'bottom'
group: 'bottom',
},
{
id: 'left',
group: 'left'
}
]
group: 'left',
},
],
},
data: {
label: '开始',
@ -92,8 +92,8 @@ const schema = {
configData: {},
trigger: 'start',
dependencies: '{\n \n}',
code: 'export default async function(ctx) {\n \n}'
}
code: 'export default async function(ctx) {\n \n}',
},
};
export default schema;

8
packages/core/src/common/previewCell/behavior.ts

@ -10,12 +10,12 @@ const schema = {
attrs: {
body: {
fill: '#AACCF7',
stroke: '#5E9CEE'
stroke: '#5E9CEE',
},
label: {
fill: '#333'
}
}
fill: '#333',
},
},
};
export default schema;

8
packages/core/src/common/previewCell/branch.ts

@ -12,7 +12,7 @@ const schema = {
strokeWidth: 2,
stroke: '#333',
fill: '#FFFC7C',
refPoints: '0,10 10,0 20,10 10,20'
refPoints: '0,10 10,0 20,10 10,20',
},
label: {
refX: 0.5,
@ -21,9 +21,9 @@ const schema = {
fill: '#333',
fontSize: 14,
textAnchor: 'middle',
textVerticalAnchor: 'middle'
}
}
textVerticalAnchor: 'middle',
},
},
};
export default schema;

2
packages/core/src/common/previewCell/index.ts

@ -5,7 +5,7 @@ import behavior from './behavior';
const cellSchemaMap: { [key: string]: any } = {
'imove-start-preview': start,
'imove-branch-preview': branch,
'imove-behavior-preview': behavior
'imove-behavior-preview': behavior,
};
export default cellSchemaMap;

6
packages/core/src/common/previewCell/start.ts

@ -11,11 +11,11 @@ const schema = {
body: {
strokeWidth: 0,
stroke: '#333',
fill: '#333'
fill: '#333',
},
label: {
fill: '#FFF'
}
fill: '#FFF',
},
},
};

41
packages/core/src/common/shortcuts.ts

@ -10,41 +10,41 @@ interface Shortcut {
const shortcuts: { [key: string]: Shortcut } = {
save: {
keys: `meta + s`,
keys: 'meta + s',
handler(flowChart: Graph) {
localSave({ dsl: flowChart.toJSON() });
return false;
}
},
},
undo: {
keys: `meta + z`,
keys: 'meta + z',
handler(flowChart: Graph) {
flowChart.undo();
return false;
}
},
},
redo: {
keys: `meta + shift + z`,
keys: 'meta + shift + z',
handler(flowChart: Graph) {
flowChart.redo();
return false;
}
},
},
zoomIn: {
keys: `meta + shift + \+`,
keys: 'meta + shift + +',
handler(flowChart: Graph) {
const nextZoom = (flowChart.zoom() + ZOOM_STEP).toPrecision(2);
flowChart.zoomTo(Number(nextZoom), { maxScale: MAX_ZOOM });
return false;
}
},
},
zoomOut: {
keys: `meta + shift + \-`,
keys: 'meta + shift + -',
handler(flowChart: Graph) {
const nextZoom = (flowChart.zoom() - ZOOM_STEP).toPrecision(2);
flowChart.zoomTo(Number(nextZoom), { minScale: MIN_ZOOM });
return false;
}
},
},
copy: {
keys: 'meta + c',
@ -54,7 +54,7 @@ const shortcuts: {[key: string]: Shortcut} = {
flowChart.copy(cells);
}
return false;
}
},
},
paste: {
keys: 'meta + v',
@ -65,7 +65,7 @@ const shortcuts: {[key: string]: Shortcut} = {
flowChart.select(cells);
}
return false;
}
},
},
delete: {
keys: ['backspace', 'del'],
@ -73,7 +73,7 @@ const shortcuts: {[key: string]: Shortcut} = {
const toDelCells = flowChart.getSelectedCells();
const onEdgeDel = (edge: Edge) => {
const srcNode = edge.getSourceNode() as Node;
const isSrcNodeInDelCells = !!toDelCells.find(c => c === srcNode);
const isSrcNodeInDelCells = !!toDelCells.find((c) => c === srcNode);
if (srcNode && srcNode.shape === 'imove-branch' && !isSrcNodeInDelCells) {
const portId = edge.getSourcePortId();
if (portId === 'right' || portId === 'bottom') {
@ -92,14 +92,14 @@ const shortcuts: {[key: string]: Shortcut} = {
flowChart.removeCells(flowChart.getSelectedCells());
flowChart.trigger('toolBar:forceUpdate');
return false;
}
},
},
selectAll: {
keys: 'meta + a',
handler(flowChart: Graph) {
flowChart.select(flowChart.getCells());
return false;
}
},
},
bold: {
keys: 'meta + b',
@ -113,7 +113,7 @@ const shortcuts: {[key: string]: Shortcut} = {
flowChart.trigger('toolBar:forceUpdate');
}
return false;
}
},
},
italic: {
keys: 'meta + i',
@ -127,22 +127,23 @@ const shortcuts: {[key: string]: Shortcut} = {
flowChart.trigger('toolBar:forceUpdate');
}
return false;
}
},
},
underline: {
keys: 'meta + u',
handler(flowChart: Graph) {
const cells = flowChart.getSelectedCells();
if (cells.length > 0) {
const isAlreadyUnderline = safeGet(cells, '0.attrs.label.textDecoration', 'none') === 'underline';
const isAlreadyUnderline =
safeGet(cells, '0.attrs.label.textDecoration', 'none') === 'underline';
cells.forEach((cell) => {
cell.setAttrs({ label: { textDecoration: isAlreadyUnderline ? 'none' : 'underline' } });
});
flowChart.trigger('toolBar:forceUpdate');
}
return false;
}
}
},
},
};
export default shortcuts;

9
packages/core/src/components/colorPicker/index.tsx

@ -8,7 +8,6 @@ interface IProps {
}
const ColorPicker: React.FC<IProps> = (props) => {
const { color, onChangeComplete: changeCb } = props;
const [curColor, setCurColor] = useState(color);
@ -19,13 +18,7 @@ const ColorPicker: React.FC<IProps> = (props) => {
const onChange = (color: ColorResult): void => setCurColor(color.hex);
const onChangeComplete = (color: ColorResult): void => changeCb(color.hex);
return (
<SketchPicker
color={curColor}
onChange={onChange}
onChangeComplete={onChangeComplete}
/>
);
return <SketchPicker color={curColor} onChange={onChange} onChangeComplete={onChangeComplete} />;
};
export default ColorPicker;

3
packages/core/src/components/miniMapSimpleNode/index.tsx

@ -1,7 +1,6 @@
import { NodeView } from '@antv/x6';
class MiniMapSimpleNode extends NodeView {
protected renderMarkup() {
return this.renderJSONMarkup({
tagName: 'rect',
@ -19,7 +18,7 @@ class MiniMapSimpleNode extends NodeView {
refWidth: '100%',
refHeight: '100%',
fill: '#D9D9D9',
}
},
});
}
}

2
packages/core/src/components/xIcon/index.tsx

@ -7,7 +7,7 @@ interface IconFontProps {
}
const XIcon: React.SFC<IconFontProps> = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_2024452_02tul6sizoy9.js'
scriptUrl: '//at.alicdn.com/t/font_2024452_02tul6sizoy9.js',
});
export default XIcon;

2
packages/core/src/index.tsx

@ -15,7 +15,7 @@ interface IProps {
onSave: (data: { nodes: any; edges: any }) => void;
}
const Core: React.FC<IProps> = props => {
const Core: React.FC<IProps> = (props) => {
const { onSave } = props;
const [flowChart, setFlowChart] = useState<Graph>();
const onFlowChartReady = (flowChart: Graph): void => setFlowChart(flowChart);

37
packages/core/src/mods/flowChart/createFlowChart.ts

@ -7,11 +7,12 @@ import {registerServerStorage} from './registerServerStorage';
import MiniMapSimpleNode from '../../components/miniMapSimpleNode';
// X6 register base/preview cell shape
[baseCellSchemaMap, previewCellSchemaMap]
.forEach(schemas => Object.values(schemas).forEach(schema => {
[baseCellSchemaMap, previewCellSchemaMap].forEach((schemas) =>
Object.values(schemas).forEach((schema) => {
const { base, ...rest } = schema;
base.define(rest);
}));
})
);
const registerEvents = (flowChart: Graph): void => {
flowChart.on('node:added', (args) => {
@ -36,7 +37,7 @@ const registerEvents = (flowChart: Graph): void => {
};
const registerShortcuts = (flowChart: Graph): void => {
Object.values(shortcuts).forEach(shortcut => {
Object.values(shortcuts).forEach((shortcut) => {
const { keys, handler } = shortcut;
flowChart.bindKey(keys, () => handler(flowChart));
});
@ -50,7 +51,7 @@ const createFlowChart = (container: HTMLDivElement, miniMapContainer: HTMLDivEle
// https://x6.antv.vision/zh/docs/tutorial/basic/clipboard
clipboard: {
enabled: true,
useLocalStorage: true
useLocalStorage: true,
},
// https://x6.antv.vision/zh/docs/tutorial/intermediate/connector
connecting: {
@ -60,7 +61,7 @@ const createFlowChart = (container: HTMLDivElement, miniMapContainer: HTMLDivEle
anchor: 'center',
connectionPoint: 'anchor',
router: {
name: 'manhattan'
name: 'manhattan',
},
validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
if (!sourceMagnet) {
@ -70,15 +71,15 @@ const createFlowChart = (container: HTMLDivElement, miniMapContainer: HTMLDivEle
} else {
return sourceView !== targetView;
}
}
},
},
// https://x6.antv.vision/zh/docs/tutorial/basic/background
background: {
color: '#f8f9fa'
color: '#f8f9fa',
},
// https://x6.antv.vision/zh/docs/tutorial/basic/grid
grid: {
visible: true
visible: true,
},
// https://x6.antv.vision/zh/docs/tutorial/basic/selection
selecting: {
@ -86,25 +87,25 @@ const createFlowChart = (container: HTMLDivElement, miniMapContainer: HTMLDivEle
multiple: true,
rubberband: true,
movable: true,
showNodeSelectionBox: true
showNodeSelectionBox: true,
},
// https://x6.antv.vision/zh/docs/tutorial/basic/snapline
snapline: {
enabled: true,
clean: 100
clean: 100,
},
// https://x6.antv.vision/zh/docs/tutorial/basic/keyboard
keyboard: {
enabled: true,
global: false
global: false,
},
// https://x6.antv.vision/zh/docs/tutorial/basic/history
history: {
enabled: true
enabled: true,
},
// https://x6.antv.vision/zh/docs/tutorial/basic/minimap
minimap: {
width: 150 * container.offsetWidth / container.offsetHeight,
width: (150 * container.offsetWidth) / container.offsetHeight,
height: 150,
minScale: MIN_ZOOM,
maxScale: MAX_ZOOM,
@ -122,18 +123,18 @@ const createFlowChart = (container: HTMLDivElement, miniMapContainer: HTMLDivEle
if (cell.isEdge()) {
return null;
}
}
}
},
},
},
// https://x6.antv.vision/zh/docs/tutorial/basic/scroller
scroller: {
enabled: true
enabled: true,
},
mousewheel: {
enabled: true,
minScale: MIN_ZOOM,
maxScale: MAX_ZOOM,
modifiers: ['ctrl', 'meta']
modifiers: ['ctrl', 'meta'],
},
});
registerEvents(flowChart);

11
packages/core/src/mods/flowChart/index.tsx

@ -12,8 +12,7 @@ interface IProps {
onReady: (graph: Graph) => void;
}
const FlowChart: React.FC<IProps> = props => {
const FlowChart: React.FC<IProps> = (props) => {
const { onReady } = props;
const graphRef = useRef<HTMLDivElement>(null);
const miniMapRef = useRef<HTMLDivElement>(null);
@ -28,11 +27,13 @@ const FlowChart: React.FC<IProps> = props => {
const fetchData = (graph: Graph) => {
const { projectId } = parseQuery();
queryGraph(projectId as string).then(res => {
queryGraph(projectId as string)
.then((res) => {
const { data: dsl } = res;
graph.fromJSON(dsl);
}).catch(err => {
console.log('query graph data failed, the error is:', err);
})
.catch((error) => {
console.log('query graph data failed, the error is:', error);
});
};

28
packages/core/src/mods/flowChart/registerServerStorage.ts

@ -15,15 +15,16 @@ const validate = (type: string, data: any) => {
} else {
return false;
}
}
};
const enqueue = (type: string, actionType: ActionType, data: any) => {
if (!validate(type, data)) {
return;
}
const foundIndex = memQueue.findIndex(item => item.type === type && item.actionType === actionType);
const foundIndex = memQueue.findIndex(
(item) => item.type === type && item.actionType === actionType
);
if (foundIndex > -1) {
const deleted = memQueue.splice(foundIndex, 1)[0];
data = merge(deleted, data);
@ -39,11 +40,13 @@ const save = (flowChart: Graph, type: string, actionType: ActionType, data: any)
const pushedActions = memQueue.slice(0);
if (pushedActions.length > 0) {
flowChart.trigger('graph:change:modify');
modifyGraph(projectId, memQueue).then(res => {
modifyGraph(projectId, memQueue)
.then((res) => {
memQueue.splice(0, pushedActions.length);
flowChart.trigger('graph:modified', { success: true });
}).catch(err => {
flowChart.trigger('graph:modified', {success: true, error: err});
})
.catch((error) => {
flowChart.trigger('graph:modified', { success: true, error: error });
});
}
}, 100);
@ -60,23 +63,20 @@ const nodeActionEventMap: ActionEventMap = {
'node:change:ports',
'node:change:attrs',
'node:change:data',
'node:change:zIndex'
]
'node:change:zIndex',
],
};
const edgeActionEventMap: ActionEventMap = {
[ActionType.create]: ['edge:connected'],
[ActionType.remove]: ['edge:removed'],
[ActionType.update]: [
'edge:moved',
]
[ActionType.update]: ['edge:moved'],
};
export const registerServerStorage = (flowChart: Graph) => {
Object.keys(nodeActionEventMap).forEach((actionType) => {
const events = nodeActionEventMap[actionType];
events.forEach(event => {
events.forEach((event) => {
flowChart.on(event, (args: any) => {
console.log('node event:', event, 'args:', args);
save(flowChart, 'node', actionType as ActionType, args.node.toJSON());
@ -86,7 +86,7 @@ export const registerServerStorage = (flowChart: Graph) => {
Object.keys(edgeActionEventMap).forEach((actionType) => {
const events = edgeActionEventMap[actionType];
events.forEach(event => {
events.forEach((event) => {
flowChart.on(event, (args: any) => {
console.log('edge event:', event, 'args:', args);
save(flowChart, 'edge', actionType as ActionType, args.edge.toJSON());

22
packages/core/src/mods/header/connectStatus/editModal.tsx

@ -10,13 +10,16 @@ import {FormInstance} from 'antd/lib/form';
import { ILocalConfig, localConfig, updateLocalConfig } from '../../../api';
const PORT_REGEX = /^\d{1,5}$/;
const IP_REGEX = /^(localhost)|(((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3})$/;
const IP_REGEX = /^(localhost)|(((2(5[0-5]|[0-4]\d))|[01]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[01]?\d{1,2})){3})$/;
const makeRules = (regex: RegExp, errTip: string) => {
return [
{ required: true, message: '不能为空!' },
{validator: (_: any, val: string) => regex.test(val) ? Promise.resolve() : Promise.reject(errTip)}
{
validator: (_: any, val: string) =>
regex.test(val) ? Promise.resolve() : Promise.reject(errTip),
},
];
}
};
interface IEditorModalProps {
visible: boolean;
@ -24,18 +27,21 @@ interface IEditorModalProps {
onCancel: () => void;
}
const EditModal: React.FC<IEditorModalProps> = props => {
const EditModal: React.FC<IEditorModalProps> = (props) => {
const { visible, onOk, onCancel } = props;
const formRef = useRef<FormInstance>(null);
// events
const onClickOk = (): void => {
formRef.current && formRef.current.validateFields().then((formValues) => {
formRef.current &&
formRef.current
.validateFields()
.then((formValues) => {
updateLocalConfig(formValues as ILocalConfig);
onOk();
}).catch(err => {
console.log(err.message);
})
.catch((error) => {
console.log(error.message);
});
};

27
packages/core/src/mods/header/connectStatus/index.tsx

@ -12,7 +12,7 @@ import {localConnect} from '../../../api';
enum Status {
connected = 'success',
disconnected = 'error'
disconnected = 'error',
}
interface IProps {
@ -22,7 +22,6 @@ interface IProps {
const PULSE_RATE = 10 * 1000; // try to connect to local servet per 10 seconds
const ConnectStatus: React.FC<IProps> = (props) => {
const { flowChart } = props;
const [visible, setVisible] = useState<boolean>(false);
const [projectName, setProjectName] = useState<string>('');
@ -37,28 +36,32 @@ const ConnectStatus: React.FC<IProps> = (props) => {
// network
const syncLocal = () => {
return localConnect().then(res => res.json()).then((data = {}) => {
return localConnect()
.then((res) => res.json())
.then((data = {}) => {
const { projectName } = data;
setStatus(Status.connected);
setProjectName(projectName);
return data;
}).catch((err) => {
})
.catch((error) => {
setStatus(Status.disconnected);
console.log('connect local failed, the error is:', err.message);
console.log('connect local failed, the error is:', error.message);
});
};
const confirmToSync = () => {
syncLocal().then(data => {
syncLocal().then((data) => {
const { dsl } = data || {};
dsl && Modal.confirm({
dsl &&
Modal.confirm({
title: '本地连接成功,是否将数据同步至当前项目?',
onOk() {
try {
flowChart.fromJSON(dsl);
} catch(err) {
} catch (error) {
message.error('同步失败!');
}
}
},
});
});
};
@ -85,11 +88,7 @@ const ConnectStatus: React.FC<IProps> = (props) => {
<Tag className={styles.tag} color={status} onClick={onOpenEditModal}>
{tagText}
</Tag>
<EditModal
visible={visible}
onOk={onOk}
onCancel={onCloseEditModal}
/>
<EditModal visible={visible} onOk={onOk} onCancel={onCloseEditModal} />
</div>
);
};

4
packages/core/src/mods/header/index.tsx

@ -9,7 +9,7 @@ interface IProps {
flowChart: Graph;
}
const Header: React.FC<IProps> = props => {
const Header: React.FC<IProps> = (props) => {
const { flowChart } = props;
return (
<div className={styles.container}>
@ -17,6 +17,6 @@ const Header: React.FC<IProps> = props => {
<ConnectStatus flowChart={flowChart} />
</div>
);
}
};
export default Header;

17
packages/core/src/mods/layout/index.tsx

@ -17,7 +17,6 @@ interface IProps {
}
const Layout: React.FC<IProps> = (props) => {
const { flowChart, Header, SideBar, ToolBar, SettingBar } = props;
let header, sideBar, toolBar, settingBar;
@ -30,22 +29,14 @@ const Layout: React.FC<IProps> = (props) => {
return (
<div className={styles.container}>
<div className={styles.header}>
{header}
</div>
<div className={styles.header}>{header}</div>
<div className={styles.body}>
<div className={styles.sideBar}>
{sideBar}
</div>
<div className={styles.sideBar}>{sideBar}</div>
<div className={styles.full}>
<div className={styles.toolBar}>
{toolBar}
</div>
<div className={styles.toolBar}>{toolBar}</div>
{props.children}
</div>
<div className={styles.settingBar}>
{settingBar}
</div>
<div className={styles.settingBar}>{settingBar}</div>
</div>
</div>
);

4
packages/core/src/mods/settingBar/components/checkbox/index.tsx

@ -15,10 +15,10 @@ interface IProps {
onValueChange: (val: boolean) => void;
}
const Checkbox: React.FC<IProps> = props => {
const Checkbox: React.FC<IProps> = (props) => {
const { name, title, value, disabled, onValueChange } = props;
const onChange = (evt: CheckboxChangeEvent): void => {
console.log(evt.target.checked)
console.log(evt.target.checked);
if (evt.target.checked !== value) {
onValueChange(evt.target.checked);
}

16
packages/core/src/mods/settingBar/components/code/index.tsx

@ -18,8 +18,7 @@ interface IProps {
onValueChange: (value: string) => void;
}
const Code: React.FC<IProps> = props => {
const Code: React.FC<IProps> = (props) => {
const { title, value, onValueChange } = props;
const [visible, setVisible] = useState<boolean>(false);
@ -38,11 +37,7 @@ const Code: React.FC<IProps> = props => {
return (
<div className={styles.container}>
<p className={styles.titleText}>{title}</p>
<Button
block={true}
className={styles.btn}
onClick={onClickEdit}
>
<Button block={true} className={styles.btn} onClick={onClickEdit}>
</Button>
<EditModal
@ -66,15 +61,14 @@ interface IEditorModalProps {
const CODE_EDITOR_STYLE = {
width: '100%',
height: 600
height: 600,
};
const CODE_EDITOR_OPTIONS = {
fontSize: 14,
useWorker: false
useWorker: false,
};
const EditModal: React.FC<IEditorModalProps> = props => {
const EditModal: React.FC<IEditorModalProps> = (props) => {
const { visible, title, value, onOk, onCancel } = props;
const [code, setCode] = useState<string>(value);

2
packages/core/src/mods/settingBar/components/input/index.tsx

@ -14,7 +14,7 @@ interface IProps {
onValueChange: (val: string) => void;
}
const Input: React.FC<IProps> = props => {
const Input: React.FC<IProps> = (props) => {
const { name, title, value, disabled, onValueChange } = props;
const onChange = (evt: React.ChangeEvent<HTMLInputElement>): void => {
if (evt.target.value !== value) {

20
packages/core/src/mods/settingBar/components/json/index.tsx

@ -21,8 +21,7 @@ interface IJsonProps {
onValueChange: (value: string) => void;
}
const Json: React.FC<IJsonProps> = props => {
const Json: React.FC<IJsonProps> = (props) => {
const { title, value, onValueChange } = props;
const [visible, setVisible] = useState<boolean>(false);
@ -49,11 +48,7 @@ const Json: React.FC<IJsonProps> = props => {
displayObjectSize={false}
src={safeParse(value)}
/>
<Button
block={true}
className={styles.btn}
onClick={onClickEdit}
>
<Button block={true} className={styles.btn} onClick={onClickEdit}>
</Button>
<EditModal
@ -77,14 +72,13 @@ interface IEditorModalProps {
const CODE_EDITOR_STYLE = {
width: '100%',
height: 400
height: 400,
};
const CODE_EDITOR_OPTIONS = {
useWorker: false
useWorker: false,
};
const EditModal: React.FC<IEditorModalProps> = props => {
const EditModal: React.FC<IEditorModalProps> = (props) => {
const { visible, title, value, onOk, onCancel } = props;
const [json, setJson] = useState<string>('');
@ -104,9 +98,9 @@ const EditModal: React.FC<IEditorModalProps> = props => {
try {
JSON.parse(json);
onOk(json);
} catch(err) {
} catch (error) {
message.error('内容必须是合法json');
console.log('save failed, the error is:', err.message);
console.log('save failed, the error is:', error.message);
}
};
const onChangeJson = (newJson: string): void => {

13
packages/core/src/mods/settingBar/index.tsx

@ -15,10 +15,9 @@ interface IProps {
flowChart: Graph;
}
const SettingBar: React.FC<IProps> = props => {
const SettingBar: React.FC<IProps> = (props) => {
const { flowChart } = props;
const forceUpdate = useReducer(n => n + 1, 0)[1];
const forceUpdate = useReducer((n) => n + 1, 0)[1];
useEffect(() => {
flowChart.on('settingBar:forceUpdate', forceUpdate);
@ -27,11 +26,15 @@ const SettingBar: React.FC<IProps> = props => {
};
}, []);
const nodes = flowChart.getSelectedCells().filter(v => v.shape !== 'edge');
const nodes = flowChart.getSelectedCells().filter((v) => v.shape !== 'edge');
if (nodes.length === 1) {
return (
<div className={styles.container}>
<Tabs tabBarGutter={0} defaultActiveKey={'basic'} tabBarStyle={{display: 'flex', flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Tabs
tabBarGutter={0}
defaultActiveKey={'basic'}
tabBarStyle={{ display: 'flex', flex: 1, justifyContent: 'center', alignItems: 'center' }}
>
<TabPane tab={'基础信息'} key={'basic'}>
<Basic selectedCell={nodes[0]} />
</TabPane>

17
packages/core/src/mods/settingBar/mods/basic/index.tsx

@ -19,8 +19,7 @@ interface IBasicData {
configSchema: string;
}
const Basic: React.FC<IProps> = props => {
const Basic: React.FC<IProps> = (props) => {
const { selectedCell } = props;
const [data, setData] = useState<IBasicData>();
const { label, code, trigger, dependencies, configSchema } = data || {};
@ -49,12 +48,7 @@ const Basic: React.FC<IProps> = props => {
return (
<div className={styles.container}>
<Input
name={'label'}
title={'显示名称'}
value={label}
onValueChange={onChangeLabel}
/>
<Input name={'label'} title={'显示名称'} value={label} onValueChange={onChangeLabel} />
{selectedCell.shape === 'imove-start' && (
<Input
name={'trigger'}
@ -63,12 +57,7 @@ const Basic: React.FC<IProps> = props => {
onValueChange={onChangeTrigger}
/>
)}
<Code
name={'code'}
title={'代码'}
value={code}
onValueChange={onChangeCode}
/>
<Code name={'code'} title={'代码'} value={code} onValueChange={onChangeCode} />
<Json
name={'configSchema'}
title={'投放配置schema'}

17
packages/core/src/mods/settingBar/mods/config/index.tsx

@ -15,7 +15,7 @@ let tempConfig: any = null;
enum Mode {
edit = 'edit',
readOnly = 'readOnly'
readOnly = 'readOnly',
}
interface IConfig {
@ -26,8 +26,7 @@ interface IProps {
selectedCell: Cell;
}
const Config: React.FC<IProps> = props => {
const Config: React.FC<IProps> = (props) => {
const { selectedCell } = props;
const [mode, setMode] = useState<Mode>(Mode.readOnly);
const [configData, setConfigData] = useState<IConfig>({});
@ -94,12 +93,16 @@ const Config: React.FC<IProps> = props => {
})}
{mode === Mode.readOnly ? (
<div className={styles.footContainer}>
<Button block onClick={onClickEdit}></Button>
<Button block onClick={onClickEdit}>
</Button>
</div>
) : (
<div className={styles.footContainer}>
<Button onClick={onClickCancel}></Button>
<Button className={styles.saveBtn} type={'primary'} onClick={onClickSave}></Button>
<Button className={styles.saveBtn} type={'primary'} onClick={onClickSave}>
</Button>
</div>
)}
</div>
@ -114,7 +117,7 @@ const Helper = {
} else {
return Input;
}
}
}
},
};
export default Config;

11
packages/core/src/mods/sideBar/index.tsx

@ -14,7 +14,7 @@ const CELL_SCALE = 0.7;
const GENERAL_GROUP = {
key: 'general',
name: '通用元件',
cells: ['imove-start-preview', 'imove-branch-preview', 'imove-behavior-preview']
cells: ['imove-start-preview', 'imove-branch-preview', 'imove-behavior-preview'],
};
const SHAPE_REFLECT_MAP: { [key: string]: string } = {
'imove-start-preview': 'imove-start',
@ -32,8 +32,7 @@ interface ISideBarProps {
flowChart: Graph;
}
const SideBar: React.FC<ISideBarProps> = props => {
const SideBar: React.FC<ISideBarProps> = (props) => {
const { flowChart } = props;
const [dnd, setDnd] = useState<Addon.Dnd>();
const [groups, setGroups] = useState<IGroupItem[]>([]);
@ -49,7 +48,7 @@ const SideBar: React.FC<ISideBarProps> = props => {
<div className={styles.container}>
{dnd && (
<Collapse className={styles.collapse} defaultActiveKey={['general', 'custom']}>
{groups.map(group => (
{groups.map((group) => (
<Panel key={group.key} header={group.name}>
<PanelContent dnd={dnd} cells={group.cells} />
</Panel>
@ -65,7 +64,7 @@ interface IPanelContentProps {
cells: string[];
}
const PanelContent: React.FC<IPanelContentProps> = props => {
const PanelContent: React.FC<IPanelContentProps> = (props) => {
const { dnd, cells } = props;
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
@ -84,7 +83,7 @@ const PanelContent: React.FC<IPanelContentProps> = props => {
graph.addNode({
shape: cell,
x: colIdx * (CELL_SIZE + 16 / CELL_SCALE),
y: rowIdx * (CELL_SIZE + 16 / CELL_SCALE) + top
y: rowIdx * (CELL_SIZE + 16 / CELL_SCALE) + top,
});
});
graph.scale(CELL_SCALE, CELL_SCALE);

5
packages/core/src/mods/toolBar/index.tsx

@ -11,10 +11,9 @@ interface IProps {
flowChart: Graph;
}
const ToolBar: React.FC<IProps> = props => {
const ToolBar: React.FC<IProps> = (props) => {
const { flowChart } = props;
const forceUpdate = useReducer(n => n + 1, 0)[1];
const forceUpdate = useReducer((n) => n + 1, 0)[1];
useEffect(() => {
flowChart.on('toolBar:forceUpdate', forceUpdate);

6
packages/core/src/mods/toolBar/widgets/bgColor.tsx

@ -36,12 +36,10 @@ const options = {
getOverlay(flowChart: Graph, onChange: (data: any) => void) {
const bgColor = options.getCurBgColor(flowChart);
const onChangeComplete = (color: string) => onChange(color);
return (
<ColorPicker color={bgColor} onChangeComplete={onChangeComplete}/>
);
return <ColorPicker color={bgColor} onChangeComplete={onChangeComplete} />;
},
handler: (flowChart: Graph, value: any) => {
getSelectedNodes(flowChart).forEach(node => node.setAttrs({body: {fill: value}}));
getSelectedNodes(flowChart).forEach((node) => node.setAttrs({ body: { fill: value } }));
},
disabled(flowChart: Graph) {
return !hasNodeSelected(flowChart);

6
packages/core/src/mods/toolBar/widgets/bold.tsx

@ -7,12 +7,12 @@ import shortcuts from '../../../common/shortcuts';
import makeBtnWidget from './common/makeBtnWidget';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const Bold: React.FC<IProps> = makeBtnWidget({
tooltip: '加粗',
handler: shortcuts['bold'].handler,
handler: shortcuts.bold.handler,
getIcon() {
return <BoldOutlined />;
},
@ -26,7 +26,7 @@ const Bold: React.FC<IProps> = makeBtnWidget({
} else {
return false;
}
}
},
});
export default Bold;

6
packages/core/src/mods/toolBar/widgets/borderColor.tsx

@ -36,12 +36,10 @@ const options = {
getOverlay(flowChart: Graph, onChange: (data: any) => void) {
const borderColor = options.getCurBorderColor(flowChart);
const onChangeComplete = (color: string) => onChange(color);
return (
<ColorPicker color={borderColor} onChangeComplete={onChangeComplete}/>
);
return <ColorPicker color={borderColor} onChangeComplete={onChangeComplete} />;
},
handler: (flowChart: Graph, value: any) => {
getSelectedNodes(flowChart).forEach(node => node.setAttrs({body: {stroke: value}}));
getSelectedNodes(flowChart).forEach((node) => node.setAttrs({ body: { stroke: value } }));
},
disabled(flowChart: Graph) {
return !hasNodeSelected(flowChart);

6
packages/core/src/mods/toolBar/widgets/bringToBack.tsx

@ -6,7 +6,7 @@ import makeBtnWidget from './common/makeBtnWidget';
import { getSelectedNodes, hasNodeSelected } from '../../../utils/flowChartUtils';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const BringToBack: React.FC<IProps> = makeBtnWidget({
@ -15,11 +15,11 @@ const BringToBack: React.FC<IProps> = makeBtnWidget({
return <XIcon type={'icon-bringtobottom'} />;
},
handler(flowChart: Graph) {
getSelectedNodes(flowChart).forEach(node => node.toBack());
getSelectedNodes(flowChart).forEach((node) => node.toBack());
},
disabled(flowChart: Graph) {
return !hasNodeSelected(flowChart);
}
},
});
export default BringToBack;

6
packages/core/src/mods/toolBar/widgets/bringToTop.tsx

@ -7,7 +7,7 @@ import makeBtnWidget from './common/makeBtnWidget';
import { getSelectedNodes, hasNodeSelected } from '../../../utils/flowChartUtils';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const BringToTop: React.FC<IProps> = makeBtnWidget({
@ -16,11 +16,11 @@ const BringToTop: React.FC<IProps> = makeBtnWidget({
return <XIcon type={'icon-bringtotop'} />;
},
handler(flowChart: Graph) {
getSelectedNodes(flowChart).forEach(node => node.toFront());
getSelectedNodes(flowChart).forEach((node) => node.toFront());
},
disabled(flowChart: Graph) {
return !hasNodeSelected(flowChart);
}
},
});
export default BringToTop;

2
packages/core/src/mods/toolBar/widgets/common/makeBtnWidget.tsx

@ -36,7 +36,7 @@ const makeBtnWidget = (options: IOptions) => {
if (disabled) return;
handler(flowChart);
flowChart.trigger('toolBar:forceUpdate');
}
};
return (
<Tooltip title={tooltip}>
<div className={iconWrapperCls.join(' ')} onClick={onClick}>

4
packages/core/src/mods/toolBar/widgets/fitWindow.tsx

@ -5,7 +5,7 @@ import makeBtnWidget from './common/makeBtnWidget';
import { FullscreenExitOutlined } from '@ant-design/icons';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const FitWindow: React.FC<IProps> = makeBtnWidget({
@ -15,7 +15,7 @@ const FitWindow: React.FC<IProps> = makeBtnWidget({
},
handler(flowChart: Graph) {
flowChart.zoomToFit({ minScale: 0.5, maxScale: 1 });
}
},
});
export default FitWindow;

10
packages/core/src/mods/toolBar/widgets/fontSize.tsx

@ -8,13 +8,11 @@ import {safeGet} from '../../../utils';
import makeDropdownWidget from './common/makeDropdownWidget';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const MenuItem = Menu.Item;
const FONT_SIZE_SET = [
9, 10, 11, 12, 13, 14, 15, 16, 19, 22, 24, 29, 32
];
const FONT_SIZE_SET = [9, 10, 11, 12, 13, 14, 15, 16, 19, 22, 24, 29, 32];
const FontSize: React.FC<IProps> = makeDropdownWidget({
tooltip: '字号',
@ -29,7 +27,7 @@ const FontSize: React.FC<IProps> = makeDropdownWidget({
getOverlay(flowChart: Graph, onChange: (data: any) => void) {
return (
<Menu onClick={(args) => onChange(args.key)}>
{FONT_SIZE_SET.map(fontSize => (
{FONT_SIZE_SET.map((fontSize) => (
<MenuItem key={fontSize}>
<span>{fontSize} px</span>
</MenuItem>
@ -38,7 +36,7 @@ const FontSize: React.FC<IProps> = makeDropdownWidget({
);
},
handler: (flowChart: Graph, value: any) => {
flowChart.getSelectedCells().forEach(cell => cell.setAttrs({label: {fontSize: value}}));
flowChart.getSelectedCells().forEach((cell) => cell.setAttrs({ label: { fontSize: value } }));
},
disabled(flowChart: Graph) {
return flowChart.getSelectedCellCount() === 0;

26
packages/core/src/mods/toolBar/widgets/horizontalAlign.tsx

@ -22,8 +22,8 @@ interface AlignItem {
textAnchor: string;
align: {
horizontal: string;
}
}
};
};
}
const MenuItem = Menu.Item;
@ -36,9 +36,9 @@ const ALIGN_MAP: {[key: string]: AlignItem} = {
refX2: 5,
textAnchor: 'start',
align: {
horizontal: 'left'
}
}
horizontal: 'left',
},
},
},
center: {
text: '居中对齐',
@ -48,9 +48,9 @@ const ALIGN_MAP: {[key: string]: AlignItem} = {
refX2: 0,
textAnchor: 'middle',
align: {
horizontal: 'center'
}
}
horizontal: 'center',
},
},
},
right: {
text: '右对齐',
@ -60,10 +60,10 @@ const ALIGN_MAP: {[key: string]: AlignItem} = {
refX2: -5,
textAnchor: 'end',
align: {
horizontal: 'right'
}
}
}
horizontal: 'right',
},
},
},
};
const HorizontalAlign: React.FC<IProps> = makeDropdownWidget({
@ -89,7 +89,7 @@ const HorizontalAlign: React.FC<IProps> = makeDropdownWidget({
);
},
handler: (flowChart: Graph, value: any) => {
getSelectedNodes(flowChart).forEach(node => node.setAttrs({label: value}));
getSelectedNodes(flowChart).forEach((node) => node.setAttrs({ label: value }));
},
disabled(flowChart: Graph) {
return !hasNodeSelected(flowChart);

2
packages/core/src/mods/toolBar/widgets/index.tsx

@ -30,7 +30,7 @@ const tools: React.FC<IProps>[][] = [
[FontSize, Bold, Italic, Underline],
[TextColor, BgColor, BorderColor, LineStyle],
[HorizontalAlign, VerticalAlign],
[BringToTop, BringToBack]
[BringToTop, BringToBack],
];
export default tools;

6
packages/core/src/mods/toolBar/widgets/italic.tsx

@ -7,12 +7,12 @@ import {ItalicOutlined} from '@ant-design/icons';
import shortcuts from '../../../common/shortcuts';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const Italic: React.FC<IProps> = makeBtnWidget({
tooltip: '斜体',
handler: shortcuts['italic'].handler,
handler: shortcuts.italic.handler,
getIcon() {
return <ItalicOutlined />;
},
@ -26,7 +26,7 @@ const Italic: React.FC<IProps> = makeBtnWidget({
} else {
return false;
}
}
},
});
export default Italic;

14
packages/core/src/mods/toolBar/widgets/lineStyle.tsx

@ -19,7 +19,7 @@ interface LineStyleItem {
attrs: {
type: string;
strokeDasharray: string;
}
};
}
const MenuItem = Menu.Item;
@ -29,17 +29,17 @@ const LINE_STYLE_MAP: {[key: string]: LineStyleItem} = {
icon: <XIcon type={'icon-line'} />,
attrs: {
type: 'straight',
strokeDasharray: '5, 0'
}
strokeDasharray: '5, 0',
},
},
dashed: {
text: '虚线',
icon: <XIcon type={'icon-dash'} />,
attrs: {
type: 'dashed',
strokeDasharray: '5, 5'
}
}
strokeDasharray: '5, 5',
},
},
};
const LineStyle: React.FC<IProps> = makeDropdownWidget({
@ -65,7 +65,7 @@ const LineStyle: React.FC<IProps> = makeDropdownWidget({
);
},
handler: (flowChart: Graph, value: any) => {
getSelectedEdges(flowChart).forEach(edge => edge.setAttrs({line: value}));
getSelectedEdges(flowChart).forEach((edge) => edge.setAttrs({ line: value }));
},
disabled(flowChart: Graph) {
return !hasEdgeSelected(flowChart);

15
packages/core/src/mods/toolBar/widgets/modifyStatus.tsx

@ -8,34 +8,33 @@ enum Status {
pending = 0,
syncing = 1,
successful = 2,
failed = 3
failed = 3,
}
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const statusMap = {
[Status.pending]: {
color: '',
text: ''
text: '',
},
[Status.syncing]: {
color: '#999',
text: '正在保存...'
text: '正在保存...',
},
[Status.successful]: {
color: '#999',
text: '所有更改已保存'
text: '所有更改已保存',
},
[Status.failed]: {
color: '#EC5B56',
text: '同步失败,进入离线模式'
}
text: '同步失败,进入离线模式',
},
};
const ModifyStatus: React.FC<IProps> = (props) => {
const { flowChart } = props;
const [status, setStatus] = useState<Status>(Status.pending);

6
packages/core/src/mods/toolBar/widgets/redo.tsx

@ -6,18 +6,18 @@ import shortcuts from '../../../common/shortcuts';
import makeBtnWidget from './common/makeBtnWidget';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const Save: React.FC<IProps> = makeBtnWidget({
tooltip: '重做',
handler: shortcuts['redo'].handler,
handler: shortcuts.redo.handler,
getIcon() {
return <RedoOutlined />;
},
disabled(flowChart: Graph) {
return !flowChart.canRedo();
}
},
});
export default Save;

6
packages/core/src/mods/toolBar/widgets/save.tsx

@ -6,15 +6,15 @@ import shortcuts from '../../../common/shortcuts';
import makeBtnWidget from './common/makeBtnWidget';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const Save: React.FC<IProps> = makeBtnWidget({
tooltip: '保存',
handler: shortcuts['save'].handler,
handler: shortcuts.save.handler,
getIcon() {
return <SaveOutlined />;
}
},
});
export default Save;

6
packages/core/src/mods/toolBar/widgets/textColor.tsx

@ -36,12 +36,10 @@ const options = {
getOverlay(flowChart: Graph, onChange: (data: any) => void) {
const textColor = options.getCurTextColor(flowChart);
const onChangeComplete = (color: string) => onChange(color);
return (
<ColorPicker color={textColor} onChangeComplete={onChangeComplete}/>
);
return <ColorPicker color={textColor} onChangeComplete={onChangeComplete} />;
},
handler: (flowChart: Graph, value: any) => {
flowChart.getSelectedCells().forEach(node => node.setAttrs({label: {fill: value}}));
flowChart.getSelectedCells().forEach((node) => node.setAttrs({ label: { fill: value } }));
},
disabled(flowChart: Graph) {
return !hasNodeSelected(flowChart);

6
packages/core/src/mods/toolBar/widgets/underline.tsx

@ -7,12 +7,12 @@ import makeBtnWidget from './common/makeBtnWidget';
import { UnderlineOutlined } from '@ant-design/icons';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const Underline: React.FC<IProps> = makeBtnWidget({
tooltip: '下划线',
handler: shortcuts['underline'].handler,
handler: shortcuts.underline.handler,
getIcon() {
return <UnderlineOutlined />;
},
@ -26,7 +26,7 @@ const Underline: React.FC<IProps> = makeBtnWidget({
} else {
return false;
}
}
},
});
export default Underline;

6
packages/core/src/mods/toolBar/widgets/undo.tsx

@ -6,18 +6,18 @@ import shortcuts from '../../../common/shortcuts';
import makeBtnWidget from './common/makeBtnWidget';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const Save: React.FC<IProps> = makeBtnWidget({
tooltip: '撤销',
handler: shortcuts['undo'].handler,
handler: shortcuts.undo.handler,
getIcon() {
return <UndoOutlined />;
},
disabled(flowChart: Graph) {
return !flowChart.canUndo();
}
},
});
export default Save;

32
packages/core/src/mods/toolBar/widgets/verticalAlign.tsx

@ -7,7 +7,11 @@ import {Graph} from '@antv/x6';
import { safeGet } from '../../../utils';
import makeDropdownWidget from './common/makeDropdownWidget';
import { hasNodeSelected, getSelectedNodes } from '../../../utils/flowChartUtils';
import {VerticalAlignTopOutlined, VerticalAlignMiddleOutlined, VerticalAlignBottomOutlined} from '@ant-design/icons';
import {
VerticalAlignTopOutlined,
VerticalAlignMiddleOutlined,
VerticalAlignBottomOutlined,
} from '@ant-design/icons';
interface IProps {
flowChart: Graph;
@ -22,8 +26,8 @@ interface AlignItem {
textVerticalAlign: string;
align: {
vertical: string;
}
}
};
};
}
const MenuItem = Menu.Item;
@ -36,9 +40,9 @@ const ALIGN_MAP: {[key: string]: AlignItem} = {
refY2: 10,
textVerticalAlign: 'start',
align: {
vertical: 'top'
}
}
vertical: 'top',
},
},
},
center: {
text: '居中对齐',
@ -48,9 +52,9 @@ const ALIGN_MAP: {[key: string]: AlignItem} = {
refY2: 0,
textVerticalAlign: 'middle',
align: {
vertical: 'center'
}
}
vertical: 'center',
},
},
},
bottom: {
text: '下对齐',
@ -60,10 +64,10 @@ const ALIGN_MAP: {[key: string]: AlignItem} = {
refY2: -10,
textVerticalAlign: 'end',
align: {
vertical: 'bottom'
}
}
}
vertical: 'bottom',
},
},
},
};
const VerticalAlign: React.FC<IProps> = makeDropdownWidget({
@ -89,7 +93,7 @@ const VerticalAlign: React.FC<IProps> = makeDropdownWidget({
);
},
handler: (flowChart: Graph, value: any) => {
getSelectedNodes(flowChart).forEach(node => node.setAttrs({label: value}));
getSelectedNodes(flowChart).forEach((node) => node.setAttrs({ label: value }));
},
disabled(flowChart: Graph) {
return !hasNodeSelected(flowChart);

18
packages/core/src/mods/toolBar/widgets/zoom.tsx

@ -8,7 +8,7 @@ import makeBtnWidget from './common/makeBtnWidget';
import { ZoomOutOutlined, ZoomInOutlined } from '@ant-design/icons';
interface IProps {
flowChart: Graph
flowChart: Graph;
}
const MIN_ZOOM = 0.5;
@ -16,27 +16,27 @@ const MAX_ZOOM = 1.5;
const ZoomOut: React.FC<IProps> = makeBtnWidget({
tooltip: '缩小',
handler: shortcuts['zoomOut'].handler,
handler: shortcuts.zoomOut.handler,
getIcon() {
return <ZoomOutOutlined />;
},
disabled(flowChart: Graph) {
return flowChart.zoom() <= MIN_ZOOM;
}
},
});
const ZoomIn: React.FC<IProps> = makeBtnWidget({
tooltip: '放大',
handler: shortcuts['zoomIn'].handler,
handler: shortcuts.zoomIn.handler,
getIcon() {
return <ZoomInOutlined />;
},
disabled(flowChart: Graph) {
return flowChart.zoom() >= MAX_ZOOM;
}
},
});
const Zoom: React.FC<IProps> = props => {
const Zoom: React.FC<IProps> = (props) => {
const { flowChart } = props;
const [scale, setScale] = useState<number>(flowChart.zoom());
useEffect(() => {
@ -47,9 +47,7 @@ const Zoom: React.FC<IProps> = props => {
return (
<div className={styles.zoomContainer}>
<ZoomOut {...props} />
<span className={styles.zoomText}>
{Helper.scaleFormatter(scale)}
</span>
<span className={styles.zoomText}>{Helper.scaleFormatter(scale)}</span>
<ZoomIn {...props} />
</div>
);
@ -58,7 +56,7 @@ const Zoom: React.FC<IProps> = props => {
const Helper = {
scaleFormatter(scale: number): string {
return (scale * 100).toFixed(0) + '%';
}
},
};
export default Zoom;

8
packages/core/src/utils/flowChartUtils.ts

@ -1,8 +1,8 @@
import {Cell, Graph} from "@antv/x6";
import { Cell, Graph } from '@antv/x6';
export const hasCellSelected = (flowChart: Graph): boolean => {
return flowChart.getSelectedCellCount() > 0;
}
};
export const hasNodeSelected = (flowChart: Graph): boolean => {
return flowChart.getSelectedCells().filter((cell: Cell) => cell.isNode()).length > 0;
@ -14,8 +14,8 @@ export const hasEdgeSelected = (flowChart: Graph): boolean => {
export const getSelectedNodes = (flowChart: Graph): Cell[] => {
return flowChart.getSelectedCells().filter((cell: Cell) => cell.isNode());
}
};
export const getSelectedEdges = (flowChart: Graph): Cell[] => {
return flowChart.getSelectedCells().filter((cell: Cell) => cell.isEdge());
}
};

5
packages/core/src/utils/index.ts

@ -1,15 +1,14 @@
import { parse } from 'query-string';
export const safeParse = (json: string): Object => {
export const safeParse = (json: string): Record<string, any> => {
try {
return JSON.parse(json);
} catch(err) {
} catch (error) {
return {};
}
};
export const safeGet = (obj: any, keyChain: string, defaultVal?: any): any => {
if (typeof obj !== 'object' || obj === null) {
return defaultVal;
}

4
packages/plugin-store/src/index.ts

@ -15,9 +15,9 @@ const plugin = (logic: any) => {
},
remove(key: string) {
delete logic[storeSymbol][key];
}
},
};
}
},
};
};

Loading…
Cancel
Save