From 86c46bad9c731fe6e5c0b7f81e5adb1bbc7349e7 Mon Sep 17 00:00:00 2001 From: Andrew Joslin Date: Fri, 3 Sep 2021 11:16:28 -0700 Subject: [PATCH] Add basic flags gui --- .github/workflows/pinata-build-deploy-ui.yml | 3 ++ docs/README.md | 2 +- ui/app/package.json | 2 + ui/app/scripts/vite-polyfills.ts | 24 ++++++++++ ui/app/src/App.vue | 27 ++--------- .../src/assets/icons/interactive/settings.svg | 1 + ui/app/src/components/AssetIcon.tsx | 1 + ui/app/src/components/Flags/Flags.tsx | 46 +++++++++++++++++++ ui/app/src/components/Flags/flagsGui.ts | 30 ++++++++++++ ui/app/src/main.ts | 6 ++- ui/app/src/store/index.ts | 3 ++ ui/app/src/store/modules/flags.ts | 33 +++++++++++++ .../RewardsPage/components/RewardSection.tsx | 3 +- ui/app/vite.config.ts | 30 ++---------- ui/core/src/services/IBCService/IBCService.ts | 4 +- ui/yarn.lock | 10 ++++ 16 files changed, 170 insertions(+), 55 deletions(-) create mode 100644 ui/app/scripts/vite-polyfills.ts create mode 100644 ui/app/src/assets/icons/interactive/settings.svg create mode 100644 ui/app/src/components/Flags/Flags.tsx create mode 100644 ui/app/src/components/Flags/flagsGui.ts create mode 100644 ui/app/src/store/modules/flags.ts diff --git a/.github/workflows/pinata-build-deploy-ui.yml b/.github/workflows/pinata-build-deploy-ui.yml index 2ca90a0f2..432ca40f0 100644 --- a/.github/workflows/pinata-build-deploy-ui.yml +++ b/.github/workflows/pinata-build-deploy-ui.yml @@ -32,12 +32,15 @@ jobs: if [[ $BRANCH_NAME == 'master' ]] then echo "SUBDOMAIN=dex" >> $GITHUB_ENV + echo "VITE_APP_DEPLOYMENT=production" elif [[ $BRANCH_NAME == 'develop' ]] && [[ "$TAG_NAME" != '' ]] then # because testnet is promoted to mainnet echo "SUBDOMAIN=testnet" >> $GITHUB_ENV + echo "VITE_APP_DEPLOYMENT=staging" else echo "SUBDOMAIN=devnet" >> $GITHUB_ENV + echo "VITE_APP_DEPLOYMENT=develop" fi - name: Build App diff --git a/docs/README.md b/docs/README.md index 1feef7527..be1685a38 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,7 +26,7 @@ First of all you need is Keplr / Metamask installed. Generate a wallet for each Run the yarn commands, pointed at devnet. ``` -export VUE_APP_DEPLOYMENT_TAG=devnet +export VUE_APP_DEPLOYMENT=develop export VUE_APP_ETHEREUM_ASSET_TAG=ethereum.mainnet export VUE_APP_SIFCHAIN_ASSET_TAG=sifchain.mainnet diff --git a/ui/app/package.json b/ui/app/package.json index f41d80b74..dd9dc486d 100644 --- a/ui/app/package.json +++ b/ui/app/package.json @@ -15,12 +15,14 @@ "@sentry/vue": "^6.12.0", "@sifchain/sdk": "^1.0.0", "@types/color-hash": "^1.0.0", + "@types/dat.gui": "^0.7.7", "autoprefixer": "^10.3.3", "buffer": "^6.0.3", "clsx": "^1.1.1", "color-hash": "^1.0.3", "copy-to-clipboard": "^3.3.1", "core-js": "^3.6.5", + "dat.gui": "^0.7.7", "flip-toolkit": "^7.0.13", "normalize-scss": "^7.0.1", "process": "^0.11.10", diff --git a/ui/app/scripts/vite-polyfills.ts b/ui/app/scripts/vite-polyfills.ts new file mode 100644 index 000000000..722d5afc0 --- /dev/null +++ b/ui/app/scripts/vite-polyfills.ts @@ -0,0 +1,24 @@ +// We have to add a few node polyfills to make Vite work. +// Vite's official stance is they DO NOT support modules that +// require node builtins as dependencies, but that doesn't really +// work for us because of all the crypto modules. +// So on the first js file compiled by vite, add a few globals... +export function vitePolyfills() { + let addedPolyfills = false; + return { + name: "vite-polyfills", + transform(src, id) { + if (!addedPolyfills && /\.m?js$/.test(id)) { + addedPolyfills = true; + return { + code: [ + `import { Buffer as ___Buffer } from 'buffer'; window.Buffer = ___Buffer;`, + `import * as ___process from 'process'; window.process = ___process;`, + `window.global = window;`, + src, + ].join("\n"), + }; + } + }, + }; +} diff --git a/ui/app/src/App.vue b/ui/app/src/App.vue index 6cdfd20ee..c3f1f3e09 100644 --- a/ui/app/src/App.vue +++ b/ui/app/src/App.vue @@ -1,29 +1,5 @@ @@ -42,6 +19,7 @@ import { useInitialize } from "./hooks/useInitialize"; import EnvAlert from "@/componentsLegacy/shared/EnvAlert.vue"; import SideBar from "@/componentsLegacy/NavSidePanel/NavSidePanel"; import Layout from "@/componentsLegacy/Layout/Layout"; +import { Flags } from "@/components/Flags/Flags"; import { useRoute, useRouter } from "vue-router"; import { accountStore } from "./store/modules/accounts"; import { Amount } from "@sifchain/sdk"; @@ -72,6 +50,7 @@ export default defineComponent({ EnvAlert, SideBar, OnboardingModal, + Flags, }, computed: { key() { diff --git a/ui/app/src/assets/icons/interactive/settings.svg b/ui/app/src/assets/icons/interactive/settings.svg new file mode 100644 index 000000000..19c27265a --- /dev/null +++ b/ui/app/src/assets/icons/interactive/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/app/src/components/AssetIcon.tsx b/ui/app/src/components/AssetIcon.tsx index 2c35d3d53..7bcedd45d 100644 --- a/ui/app/src/components/AssetIcon.tsx +++ b/ui/app/src/components/AssetIcon.tsx @@ -50,6 +50,7 @@ export type InteractiveIconName = | "tick" | "wallet" | "warning" + | "settings" | "picture"; export type NavIconName = diff --git a/ui/app/src/components/Flags/Flags.tsx b/ui/app/src/components/Flags/Flags.tsx new file mode 100644 index 000000000..61f067adc --- /dev/null +++ b/ui/app/src/components/Flags/Flags.tsx @@ -0,0 +1,46 @@ +import { useCore } from "@/hooks/useCore"; +import { flagsStore } from "@/store/modules/flags"; +import { defineComponent, watch } from "@vue/runtime-core"; +import { onMounted, ref } from "vue"; +import { Button } from "../Button/Button"; + +const isProduction = import.meta.env.VITE_APP_DEPLOYMENT === "production"; + +const loadGui = async () => { + return (await import("./flagsGui")).createGui; +}; + +export const Flags = defineComponent({ + name: "FlagsGui", + setup() { + if (isProduction) return null; + + const guiRef = ref(); + + watch(flagsStore.state, () => flagsStore.persist(), { deep: true }); + + watch(flagsStore.refs.ibcTransferTimeoutMinutes.computed(), (timeout) => { + useCore().services.ibc.transferTimeoutMinutes = timeout; + }); + + const toggleGui = async () => { + if (!guiRef.value) { + const createGui = await loadGui(); + guiRef.value = createGui(); + document.body.appendChild(guiRef.value.domElement); + } else { + guiRef.value.domElement.remove(); + guiRef.value.destroy(); + guiRef.value = undefined; + } + }; + + return () => ( + + ); + }, +}); diff --git a/ui/app/src/components/Flags/flagsGui.ts b/ui/app/src/components/Flags/flagsGui.ts new file mode 100644 index 000000000..b94d072eb --- /dev/null +++ b/ui/app/src/components/Flags/flagsGui.ts @@ -0,0 +1,30 @@ +import { flagsStore } from "@/store/modules/flags"; +import * as dat from "dat.gui"; + +export const createGui = () => { + const gui = new dat.GUI({ + load: { + preset: "Default", + closed: true, + }, + autoPlace: false, + width: 400, + }); + + gui.useLocalStorage = true; + + Object.assign(gui.domElement.style, { + zIndex: 30, + position: "fixed", + top: "48px", + right: 0, + }); + gui.domElement.querySelector(".close-button")?.remove(); + gui.show(); + + Object.keys(flagsStore.state).forEach((key) => { + gui.add(flagsStore.state, key); + }); + + return gui; +}; diff --git a/ui/app/src/main.ts b/ui/app/src/main.ts index 0b9c573dc..4e6c6a7a3 100644 --- a/ui/app/src/main.ts +++ b/ui/app/src/main.ts @@ -20,7 +20,11 @@ if (process.env.NODE_ENV === "development") { // @ts-ignore app.config.devtools = true; } -console.log(import.meta.env.VITE_APP_VERSION, import.meta.env.VITE_APP_SHA); +console.log( + import.meta.env.VITE_APP_DEPLOYMENT, + import.meta.env.VITE_APP_VERSION, + import.meta.env.VITE_APP_SHA, +); app.use(vuexStore); app.use(router).mount("#app"); diff --git a/ui/app/src/store/index.ts b/ui/app/src/store/index.ts index f6eec85ca..c24428965 100644 --- a/ui/app/src/store/index.ts +++ b/ui/app/src/store/index.ts @@ -2,6 +2,7 @@ import { accountStore } from "./modules/accounts"; import { importStore } from "./modules/import"; import { createStore } from "vuex"; import { exportStore } from "./modules/export"; +import { flagsStore } from "./modules/flags"; export const vuexStore = createStore({ devtools: true, @@ -9,10 +10,12 @@ export const vuexStore = createStore({ accountStore.register(vuexStore); importStore.register(vuexStore); exportStore.register(vuexStore); +flagsStore.register(vuexStore); export const rootStore = { accounts: accountStore, import: importStore, export: exportStore, + flags: flagsStore, }; // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/ui/app/src/store/modules/flags.ts b/ui/app/src/store/modules/flags.ts new file mode 100644 index 000000000..5bc166318 --- /dev/null +++ b/ui/app/src/store/modules/flags.ts @@ -0,0 +1,33 @@ +import { defineComponent } from "@vue/runtime-core"; +import { Vuextra } from "../Vuextra"; + +export type FlagsState = { + ibcTransferTimeoutMinutes: number; + enableRewardsClaim: boolean; +}; + +let json: any = {}; +try { + json = JSON.parse(localStorage.getItem("flags") || "") || {}; +} catch (_) {} + +export const flagsStore = Vuextra.createStore({ + name: "flags", + options: { + devtools: true, + }, + state: { + ibcTransferTimeoutMinutes: json?.ibcTransferTimeoutMinutes || 45, + enableRewardsClaim: json?.enableRewardsClaim || false, + } as FlagsState, + getters: (state) => ({}), + mutations: (state) => ({}), + actions: (ctx) => ({ + persist: () => { + localStorage.setItem("flags", JSON.stringify(ctx.state)); + }, + }), + modules: [], +}); + +const self = flagsStore; diff --git a/ui/app/src/views/RewardsPage/components/RewardSection.tsx b/ui/app/src/views/RewardsPage/components/RewardSection.tsx index 045c2f067..884a47130 100644 --- a/ui/app/src/views/RewardsPage/components/RewardSection.tsx +++ b/ui/app/src/views/RewardsPage/components/RewardSection.tsx @@ -11,6 +11,7 @@ import { Button } from "@/components/Button/Button"; import { defineComponent, PropType, computed } from "vue"; import { useCore } from "@/hooks/useCore"; import { accountStore } from "@/store/modules/accounts"; +import { flagsStore } from "@/store/modules/flags"; const REWARD_TYPE_DISPLAY_DATA = { lm: { @@ -161,7 +162,7 @@ export const RewardSection = defineComponent({ icon="navigation/rewards" active disabled={ - true || + !flagsStore.state.enableRewardsClaim || !props.data?.user ?.totalClaimableCommissionsAndClaimableRewards || props.alreadyClaimed diff --git a/ui/app/vite.config.ts b/ui/app/vite.config.ts index 73ba1baae..6b19c6136 100644 --- a/ui/app/vite.config.ts +++ b/ui/app/vite.config.ts @@ -7,6 +7,7 @@ import { viteSingleFile } from "vite-plugin-singlefile"; import svgLoader from "./scripts/vite-svg-loader"; import { minifyHtml } from "vite-plugin-html"; import { visualizer } from "rollup-plugin-visualizer"; +import { vitePolyfills } from "./scripts/vite-polyfills"; // We turned off vite hmr because it's buggy, so we gotta add livereload. import liveReload from "vite-plugin-live-reload"; @@ -14,7 +15,7 @@ const LR_EXTENSIONS = "js,json,ts,tsx,css,scss,html,vue,webp,jpg"; export default defineConfig({ plugins: [ - sifchainPolyfillPlugin(), + vitePolyfills(), vueJsx(), vue(), (svgLoader as () => Plugin)(), @@ -38,7 +39,7 @@ export default defineConfig({ cssCodeSplit: false, rollupOptions: { output: { - // inlineDynamicImports: true, + inlineDynamicImports: false, manualChunks: () => "everything.js", }, plugins: [visualizer()], @@ -64,28 +65,3 @@ export default defineConfig({ }, }, }); - -// We have to add a few node polyfills to make Vite work. -// Vite's official stance is they DO NOT support modules that -// require node builtins as dependencies, but that doesn't really -// work for us because of all the crypto modules. -// So on the first js file compiled by vite, add a few globals... -function sifchainPolyfillPlugin() { - let addedPolyfills = false; - return { - name: "sifchain-polyfill-plugin", - transform(src, id) { - if (!addedPolyfills && /\.m?js$/.test(id)) { - addedPolyfills = true; - return { - code: [ - `import { Buffer as ___Buffer } from 'buffer'; window.Buffer = ___Buffer;`, - `import * as ___process from 'process'; window.process = ___process;`, - `window.global = window;`, - src, - ].join("\n"), - }; - } - }, - }; -} diff --git a/ui/core/src/services/IBCService/IBCService.ts b/ui/core/src/services/IBCService/IBCService.ts index 83338e1a7..808cc981e 100644 --- a/ui/core/src/services/IBCService/IBCService.ts +++ b/ui/core/src/services/IBCService/IBCService.ts @@ -46,6 +46,8 @@ export class IBCService { keplrProvider = KeplrWalletProvider.create(this.context); + public transferTimeoutMinutes = 45; + constructor(private context: IBCServiceContext) {} static create(context: IBCServiceContext) { return new this(context); @@ -354,7 +356,7 @@ export class IBCService { const symbol = params.assetAmountToTransfer.asset.symbol; - const timeoutInMinutes = 45; + const timeoutInMinutes = this.transferTimeoutMinutes; const timeoutTimestampInSeconds = Math.floor( new Date().getTime() / 1000 + 60 * timeoutInMinutes, ); diff --git a/ui/yarn.lock b/ui/yarn.lock index 24578e32e..fc19dfe85 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -3375,6 +3375,11 @@ resolved "https://registry.yarnpkg.com/@types/color-hash/-/color-hash-1.0.0.tgz#2671e71d46ce07248ca149ca058bdc01c2dbb975" integrity sha512-Vj9gPc43pJeILnI0Yh0ds4+1toNUmvVqKxg/5sY8ESZafKo24TY5eCKXwXPym1xcgEMb2Qxy3dRwaYOro4U5Tg== +"@types/dat.gui@^0.7.7": + version "0.7.7" + resolved "https://registry.yarnpkg.com/@types/dat.gui/-/dat.gui-0.7.7.tgz#2125aedfaa190364c5a50b0447858a7e159aea2e" + integrity sha512-CxLCme0He5Jk3uQwfO/fGZMyNhb/ypANzqX0yU9lviBQMlen5SOvQTBQ/Cd9x5mFlUAK5Tk8RgvTyLj1nYkz+w== + "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" @@ -6628,6 +6633,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +dat.gui@^0.7.7: + version "0.7.7" + resolved "https://registry.yarnpkg.com/dat.gui/-/dat.gui-0.7.7.tgz#7f96dbd21621a76385203659aebfa264ee6ae89b" + integrity sha512-sRl/28gF/XRC5ywC9I4zriATTsQcpSsRG7seXCPnTkK8/EQMIbCu5NPMpICLGxX9ZEUvcXR3ArLYCtgreFoMDw== + data-uri-to-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"