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

[ECO-2520] Merge main to production #424

Merged
merged 5 commits into from
Nov 28, 2024
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
37 changes: 37 additions & 0 deletions .github/workflows/fallback-deploy.file.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
jobs:
verify-fallback-deploy-file:
env:
FALLBACK_FILE: 'src/cloud-formation/deploy-indexer-fallback.yaml'
PRODUCTION_FILE: 'src/cloud-formation/deploy-indexer-production.yaml'
YQ_BASE_URL: 'https://github.com/mikefarah/yq/releases/download'
YQ_VERSION: 'v4.44.5'
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v4'
- name: 'Install yaml parsing tool'
run: |
YQ_BINARY="${YQ_BASE_URL}/${YQ_VERSION}/yq_linux_amd64"
sudo wget -O /usr/local/bin/yq "$YQ_BINARY"
sudo chmod +x /usr/local/bin/yq
- name: 'Verify fallback and production files same except `Environment`'
run: |
diff \
<(yq 'del(.parameters.Environment)' "$PRODUCTION_FILE") \
<(yq 'del(.parameters.Environment)' "$FALLBACK_FILE")
- name: 'Verify `Environment` in fallback and production files.'
run: |
PROD_ENV=$(yq '.parameters.Environment' "$PRODUCTION_FILE")
FALLBACK_ENV=$(yq '.parameters.Environment' "$FALLBACK_FILE")
[ "$PROD_ENV" = 'production' ] || exit 1
[ "$FALLBACK_ENV" = 'fallback' ] || exit 1
name: 'Verify fallback stack deployment file'
'on':
pull_request: null
push:
branches:
- 'main'
- 'fallback'
- 'production'
workflow_dispatch: null
...
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ git push origin merge-main-to-prod
Now you can make a PR to merge main to production with the `merge-main-to-prod`
branch!

### `fallback` branch

The `fallback` branch is intended to follow the `production` branch by a commit
during indexer stack updates: whenever indexer stack changes merge to
`production`, frontend deployments can be temporarily pointed at the `fallback`
stack to prevent any downtime in the case of a `production` stack deployment
failure or for in-place stack upgrades that result temporary outages.

For the purposes of indexer stack management, `production` only *needs* to be
merged into `fallback` just before indexer changes land in `production`,
nevertheless it is best practice to merge from `production` into `fallback` on a
regular cadence.

### Environment variables

You can set in Vercel project settings the production branch. By default, this
Expand Down
30 changes: 30 additions & 0 deletions src/cloud-formation/deploy-indexer-fallback.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
parameters:
BrokerCpu: 1024
BrokerImageVersion: '1.1.0'
BrokerMemory: 2048
DbMaxCapacity: 8
DeployAlb: 'true'
DeployAlbDnsRecord: 'true'
DeployBastionHost: 'true'
DeployBroker: 'true'
DeployContainers: 'true'
DeployDb: 'true'
DeployNlb: 'true'
DeployNlbVpcLink: 'true'
DeployPostgrest: 'true'
DeployProcessor: 'true'
DeployRestApi: 'true'
DeployRestApiDnsRecord: 'true'
DeployStack: 'true'
DeployWaf: 'false'
EnableWafRulesGeneral: 'false'
EnableWafRulesRestApi: 'false'
EnableWafRulesWebSocket: 'false'
Environment: 'fallback'
Network: 'mainnet'
ProcessorImageVersion: '1.1.0'
VpcStackName: 'emoji-vpc'
tags: null
template-file-path: 'src/cloud-formation/indexer.cfn.yaml'
...
4 changes: 2 additions & 2 deletions src/cloud-formation/deploy-indexer-main.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
parameters:
BrokerImageVersion: '1.0.1'
BrokerImageVersion: '1.1.0'
DeployAlb: 'true'
DeployAlbDnsRecord: 'true'
DeployBastionHost: 'true'
Expand All @@ -20,7 +20,7 @@ parameters:
EnableWafRulesWebSocket: 'false'
Environment: 'main'
Network: 'testnet'
ProcessorImageVersion: '1.0.1'
ProcessorImageVersion: '1.1.0'
VpcStackName: 'emoji-vpc'
tags: null
template-file-path: 'src/cloud-formation/indexer.cfn.yaml'
Expand Down
4 changes: 2 additions & 2 deletions src/cloud-formation/deploy-indexer-production.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
parameters:
BrokerCpu: 1024
BrokerImageVersion: '1.0.1'
BrokerImageVersion: '1.1.0'
BrokerMemory: 2048
DbMaxCapacity: 8
DeployAlb: 'true'
Expand All @@ -23,7 +23,7 @@ parameters:
EnableWafRulesWebSocket: 'false'
Environment: 'production'
Network: 'mainnet'
ProcessorImageVersion: '1.0.1'
ProcessorImageVersion: '1.1.0'
VpcStackName: 'emoji-vpc'
tags: null
template-file-path: 'src/cloud-formation/indexer.cfn.yaml'
Expand Down
34 changes: 15 additions & 19 deletions src/typescript/frontend/src/app/home/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ import TextCarousel from "components/text-carousel/TextCarousel";
import { type MarketDataSortByHomePage } from "lib/queries/sorting/types";

export interface HomePageProps {
featured?: DatabaseModels["market_state"];
markets: Array<DatabaseModels["market_state"]>;
numMarkets: number;
page: number;
sortBy: MarketDataSortByHomePage;
searchBytes?: string;
children?: React.ReactNode;
priceFeed: Array<DatabaseModels["price_feed"]>;
priceFeed: DatabaseModels["price_feed"][];
}

export default async function HomePageComponent({
featured,
markets,
numMarkets,
page,
Expand All @@ -28,24 +26,22 @@ export default async function HomePageComponent({
}: HomePageProps) {
return (
<>
<div className="pt-[93px]">
<div className="flex-col mb-[31px]">
{priceFeed.length > 0 ? <PriceFeed data={priceFeed} /> : <TextCarousel />}
<div className="flex justify-center px-[16px] mobile-lg:px-[24px] mx-auto w-full max-w-full max-h-[60dvh]">
<MainCard featured={featured} page={page} sortBy={sortBy} />
</div>
{children}
<TextCarousel />
<div className="flex-col mb-[31px]">
{priceFeed.length > 0 ? <PriceFeed data={priceFeed} /> : <TextCarousel />}
<div className="flex justify-center items-center px-[16px] mobile-lg:px-[24px] mx-auto w-full max-w-full max-h-[60dvh]">
<MainCard featuredMarkets={priceFeed} page={page} sortBy={sortBy} />
</div>

<EmojiTable
markets={markets}
numMarkets={numMarkets}
page={page}
sortBy={sortBy}
searchBytes={searchBytes}
/>
{children}
<TextCarousel />
</div>

<EmojiTable
markets={markets}
numMarkets={numMarkets}
page={page}
sortBy={sortBy}
searchBytes={searchBytes}
/>
</>
);
}
46 changes: 29 additions & 17 deletions src/typescript/frontend/src/app/home/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { type HomePageParams, toHomePageParamsWithDefault } from "lib/routes/home-page-params";
import HomePageComponent from "./HomePage";
import {
fetchFeaturedMarket,
fetchMarkets,
fetchMarketsWithCount,
fetchNumRegisteredMarkets,
fetchPriceFeed,
fetchPriceFeedWithMarketState,
} from "@/queries/home";
import { symbolBytesToEmojis } from "@sdk/emoji_data";
import { MARKETS_PER_PAGE } from "lib/queries/sorting/const";
import { ORDER_BY } from "@sdk/queries";
import { SortMarketsBy } from "@sdk/indexer-v2/types/common";
import { unstable_cache } from "next/cache";
import { parseJSON, stringifyJSON } from "utils";
import { type DatabaseModels, toPriceFeed } from "@sdk/indexer-v2/types";
import { type DatabaseJsonType } from "@sdk/indexer-v2/types/json-types";
import { SortMarketsBy } from "@sdk/indexer-v2/types/common";
import { ORDER_BY } from "@sdk/queries";

export const revalidate = 2;

Expand All @@ -21,11 +23,31 @@ const getCachedNumMarketsFromAptosNode = unstable_cache(
{ revalidate: 10 }
);

const NUM_MARKETS_ON_PRICE_FEED = 25;

const stringifiedFetchPriceFeedData = () =>
fetchPriceFeedWithMarketState({
sortBy: SortMarketsBy.DailyVolume,
orderBy: ORDER_BY.DESC,
pageSize: NUM_MARKETS_ON_PRICE_FEED,
}).then((res) => stringifyJSON(res));

const getCachedPriceFeedData = unstable_cache(
stringifiedFetchPriceFeedData,
["price-feed-with-market-data"],
{ revalidate: 10 }
);

export default async function Home({ searchParams }: HomePageParams) {
const { page, sortBy, orderBy, q } = toHomePageParamsWithDefault(searchParams);
const searchEmojis = q ? symbolBytesToEmojis(q).emojis.map((e) => e.emoji) : undefined;

const priceFeedPromise = fetchPriceFeed({});
const priceFeedPromise = getCachedPriceFeedData()
.then((res) => parseJSON<DatabaseJsonType["price_feed"][]>(res).map((p) => toPriceFeed(p)))
.catch((err) => {
console.error(err);
return [] as DatabaseModels["price_feed"][];
});

let marketsPromise: ReturnType<typeof fetchMarkets>;

Expand Down Expand Up @@ -53,30 +75,20 @@ export default async function Home({ searchParams }: HomePageParams) {
numMarketsPromise = getCachedNumMarketsFromAptosNode();
}

let featuredPromise: ReturnType<typeof fetchFeaturedMarket>;

if (sortBy === SortMarketsBy.DailyVolume && orderBy === ORDER_BY.DESC) {
featuredPromise = marketsPromise.then((r) => r[0]);
} else {
featuredPromise = fetchFeaturedMarket();
}

const [featured, priceFeed, markets, numMarkets] = await Promise.all([
featuredPromise,
const [priceFeedData, markets, numMarkets] = await Promise.all([
priceFeedPromise,
marketsPromise,
numMarketsPromise,
]);

return (
<HomePageComponent
featured={featured}
markets={markets}
numMarkets={numMarkets}
page={page}
sortBy={sortBy}
searchBytes={q}
priceFeed={priceFeed}
priceFeed={priceFeedData}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import "./module.css";

export const HeaderSpacer = () => <div className="header-spacer" />;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.header-spacer {
padding-top: 93px;
}

@media screen and (max-width: 526px) {
.header-spacer {
padding-top: 110px;
}
}
2 changes: 0 additions & 2 deletions src/typescript/frontend/src/components/header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import ButtonWithConnectWalletFallback from "./wallet-button/ConnectWalletButton
import { useSearchParams } from "next/navigation";
import Link, { type LinkProps } from "next/link";
import { useEmojiPicker } from "context/emoji-picker-context";
import { GeoblockedBanner } from "components/geoblocking";

const Header = ({ isOpen, setIsOpen }: HeaderProps) => {
const { isDesktop } = useMatchBreakpoints();
Expand Down Expand Up @@ -110,7 +109,6 @@ const Header = ({ isOpen, setIsOpen }: HeaderProps) => {
</Flex>
</Container>
<MobileMenu isOpen={isOpen} setIsOpen={setIsOpen} linksForCurrentPage={linksForCurrentPage} />
<GeoblockedBanner />
</StyledContainer>
);
};
Expand Down
19 changes: 0 additions & 19 deletions src/typescript/frontend/src/components/loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,17 @@ import { getRandomSymbolEmoji, SYMBOL_EMOJI_DATA, type SymbolEmojiData } from "@
import { Emoji } from "utils/emoji";
import { usePathname } from "next/navigation";
import { EMOJI_PATH_INTRA_SEGMENT_DELIMITER, ONE_SPACE } from "utils/pathname-helpers";
import { type EmojiMartData } from "./pages/emoji-picker/types";
import { init } from "emoji-mart";

const unpathify = (pathEmojiName: string) =>
SYMBOL_EMOJI_DATA.byName(pathEmojiName.replaceAll(EMOJI_PATH_INTRA_SEGMENT_DELIMITER, ONE_SPACE));

const data = fetch("https://cdn.jsdelivr.net/npm/@emoji-mart/data@latest/sets/15/native.json").then(
(res) =>
res.json().then((data) => {
return data as EmojiMartData;
})
);

export const Loading = ({
emojis,
numEmojis,
}: {
emojis?: SymbolEmojiData[];
numEmojis?: number;
}) => {
// Fetch/load the emoji picker data here to ensure that the picker has emoji data to use.
// Since the library only initializes when the picker component is rendered, the library won't have
// data on pages that don't use the picker component unless we explicitly call `init(...)` here.
useEffect(() => {
data.then((d) => {
init({ set: "native", data: d });
});

/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
const pathname = usePathname();
// Use the emojis in the path if we're on the `market` page.
const emojisInPath = pathname
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,12 @@
import { type HTMLAttributes, Suspense, useEffect, type PointerEventHandler } from "react";
import { useEmojiPicker } from "context/emoji-picker-context";
import { default as Picker } from "@emoji-mart/react";
import { init, SearchIndex } from "emoji-mart";
import { SearchIndex } from "emoji-mart";
import { type EmojiMartData, type EmojiPickerSearchData, type EmojiSelectorData } from "./types";
import { unifiedCodepointsToEmoji } from "utils/unified-codepoint-to-emoji";
import { ECONIA_BLUE } from "theme/colors";
import RoundButton from "@icons/Minimize";

// This is 400KB of lots of repeated data, we can use a smaller version of this if necessary later.
// TBH, we should probably just fork the library.
const data = fetch("https://cdn.jsdelivr.net/npm/@emoji-mart/data@latest/sets/15/native.json").then(
(res) =>
res.json().then((data) => {
return data as EmojiMartData;
})
);

export type SearchResult = Array<EmojiPickerSearchData>;

export const search = async (value: string): Promise<SearchResult> => {
Expand All @@ -41,17 +32,6 @@ export default function EmojiPicker(
const host = document.querySelector("em-emoji-picker");
const insertEmojiTextInput = useEmojiPicker((s) => s.insertEmojiTextInput);

// Load the data from the emoji picker library and then extract the valid chat emojis from it.
// This is why it's not necessary to build/import a `chat-emojis.json` set, even though there is `symbol-emojis.json`.
// NOTE: We don't verify that the length of this set is equal to the number of valid chat emojis in the Move contract.
useEffect(() => {
data.then((d) => {
init({ set: "native", data: d });
});

/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);

useEffect(() => {
setPickerRef(host as HTMLDivElement);
}, [host, setPickerRef]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const ClientEmojicoinPage = (props: EmojicoinProps) => {
useReliableSubscribe({ eventTypes: EVENT_TYPES });

return (
<Box pt="85px">
<Box>
<MainInfo data={props.data} />
{isTablet || isMobile ? <MobileGrid data={props.data} /> : <DesktopGrid data={props.data} />}
</Box>
Expand Down
Loading
Loading