@acala-network/chopsticks 0.3.11 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/chopsticks.js +1 -1
  2. package/{dist → lib}/blockchain/block-builder.d.ts +3 -1
  3. package/{dist → lib}/blockchain/block-builder.js +29 -10
  4. package/{dist → lib}/blockchain/index.d.ts +3 -2
  5. package/{dist → lib}/blockchain/index.js +8 -3
  6. package/{dist → lib}/blockchain/inherent/parachain/babe-randomness.d.ts +1 -1
  7. package/{dist → lib}/blockchain/inherent/parachain/nimbus-author-inherent.d.ts +1 -1
  8. package/{dist → lib}/blockchain/inherent/parachain/validation-data.d.ts +1 -1
  9. package/{dist → lib}/blockchain/inherent/parachain/validation-data.js +63 -38
  10. package/{dist → lib}/blockchain/txpool.d.ts +4 -0
  11. package/{dist → lib}/blockchain/txpool.js +7 -2
  12. package/{dist → lib}/cli.js +12 -2
  13. package/lib/dry-run-preimage.d.ts +2 -0
  14. package/lib/dry-run-preimage.js +99 -0
  15. package/{dist → lib}/executor.js +2 -6
  16. package/{dist → lib}/logger.js +7 -3
  17. package/{dist → lib}/rpc/substrate/author.js +22 -6
  18. package/{dist → lib}/rpc/substrate/chain.d.ts +1 -0
  19. package/{dist → lib}/rpc/substrate/chain.js +10 -4
  20. package/lib/rpc/substrate/system.d.ts +3 -0
  21. package/{dist → lib}/server.js +6 -1
  22. package/{dist → lib}/setup.js +3 -1
  23. package/{dist → lib}/utils/decoder.js +5 -1
  24. package/{dist → lib}/utils/set-storage.js +4 -2
  25. package/package.json +40 -63
  26. package/template/diff.html +139 -78
  27. package/LICENSE +0 -201
  28. package/README.md +0 -71
  29. package/dist/executor.test.d.ts +0 -1
  30. package/dist/executor.test.js +0 -138
  31. package/dist/rpc/substrate/author.d.ts +0 -3
  32. /package/{dist → lib}/api.d.ts +0 -0
  33. /package/{dist → lib}/api.js +0 -0
  34. /package/{dist → lib}/blockchain/block.d.ts +0 -0
  35. /package/{dist → lib}/blockchain/block.js +0 -0
  36. /package/{dist → lib}/blockchain/head-state.d.ts +0 -0
  37. /package/{dist → lib}/blockchain/head-state.js +0 -0
  38. /package/{dist → lib}/blockchain/inherent/index.d.ts +0 -0
  39. /package/{dist → lib}/blockchain/inherent/index.js +0 -0
  40. /package/{dist → lib}/blockchain/inherent/para-enter.d.ts +0 -0
  41. /package/{dist → lib}/blockchain/inherent/para-enter.js +0 -0
  42. /package/{dist → lib}/blockchain/inherent/parachain/babe-randomness.js +0 -0
  43. /package/{dist → lib}/blockchain/inherent/parachain/nimbus-author-inherent.js +0 -0
  44. /package/{dist → lib}/blockchain/storage-layer.d.ts +0 -0
  45. /package/{dist → lib}/blockchain/storage-layer.js +0 -0
  46. /package/{dist → lib}/cli.d.ts +0 -0
  47. /package/{dist → lib}/db/entities.d.ts +0 -0
  48. /package/{dist → lib}/db/entities.js +0 -0
  49. /package/{dist → lib}/db/index.d.ts +0 -0
  50. /package/{dist → lib}/db/index.js +0 -0
  51. /package/{dist → lib}/dry-run.d.ts +0 -0
  52. /package/{dist → lib}/dry-run.js +0 -0
  53. /package/{dist → lib}/executor.d.ts +0 -0
  54. /package/{dist → lib}/genesis-provider.d.ts +0 -0
  55. /package/{dist → lib}/genesis-provider.js +0 -0
  56. /package/{dist → lib}/index.d.ts +0 -0
  57. /package/{dist → lib}/index.js +0 -0
  58. /package/{dist → lib}/logger.d.ts +0 -0
  59. /package/{dist → lib}/rpc/dev.d.ts +0 -0
  60. /package/{dist → lib}/rpc/dev.js +0 -0
  61. /package/{dist → lib}/rpc/index.d.ts +0 -0
  62. /package/{dist → lib}/rpc/index.js +0 -0
  63. /package/{dist → lib}/rpc/shared.d.ts +0 -0
  64. /package/{dist → lib}/rpc/shared.js +0 -0
  65. /package/{dist/rpc/substrate/index.d.ts → lib/rpc/substrate/author.d.ts} +0 -0
  66. /package/{dist/rpc/substrate/payment.d.ts → lib/rpc/substrate/index.d.ts} +0 -0
  67. /package/{dist → lib}/rpc/substrate/index.js +0 -0
  68. /package/{dist/rpc/substrate/state.d.ts → lib/rpc/substrate/payment.d.ts} +0 -0
  69. /package/{dist → lib}/rpc/substrate/payment.js +0 -0
  70. /package/{dist/rpc/substrate/system.d.ts → lib/rpc/substrate/state.d.ts} +0 -0
  71. /package/{dist → lib}/rpc/substrate/state.js +0 -0
  72. /package/{dist → lib}/rpc/substrate/system.js +0 -0
  73. /package/{dist → lib}/run-block.d.ts +0 -0
  74. /package/{dist → lib}/run-block.js +0 -0
  75. /package/{dist → lib}/schema/index.d.ts +0 -0
  76. /package/{dist → lib}/schema/index.js +0 -0
  77. /package/{dist → lib}/server.d.ts +0 -0
  78. /package/{dist → lib}/setup-with-server.d.ts +0 -0
  79. /package/{dist → lib}/setup-with-server.js +0 -0
  80. /package/{dist → lib}/setup.d.ts +0 -0
  81. /package/{dist → lib}/utils/decoder.d.ts +0 -0
  82. /package/{dist → lib}/utils/generate-html-diff.d.ts +0 -0
  83. /package/{dist → lib}/utils/generate-html-diff.js +0 -0
  84. /package/{dist → lib}/utils/import-storage.d.ts +0 -0
  85. /package/{dist → lib}/utils/import-storage.js +0 -0
  86. /package/{dist → lib}/utils/index.d.ts +0 -0
  87. /package/{dist → lib}/utils/index.js +0 -0
  88. /package/{dist → lib}/utils/open-html.d.ts +0 -0
  89. /package/{dist → lib}/utils/open-html.js +0 -0
  90. /package/{dist → lib}/utils/proof.d.ts +0 -0
  91. /package/{dist → lib}/utils/proof.js +0 -0
  92. /package/{dist → lib}/utils/set-storage.d.ts +0 -0
  93. /package/{dist → lib}/utils/time-travel.d.ts +0 -0
  94. /package/{dist → lib}/utils/time-travel.js +0 -0
  95. /package/{dist → lib}/xcm/downward.d.ts +0 -0
  96. /package/{dist → lib}/xcm/downward.js +0 -0
  97. /package/{dist → lib}/xcm/horizontal.d.ts +0 -0
  98. /package/{dist → lib}/xcm/horizontal.js +0 -0
  99. /package/{dist → lib}/xcm/index.d.ts +0 -0
  100. /package/{dist → lib}/xcm/index.js +0 -0
  101. /package/{dist → lib}/xcm/upward.d.ts +0 -0
  102. /package/{dist → lib}/xcm/upward.js +0 -0
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const shared_1 = require("../shared");
4
+ const processHeader = (header) => {
5
+ const res = header.toJSON();
6
+ res.number = '0x' + res.number.toString(16); // number is hex format
7
+ return res;
8
+ };
4
9
  const handlers = {
5
10
  chain_getBlockHash: async (context, [blockNumber]) => {
6
11
  const block = await context.chain.getBlockAt(blockNumber);
@@ -14,7 +19,7 @@ const handlers = {
14
19
  if (!block) {
15
20
  throw new shared_1.ResponseError(1, `Block ${hash} not found`);
16
21
  }
17
- return await block.header;
22
+ return processHeader(await block.header);
18
23
  },
19
24
  chain_getBlock: async (context, [hash]) => {
20
25
  const block = await context.chain.getBlock(hash);
@@ -37,7 +42,7 @@ const handlers = {
37
42
  const id = context.chain.headState.subscribeHead(() => update());
38
43
  const callback = subscribe('chain_newHead', id, () => context.chain.headState.unsubscribeHead(id));
39
44
  update = async () => {
40
- callback(await context.chain.head.header);
45
+ callback(processHeader(await context.chain.head.header));
41
46
  };
42
47
  update();
43
48
  return id;
@@ -45,9 +50,9 @@ const handlers = {
45
50
  chain_subscribeFinalizedHeads: async (context, _params, { subscribe }) => {
46
51
  let update = () => { };
47
52
  const id = context.chain.headState.subscribeHead(() => update());
48
- const callback = subscribe('chain_newFinalizedHead', id, () => context.chain.headState.unsubscribeHead(id));
53
+ const callback = subscribe('chain_finalizedHead', id, () => context.chain.headState.unsubscribeHead(id));
49
54
  update = async () => {
50
- callback(await context.chain.head.header);
55
+ callback(processHeader(await context.chain.head.header));
51
56
  };
52
57
  update();
53
58
  return id;
@@ -59,6 +64,7 @@ const handlers = {
59
64
  const alias = {
60
65
  chain_subscribeNewHeads: handlers.chain_subscribeNewHead,
61
66
  chain_unsubscribeNewHeads: handlers.chain_unsubscribeNewHead,
67
+ chain_unsubscribeFinalizedHeads: handlers.chain_unsubscribeNewHead,
62
68
  };
63
69
  exports.default = {
64
70
  ...handlers,
@@ -0,0 +1,3 @@
1
+ import { Handlers } from '../shared';
2
+ declare const handlers: Handlers;
3
+ export default handlers;
@@ -76,6 +76,7 @@ const createServer = async (handler, port) => {
76
76
  subscriptions[subid] = onCancel;
77
77
  return (data) => {
78
78
  if (subscriptions[subid]) {
79
+ logger.trace({ method, subid, data: (0, logger_1.truncate)(data) }, 'Subscription notification');
79
80
  send({
80
81
  jsonrpc: '2.0',
81
82
  method,
@@ -128,7 +129,11 @@ const createServer = async (handler, port) => {
128
129
  }, 'Received message');
129
130
  try {
130
131
  const resp = await handler(req, subscriptionManager);
131
- logger.trace('Sending response for request %o %o', req.id, req.method);
132
+ logger.trace({
133
+ id: req.id,
134
+ method: req.method,
135
+ result: (0, logger_1.truncate)(resp),
136
+ }, 'Sending response for request');
132
137
  send({
133
138
  id: req.id,
134
139
  jsonrpc: '2.0',
@@ -63,8 +63,10 @@ const setup = async (argv) => {
63
63
  });
64
64
  if (argv.timestamp)
65
65
  await (0, time_travel_1.timeTravel)(chain, argv.timestamp);
66
- await (0, import_storage_1.importStorage)(chain, argv['import-storage']);
66
+ // override wasm before importing storage, in case new pallets have been
67
+ // added that have storage imports
67
68
  await (0, import_storage_1.overrideWasm)(chain, argv['wasm-override']);
69
+ await (0, import_storage_1.importStorage)(chain, argv['import-storage']);
68
70
  return { chain, api, ws: provider };
69
71
  };
70
72
  exports.setup = setup;
@@ -100,6 +100,10 @@ const decodeStorageDiff = async (block, diff) => {
100
100
  lodash_1.default.merge(oldState, await (0, exports.decodeKeyValue)(block, key, (await block.get(key))));
101
101
  lodash_1.default.merge(newState, await (0, exports.decodeKeyValue)(block, key, value));
102
102
  }
103
- return [oldState, newState, diffPatcher.diff(oldState, newState)];
103
+ const oldStateWithoutEvents = lodash_1.default.cloneDeep(oldState);
104
+ if (oldStateWithoutEvents['system']?.['events']) {
105
+ oldStateWithoutEvents['system']['events'] = [];
106
+ }
107
+ return [oldState, newState, diffPatcher.diff(oldStateWithoutEvents, newState)];
104
108
  };
105
109
  exports.decodeStorageDiff = decodeStorageDiff;
@@ -28,12 +28,14 @@ function objectToStorageItems(meta, storage) {
28
28
  throw Error(`Cannot find storage ${storageName} in pallet ${sectionName}`);
29
29
  if (storageEntry.meta.type.isPlain) {
30
30
  const key = new types_1.StorageKey(meta.registry, [storageEntry]);
31
- storageItems.push([key.toHex(), storage ? meta.registry.createType(key.outputType, storage).toHex(true) : null]);
31
+ const type = storageEntry.meta.modifier.isOptional ? `Option<${key.outputType}>` : key.outputType;
32
+ storageItems.push([key.toHex(), storage ? meta.registry.createType(type, storage).toHex() : null]);
32
33
  }
33
34
  else {
34
35
  for (const [keys, value] of storage) {
35
36
  const key = new types_1.StorageKey(meta.registry, [storageEntry, keys]);
36
- storageItems.push([key.toHex(), value ? meta.registry.createType(key.outputType, value).toHex(true) : null]);
37
+ const type = storageEntry.meta.modifier.isOptional ? `Option<${key.outputType}>` : key.outputType;
38
+ storageItems.push([key.toHex(), value ? meta.registry.createType(type, value).toHex() : null]);
37
39
  }
38
40
  }
39
41
  }
package/package.json CHANGED
@@ -1,91 +1,68 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks",
3
- "version": "0.3.11",
4
- "main": "./dist/index.js",
5
- "types": "./dist/index.d.ts",
3
+ "version": "0.4.0",
4
+ "main": "./lib/index.js",
5
+ "types": "./lib/index.d.ts",
6
6
  "author": "Bryan Chen <xlchen1291@gmail.com>",
7
7
  "license": "Apache-2.0",
8
- "packageManager": "yarn@3.2.4",
9
- "workspaces": [
10
- ".",
11
- "executor/pkg"
12
- ],
13
8
  "bin": "./chopsticks.js",
14
9
  "scripts": {
15
10
  "lint": "tsc --noEmit --project tsconfig.json && eslint . --ext .js,.ts && prettier --check .",
16
11
  "fix": "eslint . --ext .js,.ts --fix && prettier -w .",
17
- "prepare": "husky install",
18
- "start": "ts-node --transpile-only src/cli.ts",
19
- "build": "rm -rf dist && tsc -p tsconfig.prod.json",
20
- "build-wasm": "wasm-pack build executor --target nodejs --scope acala-network",
21
- "build-wasm-logging": "yarn build-wasm --features=logging",
22
- "check": "cd executor && cargo check --locked",
23
- "test": "vitest --silent",
24
- "test:dev": "LOG_LEVEL=trace vitest --inspect",
25
- "dev": "LOG_LEVEL=trace ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=configs/dev.yml",
26
- "dev:karura": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=configs/karura.yml",
27
- "dev:acala": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=configs/acala.yml",
28
- "dev:moonriver": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=configs/moonriver.yml",
29
- "dev:moonbeam": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=configs/moonbeam.yml"
12
+ "build": "rm -rf lib && tsc -p ./tsconfig.json",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest",
15
+ "script:start": "cd ../..; ts-node packages/chopsticks/src/cli.ts",
16
+ "script:run": "LOG_LEVEL=trace ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/dev.yml",
17
+ "dev:karura": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/karura.yml",
18
+ "dev:acala": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/acala.yml",
19
+ "dev:moonriver": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/moonriver.yml",
20
+ "dev:moonbeam": "ts-node-dev --transpile-only --inspect --notify=false src/cli.ts -- dev --config=../../configs/moonbeam.yml"
30
21
  },
31
22
  "dependencies": {
32
- "@acala-network/chopsticks-executor": "0.3.10",
33
- "@polkadot/api": "^9.12.1",
34
- "@polkadot/rpc-provider": "^9.12.1",
35
- "@polkadot/types": "^9.12.1",
36
- "@polkadot/types-codec": "^9.12.1",
37
- "@polkadot/types-known": "^9.12.1",
38
- "@polkadot/util": "^10.2.6",
39
- "@polkadot/util-crypto": "^10.2.6",
40
- "axios": "^1.2.5",
23
+ "@acala-network/chopsticks-executor": "0.4.0",
24
+ "@polkadot/api": "^9.14.2",
25
+ "@polkadot/rpc-provider": "^9.14.2",
26
+ "@polkadot/types": "^9.14.2",
27
+ "@polkadot/types-codec": "^9.14.2",
28
+ "@polkadot/types-known": "^9.14.2",
29
+ "@polkadot/util": "^10.4.2",
30
+ "@polkadot/util-crypto": "^10.4.2",
31
+ "axios": "^1.3.3",
41
32
  "js-yaml": "^4.1.0",
42
33
  "jsondiffpatch": "^0.4.1",
43
34
  "lodash": "^4.17.21",
44
- "pino": "^8.8.0",
45
- "pino-pretty": "^9.1.1",
35
+ "pino": "^8.10.0",
36
+ "pino-pretty": "^9.3.0",
46
37
  "reflect-metadata": "^0.1.13",
47
38
  "sqlite3": "^5.1.4",
48
- "typeorm": "^0.3.11",
49
- "typescript": "^4.9.4",
50
- "ws": "^8.12.0",
51
- "yargs": "^17.6.2",
52
- "zod": "^3.20.2"
39
+ "typeorm": "^0.3.12",
40
+ "ws": "^8.12.1",
41
+ "yargs": "^17.7.1",
42
+ "zod": "^3.20.6"
53
43
  },
54
44
  "devDependencies": {
55
45
  "@types/js-yaml": "^4.0.5",
56
46
  "@types/lodash": "^4.14.191",
57
- "@types/node": "^18.11.18",
47
+ "@types/node": "^18.14.0",
48
+ "@types/prettier": "^2.7.2",
58
49
  "@types/ws": "^8.5.4",
59
- "@types/yargs": "^17.0.20",
60
- "@typescript-eslint/eslint-plugin": "^5.49.0",
61
- "@typescript-eslint/parser": "^5.49.0",
62
- "eslint": "^8.32.0",
50
+ "@types/yargs": "^17.0.22",
51
+ "@typescript-eslint/eslint-plugin": "^5.53.0",
52
+ "@typescript-eslint/parser": "^5.53.0",
53
+ "eslint": "^8.34.0",
63
54
  "eslint-config-prettier": "^8.6.0",
64
55
  "eslint-plugin-import": "^2.27.5",
65
56
  "eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
66
- "husky": "^8.0.3",
67
- "lint-staged": "^13.1.0",
68
- "prettier": "^2.8.3",
57
+ "prettier": "^2.8.4",
69
58
  "ts-node": "^10.9.1",
70
59
  "ts-node-dev": "^2.0.0",
71
- "vitest": "^0.28.3",
72
- "wasm-pack": "^0.10.3"
60
+ "typescript": "^4.9.5",
61
+ "vitest": "^0.28.5"
73
62
  },
74
63
  "files": [
75
- "dist",
76
- "bin",
77
- "template"
78
- ],
79
- "engines": {
80
- "node": ">=v14"
81
- },
82
- "prettier": {
83
- "tabWidth": 2,
84
- "semi": false,
85
- "singleQuote": true
86
- },
87
- "lint-staged": {
88
- "*.{js,ts}": "eslint --cache --fix",
89
- "*.{js,ts,css,md}": "prettier --write"
90
- }
64
+ "lib",
65
+ "template",
66
+ "chopsticks.js"
67
+ ]
91
68
  }
@@ -13,7 +13,7 @@
13
13
 
14
14
  div#app {
15
15
  margin: 0 !important;
16
- padding: 10px !important;
16
+ padding: 0 !important;
17
17
  }
18
18
 
19
19
  .diff {
@@ -24,6 +24,36 @@
24
24
  line-height: 150%;
25
25
  }
26
26
 
27
+ .diff > button {
28
+ position: absolute;
29
+ display: none;
30
+ left: 50%;
31
+ top: 50%;
32
+ translate: -50% -50%;
33
+ background: #fff;
34
+ border: none;
35
+ border-radius: 50%;
36
+ padding: 10px;
37
+ cursor: pointer;
38
+ cursor: pointer;
39
+ opacity: 80%;
40
+ width: 40px;
41
+ height: 40px;
42
+ }
43
+
44
+ .diff > button > img {
45
+ width: 100%;
46
+ height: 100%;
47
+ }
48
+
49
+ .diff > button:hover {
50
+ opacity: 100%;
51
+ }
52
+
53
+ .diff:hover > button {
54
+ display: block;
55
+ }
56
+
27
57
  .diffWrap {
28
58
  position: relative;
29
59
  z-index: 1;
@@ -37,30 +67,36 @@
37
67
 
38
68
  .diffAdd {
39
69
  color: darkseagreen;
70
+ display: inline-flex;
40
71
  }
41
72
 
42
73
  .diffRemove {
43
74
  text-decoration: line-through;
44
75
  text-decoration-thickness: 1px;
45
76
  color: red;
77
+ display: inline-flex;
46
78
  }
47
79
 
48
80
  .diffUpdateFrom {
49
81
  text-decoration: line-through;
50
82
  text-decoration-thickness: 1px;
51
83
  color: red;
84
+ display: inline-flex;
52
85
  }
53
86
 
54
87
  .diffUpdateTo {
55
88
  color: darkseagreen;
89
+ display: inline-flex;
56
90
  }
57
91
 
58
92
  .diffUpdateArrow {
59
93
  color: #ccc;
60
94
  }
95
+
61
96
  .unchanged {
62
97
  color: #666;
63
98
  }
99
+
64
100
  .delta {
65
101
  color: #ccc;
66
102
  font-size: 12px;
@@ -94,76 +130,82 @@
94
130
  return { className: className.join(' ') }
95
131
  }
96
132
 
97
- function valueRenderer(raw, value, ...keys) {
98
- const modifyPath = keys.reverse().join('.')
99
- const removePath = keys.map(x => Number.isInteger(parseInt(x)) ? '_' + x : x).join('.')
100
- const isDelta = _.has(delta, modifyPath) || _.has(delta, removePath)
133
+ function valueRenderer(viewPartial) {
134
+ return function (raw, value, ...keys) {
135
+ const modifyPath = keys.reverse().join('.')
136
+ const removePath = keys.map(x => Number.isInteger(parseInt(x)) ? '_' + x : x).join('.')
137
+ const isDelta = _.has(delta, modifyPath) || _.has(delta, removePath)
101
138
 
102
- function renderSpan(name, body) {
103
- return (
104
- <span key={name} {...styling(['diff', name])}>
105
- {body}
106
- </span>
107
- );
108
- }
139
+ function renderSpan(name, body, raw) {
140
+ return (
141
+ <span key={name} {...styling(['diff', name])}>
142
+ {body}
143
+ {_.isObjectLike(raw) ? <button onClick={() => viewPartial({ [modifyPath]: raw })}><img src='data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjY0cHgiIHdpZHRoPSI2NHB4IiB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjQyLjEzMyAyNDIuMTMzIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHJva2U9IiMwMDAwMDAiPgoNPGcgaWQ9IlNWR1JlcG9fYmdDYXJyaWVyIiBzdHJva2Utd2lkdGg9IjAiLz4KDTxnIGlkPSJTVkdSZXBvX3RyYWNlckNhcnJpZXIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgoNPGcgaWQ9IlNWR1JlcG9faWNvbkNhcnJpZXIiPiA8ZyBpZD0iWE1MSURfMjVfIj4gPHBhdGggaWQ9IlhNTElEXzI2XyIgZD0iTTg5LjI0NywxMzEuNjczbC00Ny43MzIsNDcuNzNsLTE1LjkwOS0xNS45MWMtNC4yOS00LjI5MS0xMC43NDItNS41NzItMTYuMzQ3LTMuMjUyIEMzLjY1NCwxNjIuNTYzLDAsMTY4LjAzMywwLDE3NC4xdjUzLjAzMmMwLDguMjg0LDYuNzE2LDE1LDE1LDE1bDUzLjAzMywwLjAwMWMwLjAwNy0wLjAwMSwwLjAxMi0wLjAwMSwwLjAxOSwwIGM4LjI4NSwwLDE1LTYuNzE2LDE1LTE1YzAtNC4zNzctMS44NzUtOC4zMTYtNC44NjUtMTEuMDU5bC0xNS40NTgtMTUuNDU4bDQ3LjczLTQ3LjcyOWM1Ljg1OC01Ljg1OCw1Ljg1OC0xNS4zNTUsMC0yMS4yMTMgQzEwNC42MDMsMTI1LjgxNSw5NS4xMDQsMTI1LjgxNiw4OS4yNDcsMTMxLjY3M3oiLz4gPHBhdGggaWQ9IlhNTElEXzI4XyIgZD0iTTIyNy4xMzMsMEgxNzQuMWMtNi4wNjcsMC0xMS41MzYsMy42NTUtMTMuODU4LDkuMjZjLTIuMzIxLDUuNjA1LTEuMDM4LDEyLjA1NywzLjI1MiwxNi4zNDdsMTUuOTExLDE1LjkxMSBsLTQ3LjcyOSw0Ny43M2MtNS44NTgsNS44NTgtNS44NTgsMTUuMzU1LDAsMjEuMjEzYzIuOTI5LDIuOTI5LDYuNzY4LDQuMzkzLDEwLjYwNiw0LjM5M2MzLjgzOSwwLDcuNjc4LTEuNDY0LDEwLjYwNi00LjM5NCBsNDcuNzMtNDcuNzNsMTUuOTA5LDE1LjkxYzIuODY5LDIuODcsNi43MDYsNC4zOTQsMTAuNjA5LDQuMzk0YzEuOTMzLDAsMy44ODItMC4zNzMsNS43MzctMS4xNDIgYzUuNjA1LTIuMzIyLDkuMjYtNy43OTIsOS4yNi0xMy44NThWMTVDMjQyLjEzMyw2LjcxNiwyMzUuNDE3LDAsMjI3LjEzMywweiIvPiA8L2c+IDwvZz4KDTwvc3ZnPg==' /></button> : null}
144
+ </span>
145
+ );
146
+ }
109
147
 
110
- function renderDelta(value) {
111
- if (/^\d+(,\d+)*$/.test(value[0]) && /^\d+(,\d+)*$/.test(value[1])) {
112
- const oldValue = parseInt(value[0].replace(/,/g, ''))
113
- const newValue = parseInt(value[1].replace(/,/g, ''))
114
- if (oldValue > 0 && newValue > 0) {
115
- const delta = Number(newValue - oldValue)
116
- return (<span className="delta" >{delta > 0 ? '+' : ''}{delta.toLocaleString()}</span>)
148
+ function renderDelta(value) {
149
+ if (/^\d+(,\d+)*$/.test(value[0]) && /^\d+(,\d+)*$/.test(value[1])) {
150
+ const oldValue = parseInt(value[0].replace(/,/g, ''))
151
+ const newValue = parseInt(value[1].replace(/,/g, ''))
152
+ if (oldValue > 0 && newValue > 0) {
153
+ const delta = Number(newValue - oldValue)
154
+ return (<span className="delta" >{delta > 0 ? '+' : ''}{delta.toLocaleString()}</span>)
155
+ }
117
156
  }
118
157
  }
119
- }
120
158
 
121
- if (isDelta && Array.isArray(value)) {
122
- switch (value.length) {
123
- case 0:
124
- return (
125
- <span {...styling('diffWrap')}>
126
- {renderSpan('diff', '[]')}
127
- </span>
128
- )
129
- case 1:
130
- return (
131
- <span {...styling('diffWrap')}>
132
- {renderSpan(
133
- 'diffAdd',
134
- stringifyAndShrink(value[0])
135
- )}
136
- </span>
137
- );
138
- case 2:
139
- return (
140
- <span {...styling('diffWrap')}>
141
- {renderSpan(
142
- 'diffUpdateFrom',
143
- stringifyAndShrink(value[0])
144
- )}
145
- {renderSpan('diffUpdateArrow', ' => ')}
146
- {renderSpan(
147
- 'diffUpdateTo',
148
- stringifyAndShrink(value[1])
149
- )}
150
- {renderDelta(value)}
151
- </span>
152
- );
153
- case 3:
154
- return (
155
- <span {...styling('diffWrap')}>
156
- {renderSpan('diffRemove', stringifyAndShrink(value[0]))}
157
- </span>
158
- );
159
+ if (isDelta && Array.isArray(value)) {
160
+ switch (value.length) {
161
+ case 0:
162
+ return (
163
+ <span {...styling('diffWrap')}>
164
+ {renderSpan('diff', '[]')}
165
+ </span>
166
+ )
167
+ case 1:
168
+ return (
169
+ <span {...styling('diffWrap')}>
170
+ {renderSpan(
171
+ 'diffAdd',
172
+ stringifyAndShrink(value[0]),
173
+ value[0]
174
+ )}
175
+ </span>
176
+ );
177
+ case 2:
178
+ return (
179
+ <span {...styling('diffWrap')}>
180
+ {renderSpan(
181
+ 'diffUpdateFrom',
182
+ stringifyAndShrink(value[0]),
183
+ value[0]
184
+ )}
185
+ {renderSpan('diffUpdateArrow', ' => ')}
186
+ {renderSpan(
187
+ 'diffUpdateTo',
188
+ stringifyAndShrink(value[1]),
189
+ value[1]
190
+ )}
191
+ {renderDelta(value)}
192
+ </span>
193
+ );
194
+ case 3:
195
+ return (
196
+ <span {...styling('diffWrap')}>
197
+ {renderSpan('diffRemove', stringifyAndShrink(value[0]), value[0])}
198
+ </span>
199
+ );
200
+ }
159
201
  }
160
- }
161
202
 
162
- return (
163
- <span {...styling('diffWrap')}>
164
- {renderSpan('unchanged', stringifyAndShrink(value))}
165
- </span>
166
- );
203
+ return (
204
+ <span {...styling('diffWrap')}>
205
+ {renderSpan('unchanged', stringifyAndShrink(value), value)}
206
+ </span>
207
+ );
208
+ }
167
209
  };
168
210
 
169
211
  function prepareDelta(value) {
@@ -208,30 +250,49 @@
208
250
  class App extends React.Component {
209
251
  constructor(props) {
210
252
  super(props);
211
- this.state = { showUnchanged: false };
253
+ this.state = { showUnchanged: false, partial: null };
212
254
  }
213
255
 
214
256
  toggle = (e) => {
215
257
  this.setState(state => {
216
- return { showUnchanged: !state.showUnchanged }
258
+ return { ...state, showUnchanged: !state.showUnchanged }
259
+ })
260
+ }
261
+
262
+ viewPartial = (value) => {
263
+ this.setState(state => {
264
+ return { ...state, partial: _.isEqual(state.partial, value) ? null : value }
217
265
  })
218
266
  }
219
267
 
220
268
  render() {
221
269
  return (
222
270
  <div>
223
- <input type="checkbox" onChange={this.toggle} id="show_unchanged" />
224
- <label for="show_unchanged" style={{fontSize: '12px', color: 'white'}}>Show Unchanged</label>
225
- <ReactJsonTree.JSONTree
226
- theme={theme}
227
- invertTheme={false}
228
- data={this.state.showUnchanged ? _.merge(_.cloneDeep(left), delta): delta}
229
- valueRenderer={valueRenderer}
230
- postprocessValue={prepareDelta}
231
- isCustomNode={Array.isArray}
232
- shouldExpandNodeInitially={expandFirstLevel}
233
- hideRoot
234
- />
271
+ <div style={{ display: 'flex', flexDirection: 'row' }}>
272
+ <div style={{ flex: 1, padding: '0 10px', overflow: 'hidden', overflowY: 'scroll', height: '100vh' }}>
273
+ <input type="checkbox" onChange={this.toggle} id="show_unchanged" />
274
+ <label for="show_unchanged" style={{ fontSize: '12px', color: 'white' }}>Show Unchanged</label>
275
+ <ReactJsonTree.JSONTree
276
+ theme={theme}
277
+ invertTheme={false}
278
+ data={this.state.showUnchanged ? _.merge(_.cloneDeep(left), delta) : delta}
279
+ valueRenderer={valueRenderer(this.viewPartial)}
280
+ postprocessValue={prepareDelta}
281
+ isCustomNode={Array.isArray}
282
+ shouldExpandNodeInitially={expandFirstLevel}
283
+ hideRoot
284
+ />
285
+ </div>
286
+ {this.state.partial ? <div style={{ flex: 1, padding: '0 10px', overflow: 'hidden', overflowY: 'scroll', height: '100vh' }}>
287
+ <ReactJsonTree.JSONTree
288
+ theme={theme}
289
+ invertTheme={false}
290
+ data={this.state.partial}
291
+ shouldExpandNodeInitially={() => true}
292
+ hideRoot
293
+ />
294
+ </div> : null}
295
+ </div>
235
296
  </div>
236
297
  );
237
298
  }