Joystream Stats 2 سال پیش
والد
کامیت
2fdd211ccb
5فایلهای تغییر یافته به همراه221 افزوده شده و 107 حذف شده
  1. 46 35
      src/App.tsx
  2. 119 58
      src/components/Events/index.tsx
  3. 1 1
      src/components/Transactions/index.tsx
  4. 1 1
      src/jslib
  5. 54 12
      yarn.lock

+ 46 - 35
src/App.tsx

@@ -2,7 +2,6 @@ import React from "react";
 import "bootstrap/dist/css/bootstrap.min.css";
 import "./index.css";
 import { Modals, Routes, Loading, Footer, Status } from "./components";
-
 import * as get from "./lib/getters";
 import { getTokenomics, queryJstats } from "./lib/queries";
 import { getCouncilApplicants, getCouncilSize, getVotes } from "./lib/election";
@@ -326,46 +325,53 @@ class App extends React.Component<IProps, IState> {
       api.rpc.chain.subscribeFinalizedHeads((header: Header) =>
         this.handleBlock(api, header)
       );
-      this.syncBlocks(api)
+      this.syncBlocks(api);
     });
   }
 
-  async syncBlocks(api:ApiPromise) {
-    const head = this.state.blocks.reduce((max, b) => b.id > max ? b.id : max, 0)
-    console.log(`Syncing block events from ${head}`)
-    let missing = []
-    for (let id = head ; id > 0 ; --id) {
-      if (!this.state.blocks.find(block=> block.id === id)) missing.push(id)
+  async syncBlocks(api: ApiPromise) {
+    const head = this.state.blocks.reduce(
+      (max, b) => (b.id > max ? b.id : max),
+      0
+    );
+    console.log(`Syncing block events from ${head}`);
+    let missing = [];
+    for (let id = head; id > 0; --id) {
+      if (!this.state.blocks.find((block) => block.id === id)) missing.push(id);
     }
-    if (!this.state.syncEvents) return
-    const maxWorkers = 5
-    let slots = []
-    for (let s = 0 ; s < maxWorkers ; ++s) { slots[s] = s }
-    slots.map(async (slot) =>{
+    if (!this.state.syncEvents) return;
+    const maxWorkers = 5;
+    let slots = [];
+    for (let s = 0; s < maxWorkers; ++s) {
+      slots[s] = s;
+    }
+    slots.map(async (slot) => {
       while (this.state.syncEventsl && missing.length) {
-        const id = slot < maxWorkers /2 ? missing.pop() : missing.shift()
-        await this.syncBlock(api, id, slot)
+        const id = slot < maxWorkers / 2 ? missing.pop() : missing.shift();
+        await this.syncBlock(api, id, slot);
       }
-      console.debug(`Slot ${slot} idle.`)
-      return true
-    })
+      console.debug(`Slot ${slot} idle.`);
+      return true;
+    });
   }
 
-  async syncBlock(api:ApiPromise, id: number, slot: number) {
-     try {
+  async syncBlock(api: ApiPromise, id: number, slot: number) {
+    try {
       const hash = await getBlockHash(api, id);
-      const events = (await getEvents(api, hash)).map((e) => {
-        const { section, method, data } = e.event;
-        return { blockId: id, section, method, data: data.toHuman() };
-      }).filter(e=> e.method !== 'ExtrinsicSuccess')
+      const events = (await getEvents(api, hash))
+        .map((e) => {
+          const { section, method, data } = e.event;
+          return { blockId: id, section, method, data: data.toHuman() };
+        })
+        .filter((e) => e.method !== "ExtrinsicSuccess");
       const timestamp = (await api.query.timestamp.now.at(hash)).toNumber();
       //const duration = 6000 // TODO update later
       const block = { id, timestamp, events };
       console.debug(`worker ${slot}: synced block`, block);
       this.save("blocks", this.state.blocks.concat(block));
-     } catch (e) {
-      console.error(`Failed to get block ${id}: ${e.message}`)
-     }
+    } catch (e) {
+      console.error(`Failed to get block ${id}: ${e.message}`);
+    }
   }
 
   save(key: string, data: any) {
@@ -376,8 +382,8 @@ class App extends React.Component<IProps, IState> {
     } catch (e) {
       const size = value.length / 1024;
       console.warn(`Failed to save ${key} (${size.toFixed()} KB)`, e.message);
-      if (key === 'blocks') this.load(key)
-      else this.setState({syncEvents:false})
+      if (key === "blocks") this.load(key);
+      else this.setState({ syncEvents: false });
     }
     return data;
   }
@@ -385,15 +391,20 @@ class App extends React.Component<IProps, IState> {
   load(key: string) {
     try {
       const data = localStorage.getItem(key);
-      if (!data) return console.debug(`loaded empty`, key);
+      if (!data) return; //console.debug(`loaded empty`, key);
       const size = data.length;
       if (size > 10240)
         console.debug(` -${key}: ${(size / 1024).toFixed(1)} KB`);
-	let loaded = JSON.parse(data)
-	if (key === 'blocks') loaded = loaded.map(({id,timestamp,events}) => {
-         return {id,timestamp,events: events.filter(e=> e.method !== 'ExtrinsicSuccess')}
-	})
-      this.setState({ [key]: loaded  });
+      let loaded = JSON.parse(data);
+      if (key === "blocks")
+        loaded = loaded.map(({ id, timestamp, events }) => {
+          return {
+            id,
+            timestamp,
+            events: events.filter((e) => e.method !== "ExtrinsicSuccess"),
+          };
+        });
+      this.setState({ [key]: loaded });
     } catch (e) {
       console.warn(`Failed to load ${key}`, e);
     }

+ 119 - 58
src/components/Events/index.tsx

@@ -1,86 +1,147 @@
 import { useState, useMemo } from "react";
 import { Button } from "react-bootstrap";
 import { IState } from "../../types";
-import Day from './Day'
-import moment from 'moment'
+import Day from "./Day";
+import moment from "moment";
 
 interface IProps extends IState {
   blocks: { id: number; events: any }[];
 }
 
 const getMethodsAndSections = (blocks) => {
-  const sections = []
-  const methods = []
-  blocks.forEach(block=> block.events?.forEach(event => {
-    if (!sections.includes(event.section)) sections.push(event.section)
-    if (!methods.includes(event.method)) methods.push(event.method)
-  }))
-  return [sections, methods]
-}
+  const sections = [];
+  const methods = [];
+  blocks.forEach((block) =>
+    block.events?.forEach((event) => {
+      if (!sections.includes(event.section)) sections.push(event.section);
+      if (!methods.includes(event.method)) methods.push(event.method);
+    })
+  );
+  return [sections, methods];
+};
 
 const applyFilter = (event, filter) => {
-    if (!filter.length) return true
-    if (event.section.includes(filter) || event.method.includes(filter)) return true
-    if (JSON.stringify(event.data).includes(filter)) return true
-    return false
-}
+  if (!filter.length) return true;
+  if (event.section.includes(filter) || event.method.includes(filter))
+    return true;
+  if (JSON.stringify(event.data).includes(filter)) return true;
+  return false;
+};
 
-const filterBlocks = (blocks, filter, hidden) => blocks.filter((b) => b.timestamp > 164804000000)
-    .filter(b=> b.events?.filter(e=> !hidden.includes(e.section) && !hidden.includes(e.method) && applyFilter(e, filter)).length)
-    .sort((a, b) => b.id - a.id)
+const filterBlocks = (blocks, filter, hidden) =>
+  blocks
+    .filter((b) => b.timestamp > 164804000000)
+    .filter(
+      (b) =>
+        b.events?.filter(
+          (e) =>
+            !hidden.includes(e.section) &&
+            !hidden.includes(e.method) &&
+            applyFilter(e, filter)
+        ).length
+    )
+    .sort((a, b) => b.id - a.id);
 
 const getDays = (blocks) => {
-  const days = {}
-  blocks.forEach(b => {
-    const day = moment(b.timestamp).format('MMM D YYYY')
-    if (!days[day]) days[day] = []
-    days[day].push(b)
-  })
-  return days
-}
+  const days = {};
+  blocks.forEach((b) => {
+    const day = moment(b.timestamp).format("MMM D YYYY");
+    if (!days[day]) days[day] = [];
+    days[day].push(b);
+  });
+  return days;
+};
 
 const Events = (props: IProps) => {
   //console.debug(`hidden event sections and methods`, props.hidden)
-  const [hidden,setHidden] = useState(props.hidden)
-  const [filter,setFilter] = useState('')
-  const { blocks, save, selectEvent } = props;
-  const head = blocks.reduce((max, b)=> b.id > max ? b.id : max, 0)
+  const [hidden, setHidden] = useState(props.hidden);
+  const [filter, setFilter] = useState("");
+  const { blocks, save } = props;
+  const head = blocks.reduce((max, b) => (b.id > max ? b.id : max), 0);
 
-  const [sections, methods] = useMemo(() => getMethodsAndSections(blocks), [blocks])
-  const filteredBlocks = useMemo(() => filterBlocks(blocks, filter, hidden), [blocks, filter, hidden])
-  const days = useMemo(() => getDays(filteredBlocks), [filteredBlocks])
+  const [sections, methods] = useMemo(
+    () => getMethodsAndSections(blocks),
+    [blocks]
+  );
+  const filteredBlocks = useMemo(
+    () => filterBlocks(blocks, filter, hidden),
+    [blocks, filter, hidden]
+  );
+  const days = useMemo(() => getDays(filteredBlocks), [filteredBlocks]);
 
-  const handleChange = (e) => setFilter(e.target.value)
+  const handleChange = (e) => setFilter(e.target.value);
   const toggleHide = (item) => {
-     if (hidden.includes(item)) setHidden(save('hidden', hidden.filter(h=> h !== item)))
-     else setHidden(save('hidden',hidden.concat(item)))
-  }
+    if (hidden.includes(item))
+      setHidden(
+        save(
+          "hidden",
+          hidden.filter((h) => h !== item)
+        )
+      );
+    else setHidden(save("hidden", hidden.concat(item)));
+  };
 
   return (
     <div className="text-light p-2">
-    <div className="box text-left m-0">
-      <div className="d-flex flex-row">
-        <b className="col-1">Search</b>
-	<input type='text' name='filter' value={filter} onChange={handleChange} className="col-6 px-1 mb-2" size={50} />
- 	<span className="ml-2">
-	  {blocks.length} of {head} blocks synced.
-	</span>
-      </div>
-      <div className="d-flex flex-row">
-        <b className="col-1">Sections</b>
-        <div className="d-flex flex-wrap">
-          {sections.map((s,i)=> <Button variant={hidden.includes(s) ? 'outline-dark' : 'dark'} className='btn-sm p-1 mr-1 mb-1' key={i} onClick={()=>toggleHide(s)} title={`Click to ${hidden.includes(s) ? `show` : `hide`}`}>{s}</Button>)}
-	</div>
-      </div>
-      <div className="d-flex flex-row">
-        <b className="col-1">Methods</b>
-	<div className="d-flex flex-wrap">
-          {methods.map((m,i)=> <Button variant={hidden.includes(m) ? 'outline-dark' : 'dark'} className='btn-sm p-1 mr-1 mb-1' key={i} onClick={()=>toggleHide(m)} title={`Click to ${hidden.includes(m) ? `show` : `hide`}`}>{m}</Button>)}
-	</div>
+      <div className="box text-left m-0">
+        <div className="d-flex flex-row">
+          <b className="col-1">Search</b>
+          <input
+            type="text"
+            name="filter"
+            value={filter}
+            onChange={handleChange}
+            className="col-6 px-1 mb-2"
+            size={50}
+          />
+          <span className="ml-2">
+            {blocks.length} of {head} blocks synced.
+          </span>
+        </div>
+        <div className="d-flex flex-row">
+          <b className="col-1">Sections</b>
+          <div className="d-flex flex-wrap">
+            {sections.map((s, i) => (
+              <Button
+                variant={hidden.includes(s) ? "outline-dark" : "dark"}
+                className="btn-sm p-1 mr-1 mb-1"
+                key={i}
+                onClick={() => toggleHide(s)}
+                title={`Click to ${hidden.includes(s) ? `show` : `hide`}`}
+              >
+                {s}
+              </Button>
+            ))}
+          </div>
+        </div>
+        <div className="d-flex flex-row">
+          <b className="col-1">Methods</b>
+          <div className="d-flex flex-wrap">
+            {methods.map((m, i) => (
+              <Button
+                variant={hidden.includes(m) ? "outline-dark" : "dark"}
+                className="btn-sm p-1 mr-1 mb-1"
+                key={i}
+                onClick={() => toggleHide(m)}
+                title={`Click to ${hidden.includes(m) ? `show` : `hide`}`}
+              >
+                {m}
+              </Button>
+            ))}
+          </div>
+        </div>
       </div>
-     </div>
 
-     {Object.keys(days).map((day) => <Day key={day} day={day} applyFilter={applyFilter} filter={filter} blocks={days[day]} hidden={hidden} />)}
+      {Object.keys(days).map((day) => (
+        <Day
+          key={day}
+          day={day}
+          applyFilter={applyFilter}
+          filter={filter}
+          blocks={days[day]}
+          hidden={hidden}
+        />
+      ))}
     </div>
   );
 };

+ 1 - 1
src/components/Transactions/index.tsx

@@ -3,7 +3,7 @@ import { Form, Table } from "react-bootstrap";
 import axios from "axios";
 
 import { alternativeBackendApis } from "../../config";
-import { mJoy } from "../../lib/util";
+//import { mJoy } from "../../lib/util";
 import { Transaction } from "../../types";
 
 interface IProps {}

+ 1 - 1
src/jslib

@@ -1 +1 @@
-Subproject commit 18fd8a36a734fc1a6711613fc52813f0cb11fe3e
+Subproject commit 6aa2fe5625a5dc0e7efa5c1578268f74080b1aa8

+ 54 - 12
yarn.lock

@@ -5263,7 +5263,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
   dependencies:
     once "^1.4.0"
 
-enhanced-resolve@^4.3.0:
+enhanced-resolve@^4.3.0, enhanced-resolve@^4.5.0:
   version "4.5.0"
   resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz"
   integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==
@@ -8268,7 +8268,7 @@ lodash.uniq@^4.5.0:
   resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz"
   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
 
-"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, lodash@^4.7.0:
+"lodash@>=3.5 <5", lodash@>=4.17.11, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, lodash@^4.7.0:
   version "4.17.21"
   resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -8798,16 +8798,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
   resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
   integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
 
-moment@^2.0.0, moment@^2.24.0:
+moment@^2.0.0, moment@^2.24.0, moment@^2.29.1:
   version "2.29.1"
   resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
   integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
 
-moment@^2.29.1:
-  version "2.29.1"
-  resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
-  integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
-
 move-concurrently@^1.0.1:
   version "1.0.1"
   resolved "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz"
@@ -10658,6 +10653,15 @@ react-calendar-timeline@^0.27.0:
     lodash.isequal "^4.5.0"
     memoize-one "^5.1.1"
 
+react-chart-histogram@^0.2.4:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/react-chart-histogram/-/react-chart-histogram-0.2.4.tgz#9f4d7e56d5900b09d7cef22fa09b5066c7f280a1"
+  integrity sha512-/6FIOClOzgi8RjxDFOVdEMXP+gjDl4oXqTh6G21QNUv7D6MZxtXTq73e6bRTNvaRqDuQQ8iz6LYdKv0PGl1X8g==
+  dependencies:
+    lodash ">=4.17.11"
+    react "^16.4.0"
+    webpack "^4.12.0"
+
 react-dev-utils@^11.0.1:
   version "11.0.4"
   resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz"
@@ -10927,6 +10931,15 @@ react-transition-group@^4.4.0, react-transition-group@^4.4.1:
     loose-envify "^1.4.0"
     prop-types "^15.6.2"
 
+react@^16.4.0:
+  version "16.14.0"
+  resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
+  integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+    prop-types "^15.6.2"
+
 react@^17.0.1:
   version "17.0.2"
   resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
@@ -13042,10 +13055,10 @@ vfile@^4.0.0:
     unist-util-stringify-position "^2.0.0"
     vfile-message "^2.0.0"
 
-video-react@^0.14.1:
-  version "0.14.1"
-  resolved "https://registry.npmjs.org/video-react/-/video-react-0.14.1.tgz"
-  integrity sha512-R5ClJo58iJcQLS+bGNmuAMc/fx9/xcJ6oLrAlbuu7MGI49Jh7b7o79aUdQMZvzuynT1NvhVmD4N/fTOEmWNDlg==
+video-react@^0.15.0:
+  version "0.15.0"
+  resolved "https://registry.yarnpkg.com/video-react/-/video-react-0.15.0.tgz#82794a0f862e08c5f3ac2660747360f5ecc735cb"
+  integrity sha512-wF3BwG1qikkSX11nu0KsygxeWehzMaYpd4Uvy1sKLFnCNk794f9TPL4q/+mMmLJ8uYb5DSlgg6VraTHyihiMHQ==
   dependencies:
     "@babel/runtime" "^7.4.5"
     classnames "^2.2.6"
@@ -13236,6 +13249,35 @@ webpack@4.44.2:
     watchpack "^1.7.4"
     webpack-sources "^1.4.1"
 
+webpack@^4.12.0:
+  version "4.46.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542"
+  integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==
+  dependencies:
+    "@webassemblyjs/ast" "1.9.0"
+    "@webassemblyjs/helper-module-context" "1.9.0"
+    "@webassemblyjs/wasm-edit" "1.9.0"
+    "@webassemblyjs/wasm-parser" "1.9.0"
+    acorn "^6.4.1"
+    ajv "^6.10.2"
+    ajv-keywords "^3.4.1"
+    chrome-trace-event "^1.0.2"
+    enhanced-resolve "^4.5.0"
+    eslint-scope "^4.0.3"
+    json-parse-better-errors "^1.0.2"
+    loader-runner "^2.4.0"
+    loader-utils "^1.2.3"
+    memory-fs "^0.4.1"
+    micromatch "^3.1.10"
+    mkdirp "^0.5.3"
+    neo-async "^2.6.1"
+    node-libs-browser "^2.2.1"
+    schema-utils "^1.0.0"
+    tapable "^1.1.3"
+    terser-webpack-plugin "^1.4.3"
+    watchpack "^1.7.4"
+    webpack-sources "^1.4.1"
+
 websocket-driver@0.6.5:
   version "0.6.5"
   resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz"