Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storybook): add storybook-react-i18next addon #10234

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .storybook/babel-storybook-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const babelConfig = {
import { TransformOptions } from "@babel/core"

export const babelConfig: TransformOptions = {
sourceType: "unambiguous",
presets: [
[
Expand Down
41 changes: 41 additions & 0 deletions .storybook/i18next.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import i18n, { Resource } from "i18next"
import { initReactI18next } from "gatsby-plugin-react-i18next"

export const baseLocales = {
en: { title: "English", left: "En" },
zh: { title: "中国人", left: "Zh" },
ru: { title: "Русский", left: "Ru" },
uk: { title: "українська", left: "Uk" },
}

// Only i18n files named in this array are being exposed to Storybook. Add filenames as necessary.
const ns = ["common", "page-about", "page-upgrades", "page-developers-index"]
const supportedLngs = Object.keys(baseLocales)

/**
* Taking the ns array and combining all the ids
* under a single ns per language, set to the default of "translation"
*/
const resources: Resource = ns.reduce((acc, n) => {
supportedLngs.forEach((lng) => {
if (!acc[lng]) acc[lng] = {}
acc[lng] = {
translation: {
...acc[lng].translation,
...require(`../src/intl/${lng}/${n}.json`),
},
}
})
return acc
}, {})

i18n.use(initReactI18next).init({
debug: true,
fallbackLng: "en",
interpolation: { escapeValue: false },
react: { useSuspense: false },
supportedLngs,
resources,
})

export default i18n
53 changes: 28 additions & 25 deletions .storybook/main.js → .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const { propNames } = require("@chakra-ui/react")
import { StorybookConfig } from "@storybook/react-webpack5"
import { propNames } from "@chakra-ui/react"
import { babelConfig } from "./babel-storybook-config"

const { babelConfig } = require("./babel-storybook-config")

module.exports = {
const config: StorybookConfig = {
stories: ["../src/components/**/*.stories.tsx"],
addons: [
"@storybook/addon-links",
Expand All @@ -11,9 +11,10 @@ module.exports = {
// https://storybook.js.org/addons/@storybook/addon-a11y/
"@storybook/addon-a11y",
"@chakra-ui/storybook-addon",
"storybook-react-i18next",
],
staticDirs: ["../static"],
babel: async (options) => ({
babel: async () => ({
...babelConfig,
}),
framework: {
Expand All @@ -27,30 +28,30 @@ module.exports = {
},
features: {},
webpackFinal: async (config) => {
const isRuleExist =
config.module && config.module.rules && config.module.rules.length
if (isRuleExist) {
// Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
config.module.rules[0].exclude = [
/node_modules\/(?!(gatsby|gatsby-script)\/)/,
]

// Remove core-js to prevent issues with Storybook
config.module.rules[0].exclude = [/core-js/]
}

if (
isRuleExist &&
config.module.rules[0].use &&
config.module.rules[0].use.length
config.module != undefined &&
config.module.rules != undefined &&
config.module.rules[0] !== "..."
) {
// Use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
config.module.rules[0].use[0].options.plugins.push(
require.resolve("babel-plugin-remove-graphql-queries")
)
config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
config.module.rules[0].use = [
{
loader: require.resolve("babel-loader"),
options: {
presets: [
// use @babel/preset-react for JSX and env (instead of staged presets)
require.resolve("@babel/preset-react"),
require.resolve("@babel/preset-env"),
],
plugins: [
// use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
require.resolve("babel-plugin-remove-graphql-queries"),
],
},
},
]
}

config.resolve.mainFields = ["browser", "module", "main"]
return config
},
typescript: {
Expand Down Expand Up @@ -83,3 +84,5 @@ module.exports = {
},
},
}

export default config
75 changes: 40 additions & 35 deletions .storybook/preview.js → .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Preview } from "@storybook/react"
import { action } from "@storybook/addon-actions"

import i18n, { baseLocales } from "./i18next"
import theme from "../src/@chakra-ui/gatsby-plugin/theme"

import "../static/fonts/inter-font-face.css"
import "../static/fonts/ibm-plex-font-face.css"

const chakraBreakpointArray = Object.entries(theme.breakpoints)

// Gatsby's Link overrides:
Expand All @@ -26,42 +25,48 @@ window.___navigate = (pathname) => {
action("NavigateTo:")(pathname)
}

export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
backgrounds: {
disable: true,
const preview: Preview = {
globals: {
locale: "en",
locales: baseLocales,
},
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
parameters: {
i18n,
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
backgrounds: {
disable: true,
},
chakra: {
theme,
},
layout: "centered",
// Modify viewport selection to match Chakra breakpoints (or custom breakpoints)
viewport: {
viewports: chakraBreakpointArray.reduce((prevVal, currVal) => {
const [token, key] = currVal
backgrounds: {
disable: true,
},
chakra: {
theme,
},
layout: "centered",
// Modify viewport selection to match Chakra breakpoints (or custom breakpoints)
viewport: {
viewports: chakraBreakpointArray.reduce((prevVal, currVal) => {
const [token, key] = currVal

// Unnecessary breakpoint
if (token === "base") return { ...prevVal }
// Unnecessary breakpoint
if (token === "base") return { ...prevVal }

return {
...prevVal,
[token]: {
name: token,
styles: {
width: key,
height: "600px",
return {
...prevVal,
[token]: {
name: token,
styles: {
width: key,
height: "600px",
},
},
},
}
}, {}),
}
}, {}),
},
},
}

export default preview
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
"pretty-quick": "^3.1.0",
"rimraf": "^4.1.1",
"storybook": "^7.0.6",
"storybook-react-i18next": "^2.0.1",
"ts-node": "^10.9.1",
"typescript": "^4.6.3",
"walkdir": "^0.4.1"
Expand Down
38 changes: 15 additions & 23 deletions src/components/BannerNotification/BannerNotification.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
import { Meta, StoryObj } from "@storybook/react"
import React from "react"
import { Text } from "@chakra-ui/react"
import { Meta, StoryFn } from "@storybook/react"
import { useTranslation } from "react-i18next"
import BannerNotification from "."

export default {
component: BannerNotification,
args: {
shouldShow: true,
},
decorators: [(Story) => <Story />],
} as Meta<typeof BannerNotification>

/**
* Story taken from PostMergeBanner component
* and content from `../../content/developers/tutorials/hello-world-smart-contract-fullstack/index.md`
*/
export const PostMergeBanner: StoryObj<typeof BannerNotification> = {
args: {
shouldShow: true,
justify: "center",
textAlign: "center",
sx: {
"& p": {
maxWidth: "100ch",
m: 0,
p: 0,
},
"& a": {
textDecor: "underline",
},
},
children: (
<p>
This tutorial is out of date after the merge and may not work. Please
raise a PR if you would like to contribute.
</p>
),
},
export const PostMergeBanner: StoryFn<typeof BannerNotification> = (args) => {
const { t } = useTranslation()

return (
<BannerNotification {...args}>
<Text m={0}>{t("page-upgrades-post-merge-banner-tutorial-ood")}</Text>
</BannerNotification>
)
}
27 changes: 16 additions & 11 deletions src/components/Card/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react"
import { Box } from "@chakra-ui/react"
import { Meta, StoryFn } from "@storybook/react"
import React from "react"
import { useTranslation } from "react-i18next"
import Card, { IProps } from "."
import Button from "../Button"

Expand All @@ -17,14 +18,18 @@ export default {
],
} as Meta<typeof Component>

const defaultProps: IProps = {
emoji: ":woman_student:",
title: "Learn Ethereum development",
description: "Read up on core concepts and the Ethereum stack with our docs",
}
export const Default: StoryFn<typeof Component> = (args) => {
const { t } = useTranslation()

export const Default: StoryFn<typeof Component> = (args) => (
<Component {...defaultProps} {...args}>
<Button>Read the docs</Button>
</Component>
)
const defaultProps: IProps = {
emoji: ":woman_student:",
title: t("page-developers-learn"),
description: t("page-developers-learn-desc"),
}

return (
<Component {...defaultProps} {...args}>
<Button>{t("page-developers-read-docs")}</Button>
</Component>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,29 @@ More on [nodes and clients](/developers/docs/nodes-and-clients/)

Ethereum nodes store their own full or partial copy of the Ethereum blockchain. This local copy is used to validate transactions and ensure the node is following the correct chain. This locally stored data allows nodes to independently verify that incoming data is valid and correct without needing to trust any other entity.

This local copy of the blockchain and associated state and receipt data takes up a lot of space on the node's hard disk. For example, a 2TB hard disk is recommended for running a node using [Geth](https://geth.ethereum.org) paired to a consensus client. Using snap sync, which only stores chain data from a relatively recent set of blocks, Geth typically occupies about 650GB of disk space but grows at around 14GB/week (you can prune the node back down to 650GB periodically).
This local copy of the blockchain and associated state and receipt data takes up a lot of space on the node's hard disk. For example, a 2TB hard disk is recommended for running a node using [Geth](https://geth.ethereum.org) paired to a consensus client. Using snap sync, which only stores chain data from a relatively recent set of blocks, Geth typically occupies about 650GB of disk space but grows at around 14GB/week (you can prune the node back down to 650GB periodically).

This means running nodes can be expensive, because a large amount of disk space has to be dedicated to Ethereum. There are several solutions to this problem on the Ethereum roadmap, including [history expiry](/roadmap/statelessness/#history-expiry), [state expiry](/roadmap/statelessness/#state-expiry) and [statelessness](/roadmap/statelessness/). However, these are likely several years away from being implemented. There are also [light nodes](/developers/docs/nodes-and-clients/light-clients/) that do not save their own copy of the chain data, they request the data they need from full nodes. However, this means light nodes have to trust full nodes to provide honest data and also stresses the full nodes that have to serve the data the light nodes need.

The Portal Network aims to provide an alternative way for light nodes to get their data that does not require trusting or adding significantly to the work that has to be done by full nodes. The way this will be done is to introduce a new way for Ethereum nodes to share data across the network.

## How does the Portal Network work? {#how-does-portal-network-work}

Ethereum nodes have strict protocols that define how they communicate with each other. Execution clients communicate using a set of subprotocols known as [DevP2P](developers/docs/networking-layer/#devp2p), while consensus clients use a different stack of subprotocols called [libP2P](/developers/docs/networking-layer/#libp2p). These define the types of data that can be passed between nodes.
Ethereum nodes have strict protocols that define how they communicate with each other. Execution clients communicate using a set of subprotocols known as [DevP2P](developers/docs/networking-layer/#devp2p), while consensus clients use a different stack of subprotocols called [libP2P](/developers/docs/networking-layer/#libp2p). These define the types of data that can be passed between nodes.

![devP2P and libP2P](portal-network-devp2p-libp2p.png)

Nodes can also serve specific data through the [JSON-RPC API](/developers/docs/apis/json-rpc/), which is how apps and wallets swap information with Ethereum nodes. However, none of these are ideal protocols for serving data to light clients.
Nodes can also serve specific data through the [JSON-RPC API](/developers/docs/apis/json-rpc/), which is how apps and wallets swap information with Ethereum nodes. However, none of these are ideal protocols for serving data to light clients.

Light clients can't currently request specific pieces of chain data over DevP2P or libP2p because those protocols are only designed to enable chain synchronization and gossiping of blocks and transactions. Light clients do not want to download this information because that would stop them from being "light".

The JSON-RPC API is not an ideal choice for light client data requests either, because it relies upon a connection to a specific full node or centralized RPC provider that can serve the data. This means the light client has to trust that specific node/provider to be honest, and also the full node might have to handle lots of requests from many light clients, adding to their bandwidth requirements.

The point of the Portal Network is to rethink the whole design, building specifically for lightness, outside of the design constraints of the existing Ethereum clients.


The core idea of the Portal Network is to take the best bits of the current networking stack by enabling information needed by light clients, such as historical data and the identity of the current head of the chain to be served through a lightweight DevP2P style peer-to-peer decentralized network using a [DHT](https://en.wikipedia.org/wiki/Distributed_hash_table) (similar to Bittorrent).

The idea is to add small parts of the total historical Ethereum data and some specific node responsibilities to each node. Then, requests are served by seeking out the nodes storing the specific data that was requested and retrieving it from them.
The idea is to add small parts of the total historical Ethereum data and some specific node responsibilities to each node. Then, requests are served by seeking out the nodes storing the specific data that was requested and retrieving it from them.

This inverts the normal model of light nodes finding a single node and requesting them to filter and serve large volumes of data; instead, they quickly filter a large network of nodes that each handle small amounts of data.

Expand All @@ -51,7 +50,6 @@ The goal is to allow a decentralized network of lightweight Portal clients to:
- broadcast transactions
- execute transactions using the [EVM](/developers/docs/evm/)


The benefits of this network design are:

- reduce dependence on centralized providers
Expand All @@ -63,8 +61,6 @@ The diagram below shows the functions of existing clients that can be delivered

![portal network table](portal-network-table2.png)



## Client diversity by default {#client-diversity-as-default}

The Portal Network developers also made the design choice to build three separate Portal Network clients from day one.
Expand All @@ -79,7 +75,6 @@ Having multiple independent client implementations enhances the resilience and d

If one client experiences issues or vulnerabilities, other clients can continue to operate smoothly, preventing a single point of failure. Additionally, diverse client implementations foster innovation and competition, driving improvements and reducing monoculture risk within the ecosystem.


## Further reading {#futher-reading}

- [The Portal Network (Piper Merriam at Devcon Bogota)](https://www.youtube.com/watch?v=0stc9jnQLXA).
Expand Down
Loading