From 965c021c3f8a102f2e7c928a66c2435e536dc3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 23 Feb 2024 11:35:24 +0100 Subject: [PATCH 001/157] fix get drep voting power --- .../frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index aade95029..48729a672 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -5,14 +5,14 @@ import { useCardano } from "@context"; import { getDRepVotingPower } from "@services"; export const useGetDRepVotingPowerQuery = () => { - const { dRepID } = useCardano(); + const { dRepID, dRep } = useCardano(); const { data, isLoading } = useQuery({ queryKey: QUERY_KEYS.useGetDRepVotingPowerKey, queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, - enabled: !!dRepID, + enabled: !!dRepID && dRep?.isRegistered, }); return { dRepVotingPower: data, isDRepVotingPowerLoading: isLoading }; From 602c0835fb102fb8218423d1a6927db3c6d2acac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 23 Feb 2024 12:46:10 +0100 Subject: [PATCH 002/157] add keys --- .../frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index 48729a672..5df7a3af1 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -8,7 +8,7 @@ export const useGetDRepVotingPowerQuery = () => { const { dRepID, dRep } = useCardano(); const { data, isLoading } = useQuery({ - queryKey: QUERY_KEYS.useGetDRepVotingPowerKey, + queryKey: [QUERY_KEYS.useGetDRepVotingPowerKey, dRepID, dRep?.isRegistered], queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, From e18baa1b111a618bb2cc1f4c2d24ebb726eff4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Fri, 23 Feb 2024 14:09:31 +0100 Subject: [PATCH 003/157] [#280] Fix get drep voting power request --- CHANGELOG.md | 1 + .../frontend/src/hooks/mutations/useDRepRegisterMutation.ts | 6 +++++- .../frontend/src/hooks/mutations/useDRepRetireMutation.ts | 6 +++++- .../src/hooks/queries/useGetDRepVotingPowerQuery.ts | 2 +- govtool/frontend/src/models/api.ts | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e9e33261..90954bacd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ changes. - Fixed vote calculation problems related to NoConfidence DRep [Issue 59](https://github.com/IntersectMBO/govtool/issues/59) - Fixed ada-holder/get-current-delegation error when delegated to NoConfidence or AlwaysAbstain dreps. [Issue 82](https://github.com/IntersectMBO/govtool/issues/82) - Fixed deployment scripts to address [Issue 171](https://github.com/IntersectMBO/govtool/issues/171). +- Fixed get drep voting power incorrectly executed endpoint [Issue 280](https://github.com/IntersectMBO/govtool/issues/280) ### Changed - Update Cardano-Serialization-Lib to 12.0.0-alpha.16 [Issue 156](https://github.com/IntersectMBO/govtool/issues/156) diff --git a/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts b/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts index 76b79287d..d757d09b2 100644 --- a/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts +++ b/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts @@ -7,7 +7,11 @@ export const useDRepRegisterMutation = () => { const { mutateAsync, isLoading } = useMutation(postDRepRegister, { onSuccess: () => { - setDRep({ deposit: 100, isRegistered: true, wasRegistered: false }); + setDRep({ + deposit: 100, + isRegistered: true, + wasRegistered: false, + }); }, }); diff --git a/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts b/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts index b3697c714..8bf8973e1 100644 --- a/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts +++ b/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts @@ -8,7 +8,11 @@ export const useDRepRetireMutation = () => { const { mutateAsync } = useMutation(postDRepRetire, { onSuccess: () => { - setDRep({ deposit: 100, wasRegistered: true, isRegistered: false }); + setDRep({ + deposit: 100, + wasRegistered: true, + isRegistered: false, + }); addSuccessAlert("DRep retired."); }, }); diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index 5df7a3af1..836946aa9 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -12,7 +12,7 @@ export const useGetDRepVotingPowerQuery = () => { queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, - enabled: !!dRepID && dRep?.isRegistered, + enabled: !!dRepID && !!dRep?.isRegistered, }); return { dRepVotingPower: data, isDRepVotingPowerLoading: isLoading }; diff --git a/govtool/frontend/src/models/api.ts b/govtool/frontend/src/models/api.ts index 03fec9e2b..5281e2a9e 100644 --- a/govtool/frontend/src/models/api.ts +++ b/govtool/frontend/src/models/api.ts @@ -1,7 +1,7 @@ export interface DRepInfo { isRegistered: boolean; wasRegistered: boolean; - deposit: number; + deposit: number | null; } export interface DRepData { From b2d03aada26b02fd7a77cfd03e56817f37f4a86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 23 Feb 2024 11:35:24 +0100 Subject: [PATCH 004/157] fix get drep voting power --- .../frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index aade95029..48729a672 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -5,14 +5,14 @@ import { useCardano } from "@context"; import { getDRepVotingPower } from "@services"; export const useGetDRepVotingPowerQuery = () => { - const { dRepID } = useCardano(); + const { dRepID, dRep } = useCardano(); const { data, isLoading } = useQuery({ queryKey: QUERY_KEYS.useGetDRepVotingPowerKey, queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, - enabled: !!dRepID, + enabled: !!dRepID && dRep?.isRegistered, }); return { dRepVotingPower: data, isDRepVotingPowerLoading: isLoading }; From 7bea37d63c0047df51aa0a3854a1d26c14cb10f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 23 Feb 2024 12:46:10 +0100 Subject: [PATCH 005/157] add keys --- .../frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index 48729a672..5df7a3af1 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -8,7 +8,7 @@ export const useGetDRepVotingPowerQuery = () => { const { dRepID, dRep } = useCardano(); const { data, isLoading } = useQuery({ - queryKey: QUERY_KEYS.useGetDRepVotingPowerKey, + queryKey: [QUERY_KEYS.useGetDRepVotingPowerKey, dRepID, dRep?.isRegistered], queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, From 26d5251e91f6d266a463f639c576601c7c3ea26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Fri, 23 Feb 2024 14:09:31 +0100 Subject: [PATCH 006/157] [#280] Fix get drep voting power request --- CHANGELOG.md | 1 + .../frontend/src/hooks/mutations/useDRepRegisterMutation.ts | 6 +++++- .../frontend/src/hooks/mutations/useDRepRetireMutation.ts | 6 +++++- .../src/hooks/queries/useGetDRepVotingPowerQuery.ts | 2 +- govtool/frontend/src/models/api.ts | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e9e33261..90954bacd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ changes. - Fixed vote calculation problems related to NoConfidence DRep [Issue 59](https://github.com/IntersectMBO/govtool/issues/59) - Fixed ada-holder/get-current-delegation error when delegated to NoConfidence or AlwaysAbstain dreps. [Issue 82](https://github.com/IntersectMBO/govtool/issues/82) - Fixed deployment scripts to address [Issue 171](https://github.com/IntersectMBO/govtool/issues/171). +- Fixed get drep voting power incorrectly executed endpoint [Issue 280](https://github.com/IntersectMBO/govtool/issues/280) ### Changed - Update Cardano-Serialization-Lib to 12.0.0-alpha.16 [Issue 156](https://github.com/IntersectMBO/govtool/issues/156) diff --git a/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts b/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts index 76b79287d..d757d09b2 100644 --- a/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts +++ b/govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts @@ -7,7 +7,11 @@ export const useDRepRegisterMutation = () => { const { mutateAsync, isLoading } = useMutation(postDRepRegister, { onSuccess: () => { - setDRep({ deposit: 100, isRegistered: true, wasRegistered: false }); + setDRep({ + deposit: 100, + isRegistered: true, + wasRegistered: false, + }); }, }); diff --git a/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts b/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts index b3697c714..8bf8973e1 100644 --- a/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts +++ b/govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts @@ -8,7 +8,11 @@ export const useDRepRetireMutation = () => { const { mutateAsync } = useMutation(postDRepRetire, { onSuccess: () => { - setDRep({ deposit: 100, wasRegistered: true, isRegistered: false }); + setDRep({ + deposit: 100, + wasRegistered: true, + isRegistered: false, + }); addSuccessAlert("DRep retired."); }, }); diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index 5df7a3af1..836946aa9 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -12,7 +12,7 @@ export const useGetDRepVotingPowerQuery = () => { queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, - enabled: !!dRepID && dRep?.isRegistered, + enabled: !!dRepID && !!dRep?.isRegistered, }); return { dRepVotingPower: data, isDRepVotingPowerLoading: isLoading }; diff --git a/govtool/frontend/src/models/api.ts b/govtool/frontend/src/models/api.ts index 03fec9e2b..5281e2a9e 100644 --- a/govtool/frontend/src/models/api.ts +++ b/govtool/frontend/src/models/api.ts @@ -1,7 +1,7 @@ export interface DRepInfo { isRegistered: boolean; wasRegistered: boolean; - deposit: number; + deposit: number | null; } export interface DRepData { From eb7eb45030ec780b1781bb4da3247f998744f60d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 23 Feb 2024 11:35:24 +0100 Subject: [PATCH 007/157] fix get drep voting power --- .../frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index 836946aa9..5df7a3af1 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -12,7 +12,7 @@ export const useGetDRepVotingPowerQuery = () => { queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, - enabled: !!dRepID && !!dRep?.isRegistered, + enabled: !!dRepID && dRep?.isRegistered, }); return { dRepVotingPower: data, isDRepVotingPowerLoading: isLoading }; From e23b8687ab4d9e96c4ad16e9b659296dafa8070c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Fri, 23 Feb 2024 14:09:31 +0100 Subject: [PATCH 008/157] [#280] Fix get drep voting power request --- .../frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts index 5df7a3af1..836946aa9 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotingPowerQuery.ts @@ -12,7 +12,7 @@ export const useGetDRepVotingPowerQuery = () => { queryFn: async () => { return await getDRepVotingPower({ dRepID }); }, - enabled: !!dRepID && dRep?.isRegistered, + enabled: !!dRepID && !!dRep?.isRegistered, }); return { dRepVotingPower: data, isDRepVotingPowerLoading: isLoading }; From 5e2df20725b5661369d9ad2684861eb8ece65423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 26 Feb 2024 15:20:54 +0100 Subject: [PATCH 009/157] [#265] make button disabled when tries to connect --- CHANGELOG.md | 1 + .../src/components/molecules/WalletOption.tsx | 81 ++++++++++++------- govtool/frontend/src/context/wallet.tsx | 7 ++ 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90954bacd..b80f9c5f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ changes. - i18next library added to FE [Issue 80](https://github.com/IntersectMBO/govtool/issues/80) ### Fixed +- Fix make button disble when wallet tries connect [Issue 265](https://github.com/IntersectMBO/govtool/issues/265) - Fix drep voting power calculation [Issue 231](https://github.com/IntersectMBO/govtool/issues/231) - Fix proposal/list and network/metrics bug that appeared when noone has delegated their funds either to drep_always_abstain or drep_always_no_confidence [Issue 231](https://github.com/IntersectMBO/govtool/issues/231) - Fix GA details [Issue 272](https://github.com/IntersectMBO/govtool/issues/272) diff --git a/govtool/frontend/src/components/molecules/WalletOption.tsx b/govtool/frontend/src/components/molecules/WalletOption.tsx index 94c5f9ed7..a1a14dd69 100644 --- a/govtool/frontend/src/components/molecules/WalletOption.tsx +++ b/govtool/frontend/src/components/molecules/WalletOption.tsx @@ -1,10 +1,10 @@ -import { Box, Typography } from "@mui/material"; -import { FC } from "react"; +import { FC, useCallback } from "react"; +import { useNavigate } from "react-router-dom"; +import { Box, CircularProgress, Typography } from "@mui/material"; +import { PATHS } from "@consts"; import { useCardano } from "@context"; import { theme } from "@/theme"; -import { useNavigate } from "react-router-dom"; -import { PATHS } from "@/consts"; export interface WalletOption { icon: string; @@ -15,7 +15,7 @@ export interface WalletOption { } export const WalletOptionButton: FC = ({ ...props }) => { - const { enable } = useCardano(); + const { enable, isEnableLoading } = useCardano(); const { palette: { lightBlue }, } = theme; @@ -23,52 +23,77 @@ export const WalletOptionButton: FC = ({ ...props }) => { const { dataTestId, icon, label, name, cip95Available } = props; + const enableByWalletName = useCallback(async() => { + if(isEnableLoading) return; + const result = await enable(name); + if (result?.stakeKey) { + navigate(PATHS.dashboard); + return; + } + navigate(PATHS.stakeKeys); + }, [enable, isEnableLoading]) + return ( { - const result = await enable(name); - if (result?.stakeKey) { - navigate(PATHS.dashboard); - return; - } - navigate(PATHS.stakeKeys); - }} + onClick={enableByWalletName} > {`${name} {name ?? label} - {`${name} +
+ {isEnableLoading === name && ( + + + + )} ); }; diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index 3d49f7a25..765e24226 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -97,6 +97,7 @@ interface CardanoContext { address?: string; disconnectWallet: () => Promise; enable: (walletName: string) => Promise; + isEnableLoading: string | null; error?: string; dRep: DRepInfo | undefined; isEnabled: boolean; @@ -165,6 +166,7 @@ CardanoContext.displayName = "CardanoContext"; function CardanoProvider(props: Props) { const [isEnabled, setIsEnabled] = useState(false); + const [isEnableLoading, setIsEnableLoading] = useState(null); const [dRep, setDRep] = useState(undefined); const [walletApi, setWalletApi] = useState( undefined @@ -517,6 +519,7 @@ function CardanoProvider(props: Props) { const enable = useCallback( async (walletName: string) => { + setIsEnableLoading(walletName); await checkIsMaintenanceOn(); // todo: use .getSupportedExtensions() to check if wallet supports CIP-95 @@ -650,6 +653,8 @@ function CardanoProvider(props: Props) { status: "ERROR", error: `${e == undefined ? t("errors.somethingWentWrong") : e}`, }; + } finally { + setIsEnableLoading(null); } } throw { status: "ERROR", error: t("errors.somethingWentWrong") }; @@ -1141,6 +1146,7 @@ function CardanoProvider(props: Props) { isPendingTransaction, isDrepLoading, setIsDrepLoading, + isEnableLoading, }), [ address, @@ -1173,6 +1179,7 @@ function CardanoProvider(props: Props) { isPendingTransaction, isDrepLoading, setIsDrepLoading, + isEnableLoading, ] ); From 36b8202541ecc6586883da8219a3e37a146f60c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Mon, 26 Feb 2024 14:36:25 +0100 Subject: [PATCH 010/157] =?UTF-8?q?[#301]=20Add=20Micha=C5=82=20Sza=C5=82o?= =?UTF-8?q?wski=20to=20SSH=20access=20list=20for=20environment=20managemen?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the user_data.sh script within the Terraform modules for govtool-EC2 instances. It adds Michał Szałowski to the list of users authorized for SSH access, thereby expanding the secure access management system to include a team leader. This change is a step towards fulfilling the secure credential sharing acceptance criterion by ensuring new team members like Michał have the necessary access to sensitive environments. --- infra/terraform/modules/govtool-ec2/main.tf | 2 +- infra/terraform/modules/govtool-ec2/user_data.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/terraform/modules/govtool-ec2/main.tf b/infra/terraform/modules/govtool-ec2/main.tf index f71417f05..40ad6f6cd 100644 --- a/infra/terraform/modules/govtool-ec2/main.tf +++ b/infra/terraform/modules/govtool-ec2/main.tf @@ -153,7 +153,7 @@ resource "aws_instance" "govtool" { } user_data = file("${path.module}/user_data.sh") - # user_data_replace_on_change = true + user_data_replace_on_change = false credit_specification { cpu_credits = "unlimited" diff --git a/infra/terraform/modules/govtool-ec2/user_data.sh b/infra/terraform/modules/govtool-ec2/user_data.sh index 6f9708ffe..79a7f1a06 100644 --- a/infra/terraform/modules/govtool-ec2/user_data.sh +++ b/infra/terraform/modules/govtool-ec2/user_data.sh @@ -2,7 +2,7 @@ # setup ssh access mkdir -p /home/ubuntu/.ssh -users="a.guderski,michal.jankun,p.placzynski" +users="a.guderski,michal.jankun,p.placzynski,michal.szalowski" curl --retry 5 --retry-delay 5 -L keys.binarapps.com/ssh/{$users} | tee -a /home/ubuntu/.ssh/authorized_keys echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKeM0HOF9szWhOfbQM8XkIfznORTtTaCJJStALYjQuy6 (voltaire-era-github-actions)" | tee -a /home/ubuntu/.ssh/authorized_keys chmod 700 /home/ubuntu/.ssh From 314d71ef0052b5bbd835af9ab4ace9e28bf220a3 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Wed, 14 Feb 2024 09:37:03 +0100 Subject: [PATCH 011/157] Sole voter information page, without footer --- govtool/frontend/src/App.tsx | 5 + .../components/organisms/SoleVoterInfo.tsx | 108 +++++++++++++++++ govtool/frontend/src/consts/paths.ts | 1 + govtool/frontend/src/i18n/locales/en.ts | 8 ++ .../src/pages/RegisterAsSoleVoter.tsx | 110 ++++++++++++++++++ 5 files changed, 232 insertions(+) create mode 100644 govtool/frontend/src/components/organisms/SoleVoterInfo.tsx create mode 100644 govtool/frontend/src/pages/RegisterAsSoleVoter.tsx diff --git a/govtool/frontend/src/App.tsx b/govtool/frontend/src/App.tsx index 91dab6356..d48e4d55a 100644 --- a/govtool/frontend/src/App.tsx +++ b/govtool/frontend/src/App.tsx @@ -30,6 +30,7 @@ import { } from "@utils"; import { SetupInterceptors } from "./services"; import { useGetDRepInfo, useWalletConnectionListener } from "./hooks"; +import { RegisterAsSoleVoter } from "./pages/RegisterAsSoleVoter"; export default function App() { const { enable, setDRep, setIsDrepLoading } = useCardano(); @@ -115,6 +116,10 @@ export default function App() { } /> } /> + } + /> } /> } /> } /> diff --git a/govtool/frontend/src/components/organisms/SoleVoterInfo.tsx b/govtool/frontend/src/components/organisms/SoleVoterInfo.tsx new file mode 100644 index 000000000..4eb34dafe --- /dev/null +++ b/govtool/frontend/src/components/organisms/SoleVoterInfo.tsx @@ -0,0 +1,108 @@ +import { useMemo } from "react"; +import { Box, Link } from "@mui/material"; + +import { LoadingButton, Button, Typography } from "@atoms"; +import { theme } from "@/theme"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { Trans } from "react-i18next"; +import { openInNewTab } from "@/utils"; +import { useNavigate } from "react-router-dom"; +import { PATHS } from "@consts"; + +export const SoleVoterInfo = () => { + const { + palette: { boxShadow2 }, + } = theme; + const { isMobile, pagePadding, screenWidth } = useScreenDimension(); + const navigate = useNavigate(); + const { t } = useTranslation(); + + const renderBackButton = useMemo(() => { + return ( + + ); + }, [isMobile]); + + const renderRegisterButton = useMemo(() => { + return ( + {}} + sx={{ + borderRadius: 50, + textTransform: "none", + px: 6, + width: isMobile ? "100%" : "auto", + height: 48, + }} + variant="contained" + > + {t("soleVoter.continueToRegister")} + + ); + }, [ + // isLoading, + isMobile, + ]); + + return ( + + + + {t("soleVoter.heading")} + + + openInNewTab("https://sancho.network/")} + sx={{ cursor: "pointer" }} + key="0" + />, + ]} + /> + + + + {isMobile ? renderRegisterButton : renderBackButton} + + {isMobile ? renderBackButton : renderRegisterButton} + + + ); +}; diff --git a/govtool/frontend/src/consts/paths.ts b/govtool/frontend/src/consts/paths.ts index 645f4e695..8af3a6381 100644 --- a/govtool/frontend/src/consts/paths.ts +++ b/govtool/frontend/src/consts/paths.ts @@ -16,6 +16,7 @@ export const PATHS = { faqs: "/faqs", delegateTodRep: "/delegate", registerAsdRep: "/register", + registerAsSoleVoter: "/register_sole_voter", stakeKeys: "/stake_keys", updateMetadata: "/update_metadata", }; diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index 9204175a4..68cd48743 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -286,6 +286,13 @@ export const en = { showAll: "Show all", viewAll: "View all", }, + soleVoter: { + becomeSoleVoter: "Become a Sole Voter", + continueToRegister: "Continue to register", + description: + "A Sole Voter is someone that can vote on any Governance Action with their own Voting Power, which is equal to the balance of ADA in their connected wallet. <0>Learn More about Sole Voter.\n\nBecoming a Sole Voter will require a refundable deposit of ₳2.\n\nYour deposit will be refunded if you either retire or delegate your voting power to someone else (a DRep)", + heading: "What this Means", + }, system: { sanchoNet: "SanchoNet", sanchoNetIsBeta: @@ -360,6 +367,7 @@ export const en = { back: "Back", backToDashboard: "Back to dashboard", backToList: "Back to the list", + backToDashboard: "Back to dashboard", cancel: "Cancel", clear: "Clear", confirm: "Confirm", diff --git a/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx new file mode 100644 index 000000000..370a5fefc --- /dev/null +++ b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx @@ -0,0 +1,110 @@ +import { useEffect } from "react"; +import { Box, Link } from "@mui/material"; + +import { Background, Typography } from "@atoms"; +import { ICONS, PATHS } from "@consts"; +import { DashboardTopNav, Footer } from "@organisms"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { useNavigate } from "react-router-dom"; +import { WALLET_LS_KEY, getItemFromLocalStorage } from "@/utils/localStorage"; +import { SoleVoterInfo } from "@/components/organisms/SoleVoterInfo"; + +export const RegisterAsSoleVoter = () => { + const { isMobile, screenWidth } = useScreenDimension(); + const navigate = useNavigate(); + const { t } = useTranslation(); + + useEffect(() => { + if ( + !getItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`) || + !getItemFromLocalStorage(`${WALLET_LS_KEY}_name`) + ) { + navigate(PATHS.home); + } + }, []); + + return ( + + + + + + {isMobile && ( + + + {t("soleVoter.becomeSoleVoter")} + + + )} + navigate(PATHS.dashboard)} + > + arrow + + {t("backToDashboard")} + + + + + {isMobile &&
} + + + ); +}; From 0d9915cc83216aa043010192812a5db783c2d181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 16 Feb 2024 14:31:58 +0100 Subject: [PATCH 012/157] add image for sole voter --- .../public/images/GovActionsSoleVoter.png | Bin 0 -> 4097 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 govtool/frontend/public/images/GovActionsSoleVoter.png diff --git a/govtool/frontend/public/images/GovActionsSoleVoter.png b/govtool/frontend/public/images/GovActionsSoleVoter.png new file mode 100644 index 0000000000000000000000000000000000000000..69048a4c322a99fc2098fe7efffd775246ed0620 GIT binary patch literal 4097 zcmV+c5dQCpP)#|kkg5?$Ah31-zu2|0cTI3?{E|X=I3#x1yZ1b1{`~VibIv}z-t}cI zCBJuk=bp#R{NMcVxd6Z6#GsAT8tAzMBeseIe-{e*PMWSpmt)4*F`0>jE!o;UYw_B{ zFoks50Z0a(UL=u!9E4m8LRO8>*i8c7W;$&E z3~k?h5v!+Pfh1dvnXpVV^T${|lj}1F1g9>2N<0!F{6l5&>WATNq|*XG>xG^VU=sfq zF@K(Cn6sSOQD?Uj;XokJq?Dg+MDlL7Xw4wJ4OD?iQfqh5257cE3sN*##LTWTmbU@| zXe7g_guX<5QWKq9w)Ohaym3 zGqjuhotjMk9@@bnezWt0<98&P$K4S2LlOWJ??sJ zCbWr834qrA=jO>)`e%C46+SlePLE04AtiB6)jhg=g~5rWrI@Sy;+Q3oUwe(>u#K(LtE!YiTD9Y(7PFdr0s#5 zqog)!Y%b)7>DGTh8))1{u-U(P4j&ro!!&y*t43P)^)6aT@MM{nar)CJO+Qpy_J`X? z8n5;8wo7@I?Z70RsloCqGE35+s78QeDw>V@PiL~O+fq2qG;S4$B(A_rCp5#1TTV8p ziIc%N9(>rwJ5)#e7efv zGy|Xv-=2Oa8qc`X_P+53F_)E%UO}x~41v+v&;}Y4fT2ClTpagr+D=>bB{`Hd zFv&otx-N>7GB;M%<&jaFgED(0?ccN!PD1P^%KtgMm1mAt@AXY)!fLSgfMX}Lfkp)& z>)&!COOqFIFz!}<+(c+r*L6|@CZ?A*oK=QgNkmF5q3|UYpBvi!)M_{xVKhWyMV)f9 z^JqgD(Ogjt+CU=$(AxRzU!=|Ex3QJg%>t~?w+qrCyxwuh8COm9(SFa!YGl!;vFD-2 z81pNYO8od<0=R7!3$_kpqQ7bt+CT+VkN5RlBD3@X((_0aCrp%Q7Xo2E zZ}nb>_+cUw#so}D2>mUfFWW|4fs}6*#@Csl8-i;WtLzL``MS7&%K^^Ve#!Z6y0}vc z`D%mlH$a{^I?)P}2Y~dM#l6pb57U-qJ_LZ}1q|tO^^kF1WL#e}U8?Dfskhz*1|;eo{tk!-wlx{Y1N2NU71oXr@&{_19f6MO z0Gro!98Ly6vTMsHF-}ws1R~-)L*PLK)?>oqa zt=9`swuVPOuU8@np|w{Fvc^s^h-d-R?^JvrwLO5NNu2eL1wfqOkMtVUn3Cm;I#68X z8P*lN$zXX>rq{(xBueoJCN{s|>}-;u)%5V4oYxM06<(xZ^kUUkg>>C zX^rJ)WeM;=7{*mz&pWHYIw(4<+X%605+tU*1%COgRjZDT1;C62OJ8Kjp3Ms(7&JC4 zGc-$LK48+{T`^Xt=SF&2B~aabNcGa6#Fb<#_HCW-0bl~x>#p5>Q=PSL$s0C>u<-s3`9V#bJrUf{i*E8q7oFb*Ox{}xQeB#$Yu^bjk*3k{dkhVi$z-W0`&jw{1I%C%d;^Nj`m{W;P0RKa9$}*fSOPA3}&1)vJw*Nar3U zwXLX9XQHmq+X0}bP1rB4-ptD>UygVTuXl8< zI0_S_R{yqtrTK3kw)-I<5i1=x7&occD6EP);(_WSn&1ts`_7a>7kgQWNc(dJN|ITiWRp&8z~-m{$`r!9+IRB3paeM#fnm)%5B2rB`l05+_Q?L1t2Wb z(eqM>H#wnlS?FQPuEtz44^*oB>(FMZFSz=fwR0+$3zQ$G1^1B1X5KDH$h{He9N1LV zBBST|c|=fG2oHZ3+#TltKjk;oP^&V6{Z6tX6C%-vu2|KE@h>=#?X^t7}Y` z)(&D9UDTqF=kTTNucU%~OvWPckU@}CHkKA3ckTjKl{NFK&PV_-DetQwXPBSgLB9K8 zSgJEp7Qqw|zO?haREQ@r5%cs?!;|N-r*NVU-sM@nSIkSj^Az)t>lgQTthr%xg)aY! z-tEwDl*HeYL3{SEc0V_J#-in~!zqx;F_NG3y@zJ);;b@Ts#9cSzYrkyH>zw0yL9P^ zG2g%IE}qEjX)<>6^aWRXD@2L*VVQ^0==wHQR}rGxd9chMJpR@v)N^D5_|GB2*@YO~ zjF5lV2?xxqVP!e>9)s~P{!-t<1jL^v`^c(GIA7_Y1XKG{(X$dLRY^K2I5ssR+9>2+eq4?F$CZGVkgX(lSqsqe!1875MbDH8=df8=rP($CojM z^$?!KJDmYLs6D*I2oBcy^!e;0oI{#8>~dkxOyV?03F2xsWS@r~5Q%svHv@_c% zja=_esSVR^!FEy)HoG{91~;`1?!L8g@uGctew7p)*>ho>BS5Hmg*SKrK3y)ZuexK6u3#Dmo$n>E0cGK;Zw-+X3%Nu*4Aa^-74p}Y*!J_ojBkaCs5S(6uwF@?iW2FGbNr8ISNf?yoaR8`z zNQJ>I(IV@-sIhX%PhbM%hpw|}>uAtlI-LsB$h?n1Ob+@;Oea?(T))DOCv#J~2_|3jnYM3*Mx?`G{u9F;?zNvy&K}1B3vT7OLM- zRyi}EnjcdIOb%ntN}Vf$3h?SR3}~CxGQ?3&pic<^MUD3^`2kgNKSfPyadn2q^@C5% zm@z)K_z<+rw$$jTZ|a^d`?Dg`9+BWW3)CU>PL_FFFjj8$0GuuW6xFX@@|iS~AEm*M z`!G_L8H7TkK+3elwlx0)^*KaqK7q$^5bveMA09Rq<%Cp z;?dajWy`*SmFOyp*qgXxpf@bCuq`@05(`E5Ei;t zPhX?wze~sdU+w(BHCw``*@CMM#8ieO5r5b-gHGZR!rvL?F3*OzQEna_amFuzNzh3T z96MJnf0RBRJ^sYzODkA;KTY0EhG#AnLocAUOe2>zNU$6vaXd;VGB4Jv(bnqqMW)Mi z&tu{7)%ij?bUEo-hJ#OxP1lIRKQhlJUfiCg92gs65U&e1N4u zXcfq#3AXBJPRgBZTa2JL`X<> z3ze;20>Ne$!d`708RVx_Q2ad-UE?XVV1jf;NPwd0?_c^F6Z}Rm0ihJQoFlbHP_@`b zo1_ZlOu8Hc=e(&sa#PAh!!HztGJBF@(FOeSF0$FhM$_08q5|XSKT- z^82)?yQC^+Ho3AA5L@Qy04PB Date: Fri, 16 Feb 2024 14:32:44 +0100 Subject: [PATCH 013/157] change props and dashabord card sizes --- .../components/molecules/DashboardActionCard.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/govtool/frontend/src/components/molecules/DashboardActionCard.tsx b/govtool/frontend/src/components/molecules/DashboardActionCard.tsx index 3d3e9fc26..90cfce5ca 100644 --- a/govtool/frontend/src/components/molecules/DashboardActionCard.tsx +++ b/govtool/frontend/src/components/molecules/DashboardActionCard.tsx @@ -18,9 +18,7 @@ type DashboardActionCardProps = { firstButtonIsLoading?: boolean; firstButtonLabel?: string; firstButtonVariant?: ButtonProps["variant"]; - imageHeight?: number; imageURL?: string; - imageWidth?: number; inProgress?: boolean; isLoading?: boolean; secondButtonAction?: () => void; @@ -62,17 +60,15 @@ export const DashboardActionCard: FC = ({ return ( {inProgress && !isLoading && ( Date: Fri, 16 Feb 2024 14:33:28 +0100 Subject: [PATCH 014/157] add sole voter into IMAGES --- govtool/frontend/src/consts/images.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/govtool/frontend/src/consts/images.ts b/govtool/frontend/src/consts/images.ts index f9a098d4f..9d64fe9b2 100644 --- a/govtool/frontend/src/consts/images.ts +++ b/govtool/frontend/src/consts/images.ts @@ -3,6 +3,7 @@ export const IMAGES = { appLogoWithoutText: "/images/AppLogoWithoutText.png", errorPageImage: "/images/ErrorPageImage.png", heroImage: "/images/HeroImage.png", + soleVoterImage: "/images/GovActionsSoleVoter.png", govActionDelegateImage: "/images/GovActionDelegate.png", govActionRegisterImage: "/images/GovActionRegister.png", govActionListImage: "/images/GovActionList.png", From bf8a0fa84d3f43f68dea463d9c2e3d9ecd615be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 16 Feb 2024 14:33:46 +0100 Subject: [PATCH 015/157] sort IMAGES asc --- govtool/frontend/src/consts/images.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/govtool/frontend/src/consts/images.ts b/govtool/frontend/src/consts/images.ts index 9d64fe9b2..b74b473ea 100644 --- a/govtool/frontend/src/consts/images.ts +++ b/govtool/frontend/src/consts/images.ts @@ -1,16 +1,16 @@ export const IMAGES = { appLogo: "/images/SanchoLogo.png", appLogoWithoutText: "/images/AppLogoWithoutText.png", + bgBlue: "/images/BGBlue.png", + bgOrange: "/images/BGOrange.png", errorPageImage: "/images/ErrorPageImage.png", - heroImage: "/images/HeroImage.png", - soleVoterImage: "/images/GovActionsSoleVoter.png", + govActionDefaultImage: "/images/GovActionDefault.png", govActionDelegateImage: "/images/GovActionDelegate.png", - govActionRegisterImage: "/images/GovActionRegister.png", govActionListImage: "/images/GovActionList.png", - govActionDefaultImage: "/images/GovActionDefault.png", + govActionRegisterImage: "/images/GovActionRegister.png", + heroImage: "/images/HeroImage.png", + soleVoterImage: "/images/GovActionsSoleVoter.png", successImage: "/images/Success.png", warningImage: "/images/Warning.png", warningYellowImage: "/images/WarningYellow.png", - bgOrange: "/images/BGOrange.png", - bgBlue: "/images/BGBlue.png", }; From 6b5576536b0c7a681141b18003101cced3fd9463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 16 Feb 2024 14:34:04 +0100 Subject: [PATCH 016/157] add translations for sole voter card --- govtool/frontend/src/i18n/locales/en.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index 68cd48743..ed247a1e1 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -72,6 +72,11 @@ export const en = { title: "Governance Actions", view: "View governance actions", }, + cards: { + registerAsSoleVoterTitle: "Become a Sole Voter", + registerAsSoleVoterDescription: + "Vote on Governance Actions using your own voting power of ₳{{votingPower}}", + }, registration: { changeMetadata: "Change metadata", connectToRegister: "Connect to register", From 928b20b570cfc3aaa65ee158f200cf923ab3adcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 16 Feb 2024 14:34:28 +0100 Subject: [PATCH 017/157] change way to display cards on dashboard/ add sole voter card --- .../components/organisms/DashboardCards.tsx | 327 +++++++++--------- 1 file changed, 164 insertions(+), 163 deletions(-) diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index a4bde49da..8aa4cad6b 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -1,5 +1,5 @@ import { useNavigate } from "react-router-dom"; -import { Box, CircularProgress, Typography } from "@mui/material"; +import { Box, CircularProgress } from "@mui/material"; import { Trans } from "react-i18next"; import { IMAGES, PATHS } from "@consts"; @@ -259,38 +259,6 @@ export const DashboardCards = () => { dRep?.wasRegistered, ]); - const renderGovActionSection = useCallback(() => { - return ( - <> - - {t("dashboard.headingTwo")} - - - - navigate(PATHS.dashboard_governance_actions) - } - firstButtonLabel={t( - `dashboard.govActions.${ - dRep?.isRegistered ? "reviewAndVote" : "view" - }` - )} - imageURL={IMAGES.govActionListImage} - title={t("dashboard.govActions.title")} - /> - {screenWidth < 1024 ? null : ( - <> - - - - )} - - - ); - }, [screenWidth, isMobile, dRep?.isRegistered]); - return isDrepLoading ? ( { ) : ( - {dRep?.isRegistered && renderGovActionSection()} - - {t("dashboard.headingOne")} - - - navigateTo(PATHS.delegateTodRep)} - firstButtonLabel={ - delegateTransaction?.transactionHash - ? "" - : currentDelegation - ? t("dashboard.delegation.changeDelegation") - : t("delegate") - } - imageHeight={55} - imageWidth={65} - firstButtonVariant={currentDelegation ? "outlined" : "contained"} - imageURL={IMAGES.govActionDelegateImage} - cardId={displayedDelegationId} - inProgress={!!delegateTransaction?.transactionHash} - cardTitle={t("dashboard.delegation.dRepDelegatedTo")} - secondButtonAction={ - delegateTransaction?.transactionHash - ? () => openInNewTab("https://adanordic.com/latest_transactions") - : () => - openInNewTab( - "https://docs.sanchogov.tools/faqs/ways-to-use-your-voting-power" - ) - } - secondButtonLabel={ - delegateTransaction?.transactionHash - ? t("seeTransaction") - : currentDelegation - ? "" - : t("learnMore") - } - title={ - delegateTransaction?.transactionHash ? ( - t("dashboard.delegation.votingPowerDelegation") - ) : currentDelegation ? ( - - ) : ( - t("dashboard.delegation.useYourVotingPower") - ) - } - /> - - navigateTo(PATHS.registerAsdRep) - } - firstButtonIsLoading={isRetirementLoading} - firstButtonLabel={ - registerTransaction?.transactionHash - ? "" - : t( - `dashboard.registration.${ - dRep?.isRegistered ? "retire" : "register" - }` + {/* DELEGATION CARD */} + navigateTo(PATHS.delegateTodRep)} + firstButtonLabel={ + delegateTransaction?.transactionHash + ? "" + : currentDelegation + ? t("dashboard.delegation.changeDelegation") + : t("delegate") + } + firstButtonVariant={currentDelegation ? "outlined" : "contained"} + imageURL={IMAGES.govActionDelegateImage} + cardId={displayedDelegationId} + inProgress={!!delegateTransaction?.transactionHash} + cardTitle={t("dashboard.delegation.dRepDelegatedTo")} + secondButtonAction={ + delegateTransaction?.transactionHash + ? () => openInNewTab("https://adanordic.com/latest_transactions") + : () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/ways-to-use-your-voting-power" ) - } - inProgress={!!registerTransaction?.transactionHash} - imageURL={IMAGES.govActionRegisterImage} - secondButtonAction={ - registerTransaction?.transactionHash - ? () => openInNewTab("https://adanordic.com/latest_transactions") - : dRep?.isRegistered - ? () => { - navigateTo(PATHS.updateMetadata); - } - : () => - openInNewTab( - "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" - ) - } - secondButtonLabel={ - registerTransaction?.transactionHash - ? t("seeTransaction") - : dRep?.isRegistered - ? t("dashboard.registration.changeMetadata") - : t("learnMore") - } - cardId={dRep?.isRegistered || dRep?.wasRegistered ? dRepIDBech32 : ""} - cardTitle={ - dRep?.isRegistered || dRep?.wasRegistered ? t("myDRepId") : "" - } - title={registrationCardTitle} - /> - - {!dRep?.isRegistered && renderGovActionSection()} + } + secondButtonLabel={ + delegateTransaction?.transactionHash + ? t("seeTransaction") + : currentDelegation + ? "" + : t("learnMore") + } + title={ + delegateTransaction?.transactionHash ? ( + t("dashboard.delegation.votingPowerDelegation") + ) : currentDelegation ? ( + + ) : ( + t("dashboard.delegation.useYourVotingPower") + ) + } + /> + {/* DELEGATION CARD END*/} + {/* REGISTARTION AS DREP CARD */} + navigateTo(PATHS.registerAsdRep) + } + firstButtonIsLoading={isRetirementLoading} + firstButtonLabel={ + registerTransaction?.transactionHash + ? "" + : t( + `dashboard.registration.${ + dRep?.isRegistered ? "retire" : "register" + }` + ) + } + inProgress={!!registerTransaction?.transactionHash} + imageURL={IMAGES.govActionRegisterImage} + secondButtonAction={ + registerTransaction?.transactionHash + ? () => openInNewTab("https://adanordic.com/latest_transactions") + : dRep?.isRegistered + ? () => { + navigateTo(PATHS.updateMetadata); + } + : () => + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" + ) + } + secondButtonLabel={ + registerTransaction?.transactionHash + ? t("seeTransaction") + : dRep?.isRegistered + ? t("dashboard.registration.changeMetadata") + : t("learnMore") + } + cardId={dRep?.isRegistered || dRep?.wasRegistered ? dRepIDBech32 : ""} + cardTitle={ + dRep?.isRegistered || dRep?.wasRegistered ? t("myDRepId") : "" + } + title={registrationCardTitle} + /> + {/* DREP CARD END*/} + {/* SOLE VOTER CARD */} + + } + firstButtonAction={() => navigateTo(PATHS.registerAsSoleVoter)} + firstButtonLabel={t("dashboard.registration.register")} + imageURL={IMAGES.soleVoterImage} + secondButtonAction={() => + openInNewTab( + "https://docs.sanchogov.tools/faqs/what-does-it-mean-to-register-as-a-drep" + ) + } + secondButtonLabel={t("learnMore")} + title={t("dashboard.cards.registerAsSoleVoterTitle")} + /> + {/* REGISTARTION AS SOLE VOTER CARD END*/} + {/* GOV ACTIONS LIST CARD */} + navigate(PATHS.dashboard_governance_actions)} + firstButtonLabel={t( + `dashboard.govActions.${ + dRep?.isRegistered ? "reviewAndVote" : "view" + }` + )} + imageURL={IMAGES.govActionListImage} + title={t("dashboard.govActions.title")} + /> + {/* GOV ACTIONS LIST CARD END*/} ); }; From 1849e036a86680dcbba1c512fb77aad7298017df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 16 Feb 2024 14:35:14 +0100 Subject: [PATCH 018/157] delete unnecessary code --- govtool/frontend/src/components/organisms/DashboardCards.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index 8aa4cad6b..7e3ae3721 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -31,7 +31,7 @@ export const DashboardCards = () => { const navigate = useNavigate(); const { currentDelegation, isCurrentDelegationLoading } = useGetAdaHolderCurrentDelegationQuery(stakeKey); - const { screenWidth, isMobile } = useScreenDimension(); + const { screenWidth } = useScreenDimension(); const { openModal } = useModal(); const [isRetirementLoading, setIsRetirementLoading] = useState(false); From 249df28ac9d4942a65b327714da34b566b3f0b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 16 Feb 2024 14:39:07 +0100 Subject: [PATCH 019/157] add feat to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b80f9c5f8..6830148d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ As a minor extension, we also keep a semantic version for the `UNRELEASED` changes. ## [Unreleased] +- Add Sole Voter card [Issue 141](https://github.com/IntersectMBO/govtool/issues/141) - Create DRep registration page about roles [Issue 205](https://github.com/IntersectMBO/govtool/issues/205) - Create Checkbox component. Improve Field and ControlledField [Issue 177](https://github.com/IntersectMBO/govtool/pull/177) - Vitest unit tests added for utils functions [Issue 81](https://github.com/IntersectMBO/govtool/issues/81) From 50514fac2daebe8468bf784321236570d4101237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Fri, 16 Feb 2024 14:33:28 +0100 Subject: [PATCH 020/157] add sole voter into IMAGES --- govtool/frontend/src/consts/images.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/govtool/frontend/src/consts/images.ts b/govtool/frontend/src/consts/images.ts index b74b473ea..e178dbf93 100644 --- a/govtool/frontend/src/consts/images.ts +++ b/govtool/frontend/src/consts/images.ts @@ -4,6 +4,8 @@ export const IMAGES = { bgBlue: "/images/BGBlue.png", bgOrange: "/images/BGOrange.png", errorPageImage: "/images/ErrorPageImage.png", + heroImage: "/images/HeroImage.png", + soleVoterImage: "/images/GovActionsSoleVoter.png", govActionDefaultImage: "/images/GovActionDefault.png", govActionDelegateImage: "/images/GovActionDelegate.png", govActionListImage: "/images/GovActionList.png", From 13317821fb2382ee9fd50f8d34c3fc8d82de1352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 19 Feb 2024 09:00:16 +0100 Subject: [PATCH 021/157] add retire as sole voter screen --- govtool/frontend/src/App.tsx | 2 + .../components/organisms/DashboardCards.tsx | 43 ++++- govtool/frontend/src/consts/paths.ts | 23 +-- govtool/frontend/src/context/wallet.tsx | 11 ++ govtool/frontend/src/i18n/locales/en.ts | 10 +- .../frontend/src/pages/RetireAsSoleVoter.tsx | 180 ++++++++++++++++++ govtool/frontend/src/pages/index.ts | 5 +- 7 files changed, 250 insertions(+), 24 deletions(-) create mode 100644 govtool/frontend/src/pages/RetireAsSoleVoter.tsx diff --git a/govtool/frontend/src/App.tsx b/govtool/frontend/src/App.tsx index d48e4d55a..a36a89f8f 100644 --- a/govtool/frontend/src/App.tsx +++ b/govtool/frontend/src/App.tsx @@ -21,6 +21,7 @@ import { UpdatedRepMetadata, GovernanceActionsCategory, DashboardGovernanceActionsCategory, + RetireAsSoleVoter, } from "@pages"; import { callAll, @@ -120,6 +121,7 @@ export default function App() { path={PATHS.registerAsSoleVoter} element={} /> + } /> } /> } /> } /> diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index 7e3ae3721..953c11c4c 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -27,6 +27,7 @@ export const DashboardCards = () => { isPendingTransaction, registerTransaction, stakeKey, + soleVoter, } = useCardano(); const navigate = useNavigate(); const { currentDelegation, isCurrentDelegationLoading } = @@ -271,12 +272,12 @@ export const DashboardCards = () => { ) : ( {/* DELEGATION CARD */} { {/* DREP CARD END*/} {/* SOLE VOTER CARD */} } - firstButtonAction={() => navigateTo(PATHS.registerAsSoleVoter)} - firstButtonLabel={t("dashboard.registration.register")} + firstButtonAction={() => + navigateTo( + soleVoter?.isRegistered + ? PATHS.retireAsSoleVoter + : PATHS.registerAsSoleVoter + ) + } + firstButtonLabel={t( + soleVoter?.isRegistered + ? "dashboard.cards.retire" + : "dashboard.registration.register" + )} + firstButtonVariant={soleVoter?.isRegistered ? "outlined" : "contained"} imageURL={IMAGES.soleVoterImage} secondButtonAction={() => openInNewTab( @@ -419,7 +437,12 @@ export const DashboardCards = () => { ) } secondButtonLabel={t("learnMore")} - title={t("dashboard.cards.registerAsSoleVoterTitle")} + secondButtonVariant={"outlined"} + title={t( + soleVoter?.isRegistered + ? "dashboard.cards.youAreSoleVoterTitle" + : "dashboard.cards.registerAsSoleVoterTitle" + )} /> {/* REGISTARTION AS SOLE VOTER CARD END*/} {/* GOV ACTIONS LIST CARD */} diff --git a/govtool/frontend/src/consts/paths.ts b/govtool/frontend/src/consts/paths.ts index 8af3a6381..4ac0cbde2 100644 --- a/govtool/frontend/src/consts/paths.ts +++ b/govtool/frontend/src/consts/paths.ts @@ -1,22 +1,23 @@ export const PATHS = { - home: "/", - dashboard: "/dashboard", - error: "/error", - governance_actions: "/governance_actions", - governance_actions_category: "/governance_actions/category/:category", - governance_actions_category_action: - "/governance_actions/category/:category/:proposalId", - governance_actions_action: "/governance_actions/:proposalId", - dashboard_governance_actions: "/connected/governance_actions", dashboard_governance_actions_action: "/connected/governance_actions/:proposalId", dashboard_governance_actions_category: "/connected/governance_actions/category/:category", - guides: "/guides", - faqs: "/faqs", + dashboard_governance_actions: "/connected/governance_actions", + dashboard: "/dashboard", delegateTodRep: "/delegate", + error: "/error", + faqs: "/faqs", + governance_actions_action: "/governance_actions/:proposalId", + governance_actions_category_action: + "/governance_actions/category/:category/:proposalId", + governance_actions_category: "/governance_actions/category/:category", + governance_actions: "/governance_actions", + guides: "/guides", + home: "/", registerAsdRep: "/register", registerAsSoleVoter: "/register_sole_voter", + retireAsSoleVoter: "/retire_sole_voter", stakeKeys: "/stake_keys", updateMetadata: "/update_metadata", }; diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index 765e24226..925f3d418 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -100,6 +100,8 @@ interface CardanoContext { isEnableLoading: string | null; error?: string; dRep: DRepInfo | undefined; + soleVoter: DRepInfo | undefined; + setSoleVoter: (key: undefined | DRepInfo) => void; isEnabled: boolean; pubDRepKey: string; dRepID: string; @@ -168,6 +170,11 @@ function CardanoProvider(props: Props) { const [isEnabled, setIsEnabled] = useState(false); const [isEnableLoading, setIsEnableLoading] = useState(null); const [dRep, setDRep] = useState(undefined); + const [soleVoter, setSoleVoter] = useState({ + deposit: 4000000, + isRegistered: false, + wasRegistered: false, + }); const [walletApi, setWalletApi] = useState( undefined ); @@ -1147,6 +1154,8 @@ function CardanoProvider(props: Props) { isDrepLoading, setIsDrepLoading, isEnableLoading, + soleVoter, + setSoleVoter, }), [ address, @@ -1180,6 +1189,8 @@ function CardanoProvider(props: Props) { isDrepLoading, setIsDrepLoading, isEnableLoading, + soleVoter, + setSoleVoter, ] ); diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index ed247a1e1..bcdea545c 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -73,9 +73,13 @@ export const en = { view: "View governance actions", }, cards: { + retire: "Retire", + youAreSoleVoterTitle: "You are a Sole Voter", + youAreSoleVoterDescription: + "Your Voting Power of ₳{{votingPower}} can be used to vote.", registerAsSoleVoterTitle: "Become a Sole Voter", registerAsSoleVoterDescription: - "Vote on Governance Actions using your own voting power of ₳{{votingPower}}", + "Vote on Governance Actions using your own voting power of ₳{{votingPower}}.", }, registration: { changeMetadata: "Change metadata", @@ -292,11 +296,15 @@ export const en = { viewAll: "View all", }, soleVoter: { + retireSoleVoter: "Retire as a Sole Voter", becomeSoleVoter: "Become a Sole Voter", continueToRegister: "Continue to register", description: "A Sole Voter is someone that can vote on any Governance Action with their own Voting Power, which is equal to the balance of ADA in their connected wallet. <0>Learn More about Sole Voter.\n\nBecoming a Sole Voter will require a refundable deposit of ₳2.\n\nYour deposit will be refunded if you either retire or delegate your voting power to someone else (a DRep)", heading: "What this Means", + retirementHeading: "What Retirement Means", + retirementDescription: + "By Retiring you are giving up your Voting Power. You will not be able to vote on any Governance Actions. Your deposit of {{deposit}} ADA will be refunded.\n\nYou can at any time in the future re-register to become a Sole Voter, or you can delegate your Voting Power to someone else, or become a DRep.\n\n<0>These options are listed in our Guides here: <1>Voting options and Roles", }, system: { sanchoNet: "SanchoNet", diff --git a/govtool/frontend/src/pages/RetireAsSoleVoter.tsx b/govtool/frontend/src/pages/RetireAsSoleVoter.tsx new file mode 100644 index 000000000..830f4ffd5 --- /dev/null +++ b/govtool/frontend/src/pages/RetireAsSoleVoter.tsx @@ -0,0 +1,180 @@ +import { useCallback, useEffect, useMemo } from "react"; +import { useNavigate } from "react-router-dom"; +import { Trans } from "react-i18next"; +import { Box, Link } from "@mui/material"; +import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; + +import { Background, Button, Typography } from "@atoms"; +import { useCardano } from "@context"; +import { ICONS, PATHS } from "@consts"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { DashboardTopNav, Footer } from "@organisms"; +import { + WALLET_LS_KEY, + correctAdaFormat, + getItemFromLocalStorage, + openInNewTab, +} from "@utils"; +import { theme } from "@/theme"; + +export const RetireAsSoleVoter = () => { + const { + palette: { boxShadow2 }, + } = theme; + const { isMobile, screenWidth } = useScreenDimension(); + const navigate = useNavigate(); + const { t } = useTranslation(); + const { soleVoter } = useCardano(); + + const navigateToDashboard = useCallback( + () => navigate(PATHS.dashboard), + [navigate] + ); + + useEffect(() => { + if ( + !getItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`) || + !getItemFromLocalStorage(`${WALLET_LS_KEY}_name`) || + !soleVoter?.isRegistered + ) { + navigate(PATHS.home); + } + }, []); + + const renderBackButton = useMemo(() => { + return ( + + ); + }, [isMobile, navigateToDashboard]); + + const renderRegisterButton = useMemo(() => { + return ( + + ); + }, [isMobile]); + + return ( + + + + + = 768 ? "center" : "inherit", + marginTop: screenWidth < 1440 ? "97px" : "153px", + display: screenWidth < 1440 ? "flex" : "grid", + ...(screenWidth < 1440 && { + flexDirection: "column", + }), + ...(screenWidth >= 1440 && { gridTemplateColumns: "1fr auto 1fr" }), + }} + > + {isMobile && ( + + + {t("soleVoter.retireSoleVoter")} + + + )} + + + + {t("backToDashboard")} + + + 768 ? 600 : undefined} + px={isMobile ? 2 : 18.75} + py={isMobile ? 6.25 : 10} + > + + + {t("soleVoter.retirementHeading")} + + + , + openInNewTab("https://sancho.network/")} + sx={{ cursor: "pointer" }} + />, + ]} + i18nKey={"soleVoter.retirementDescription"} + values={{ deposit: correctAdaFormat(soleVoter?.deposit) }} + /> + + + + {isMobile ? renderRegisterButton : renderBackButton} + + {isMobile ? renderBackButton : renderRegisterButton} + + + {isMobile &&
} + + + + ); +}; diff --git a/govtool/frontend/src/pages/index.ts b/govtool/frontend/src/pages/index.ts index e6cdcc6de..c2f422300 100644 --- a/govtool/frontend/src/pages/index.ts +++ b/govtool/frontend/src/pages/index.ts @@ -1,11 +1,12 @@ export * from "./ChooseStakeKey"; export * from "./Dashboard"; +export * from "./DashboardGovernanceActionsCategory"; export * from "./DelegateTodRep"; +export * from "./ErrorPage"; export * from "./GovernanceActionDetails"; export * from "./GovernanceActions"; export * from "./GovernanceActionsCategory"; -export * from "./DashboardGovernanceActionsCategory"; export * from "./Home"; export * from "./RegisterAsdRep"; +export * from "./RetireAsSoleVoter"; export * from "./UpdatedRepMetadata"; -export * from "./ErrorPage"; From 82077a9708f303d89ac783355b28914e723eb9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 19 Feb 2024 09:03:10 +0100 Subject: [PATCH 022/157] add retirement to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6830148d4..9c094e85f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ As a minor extension, we also keep a semantic version for the `UNRELEASED` changes. ## [Unreleased] +- Add retire as Sole Voter screen [Issue 198](https://github.com/IntersectMBO/govtool/issues/198) - Add Sole Voter card [Issue 141](https://github.com/IntersectMBO/govtool/issues/141) - Create DRep registration page about roles [Issue 205](https://github.com/IntersectMBO/govtool/issues/205) - Create Checkbox component. Improve Field and ControlledField [Issue 177](https://github.com/IntersectMBO/govtool/pull/177) From cf3a1117bf39e8811fcf27f4d36adbfc8d0fdca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 19 Feb 2024 11:34:05 +0100 Subject: [PATCH 023/157] update home cards --- .../src/components/molecules/ActionCard.tsx | 1 - .../components/organisms/DashboardCards.tsx | 4 +- .../src/components/organisms/Hero.tsx | 34 ++++++- .../src/components/organisms/HomeCards.tsx | 93 ++++++++++++++----- govtool/frontend/src/i18n/locales/en.ts | 28 +++++- govtool/frontend/src/pages/Home.tsx | 8 +- 6 files changed, 134 insertions(+), 34 deletions(-) diff --git a/govtool/frontend/src/components/molecules/ActionCard.tsx b/govtool/frontend/src/components/molecules/ActionCard.tsx index 63fc9eb03..3418c6471 100644 --- a/govtool/frontend/src/components/molecules/ActionCard.tsx +++ b/govtool/frontend/src/components/molecules/ActionCard.tsx @@ -94,7 +94,6 @@ export const ActionCard: FC = ({ ...props }) => { + ); + }, [isMobile]); + + const renderRegisterButton = useMemo(() => { + return ( + + {rightButtonText ?? t("continue")} + + ); + }, [rightButtonIsLoading, isMobile]); + + return ( + + {isMobile ? renderRegisterButton : renderBackButton} + + {isMobile ? renderBackButton : renderRegisterButton} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/CenteredBoxPageWrapper.tsx b/govtool/frontend/src/components/molecules/CenteredBoxPageWrapper.tsx new file mode 100644 index 000000000..dc9cbe0da --- /dev/null +++ b/govtool/frontend/src/components/molecules/CenteredBoxPageWrapper.tsx @@ -0,0 +1,108 @@ +import { FC, PropsWithChildren } from "react"; +import { Box, Link } from "@mui/material"; + +import { Background, Typography } from "@atoms"; +import { ICONS } from "@consts"; +import { DashboardTopNav } from "@organisms"; +import { useScreenDimension } from "@hooks"; +import { useNavigate } from "react-router-dom"; +import { theme } from "@/theme"; + +interface Props { + pageTitle: string; + backButtonText: string; + backButtonPath: string; + isVotingPowerHidden?: boolean; +} +export const CenteredBoxPageWrapper: FC> = ({ + pageTitle, + backButtonText, + backButtonPath, + isVotingPowerHidden, + children, +}) => { + const { isMobile, screenWidth, pagePadding } = useScreenDimension(); + const navigate = useNavigate(); + const { + palette: { boxShadow2 }, + } = theme; + + return ( + + + + + {isMobile && ( + + + {pageTitle} + + + )} + navigate(backButtonPath)} + > + arrow + + {backButtonText} + + + + + + {children} + + + + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/index.ts b/govtool/frontend/src/components/molecules/index.ts index 4fc87340a..cb5e9115b 100644 --- a/govtool/frontend/src/components/molecules/index.ts +++ b/govtool/frontend/src/components/molecules/index.ts @@ -1,4 +1,6 @@ export * from "./ActionCard"; +export * from "./BottomBoxButtons"; +export * from "./CenteredBoxPageWrapper"; export * from "./DashboardActionCard"; export * from "./DataActionsBar"; export * from "./DRepInfoCard"; diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index 49ae2df2c..e78353ccb 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -1,3 +1,4 @@ +import { useCallback, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { Box, CircularProgress } from "@mui/material"; import { Trans } from "react-i18next"; @@ -11,7 +12,6 @@ import { useTranslation, } from "@hooks"; import { DashboardActionCard } from "@molecules"; -import { useCallback, useMemo, useState } from "react"; import { correctAdaFormat, formHexToBech32, openInNewTab } from "@utils"; export const DashboardCards = () => { @@ -26,6 +26,7 @@ export const DashboardCards = () => { isDrepLoading, isPendingTransaction, registerTransaction, + soleVoterTransaction, stakeKey, soleVoter, } = useCardano(); @@ -413,8 +414,8 @@ export const DashboardCards = () => { @@ -428,10 +429,18 @@ export const DashboardCards = () => { } firstButtonLabel={t( soleVoter?.isRegistered - ? "dashboard.cards.retire" - : "dashboard.registration.register" + ? "dashboard.soleVoter.retire" + : "dashboard.soleVoter.register" )} firstButtonVariant={soleVoter?.isRegistered ? "outlined" : "contained"} + secondButtonVariant={ + soleVoterTransaction?.transactionHash + ? "outlined" + : soleVoter?.isRegistered + ? "text" + : "outlined" + } + inProgress={!!soleVoterTransaction?.transactionHash} imageURL={IMAGES.soleVoterImage} secondButtonAction={() => openInNewTab( @@ -442,8 +451,8 @@ export const DashboardCards = () => { secondButtonVariant={"outlined"} title={t( soleVoter?.isRegistered - ? "dashboard.cards.youAreSoleVoterTitle" - : "dashboard.cards.registerAsSoleVoterTitle" + ? "dashboard.soleVoter.youAreSoleVoterTitle" + : "dashboard.soleVoter.registerAsSoleVoterTitle" )} /> {/* REGISTARTION AS SOLE VOTER CARD END*/} diff --git a/govtool/frontend/src/components/organisms/DashboardTopNav.tsx b/govtool/frontend/src/components/organisms/DashboardTopNav.tsx index 5bf0a3be4..b02a4c2ae 100644 --- a/govtool/frontend/src/components/organisms/DashboardTopNav.tsx +++ b/govtool/frontend/src/components/organisms/DashboardTopNav.tsx @@ -15,6 +15,7 @@ type DashboardTopNavProps = { imageHeight?: number; title: string; isDrawer?: boolean; + isVotingPowerHidden?: boolean; }; const DRAWER_PADDING = 2; @@ -25,6 +26,7 @@ export const DashboardTopNav = ({ imageSRC, imageWidth, imageHeight, + isVotingPowerHidden, }: DashboardTopNavProps) => { const { isMobile, screenWidth } = useScreenDimension(); const { dRep } = useCardano(); @@ -47,6 +49,7 @@ export const DashboardTopNav = ({ zIndex={100} flex={1} width={"fill-available"} + height={"48px"} > {imageSRC ? ( @@ -66,7 +69,7 @@ export const DashboardTopNav = ({ ) : null} - + {!isVotingPowerHidden && } {isMobile && ( { + const [isLoading, setIsLoading] = useState(false); + + const { buildSignSubmitConwayCertTx, buildDRepRegCert } = useCardano(); + const navigate = useNavigate(); + const { openModal, closeModal } = useModal(); + const { t } = useTranslation(); + + const onRegister = useCallback(async () => { + setIsLoading(true); + + try { + const certBuilder = await buildDRepRegCert(); + const result = await buildSignSubmitConwayCertTx({ + certBuilder, + type: "soleVoterRegistration", + registrationType: "registration", + }); + if (result) + openModal({ + type: "statusModal", + state: { + status: "success", + title: t("modals.registration.title"), + message: t("modals.registration.message"), + link: "https://adanordic.com/latest_transactions", + buttonText: t("modals.common.goToDashboard"), + onSubmit: () => { + navigate(PATHS.dashboard); + closeModal(); + }, + dataTestId: "registration-transaction-submitted-modal", + }, + }); + } catch (e: any) { + const errorMessage = e.info ? e.info : e; + + openModal({ + type: "statusModal", + state: { + status: "warning", + title: t("modals.common.oops"), + message: errorMessage, + buttonText: t("modals.common.goToDashboard"), + onSubmit: () => { + navigate(PATHS.dashboard); + closeModal(); + }, + dataTestId: "registration-transaction-error-modal", + }, + }); + } finally { + setIsLoading(false); + } + }, [buildSignSubmitConwayCertTx, buildDRepRegCert, openModal]); + + return ( + <> + + navigate(PATHS.dashboard)} + rightButtonAction={onRegister} + rightButtonIsLoading={isLoading} + /> + + ); +}; diff --git a/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBoxContent.tsx b/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBoxContent.tsx new file mode 100644 index 000000000..9308da9f5 --- /dev/null +++ b/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBoxContent.tsx @@ -0,0 +1,48 @@ +import { Link } from "@mui/material"; +import { Trans } from "react-i18next"; + +import { Typography } from "@atoms"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { + PROTOCOL_PARAMS_KEY, + correctAdaFormat, + getItemFromLocalStorage, + openInNewTab, +} from "@utils"; + +export const RegisterAsSoleVoterBoxContent = () => { + const { isMobile } = useScreenDimension(); + const { t } = useTranslation(); + + const epochParams = getItemFromLocalStorage(PROTOCOL_PARAMS_KEY); + + return ( + <> + + {t("soleVoter.registerHeading")} + + + openInNewTab("https://sancho.network/")} + sx={{ cursor: "pointer" }} + key="0" + />, + ]} + /> + + + ); +}; diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx new file mode 100644 index 000000000..0b41dba29 --- /dev/null +++ b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx @@ -0,0 +1,86 @@ +import { useCallback, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; + +import { PATHS } from "@consts"; +import { BottomBoxButtons } from "@molecules"; +import { useCardano, useModal } from "@context"; +import { RetireAsSoleVoterBoxContent } from "@organisms"; + +export const RetireAsSoleVoterBox = () => { + const [isLoading, setIsLoading] = useState(false); + + const navigate = useNavigate(); + const { + buildDRepRetirementCert, + buildSignSubmitConwayCertTx, + isPendingTransaction, + } = useCardano(); + const { openModal, closeModal } = useModal(); + const { t } = useTranslation(); + + const onRetire = useCallback(async () => { + try { + setIsLoading(true); + const isPendingTx = isPendingTransaction(); + if (isPendingTx) return; + const certBuilder = await buildDRepRetirementCert(); + const result = await buildSignSubmitConwayCertTx({ + certBuilder, + type: "soleVoterRegistration", + registrationType: "retirement", + }); + if (result) + openModal({ + type: "statusModal", + state: { + status: "success", + title: t("modals.retirement.title"), + message: t("modals.retirement.message"), + link: `https://adanordic.com/latest_transactions`, + buttonText: t("modals.common.goToDashboard"), + dataTestId: "retirement-transaction-submitted-modal", + onSubmit: () => { + navigate(PATHS.dashboard); + closeModal(); + }, + }, + }); + } catch (error: any) { + const errorMessage = error.info ? error.info : error; + + openModal({ + type: "statusModal", + state: { + status: "warning", + message: errorMessage, + buttonText: t("modals.common.goToDashboard"), + title: t("modals.common.oops"), + dataTestId: "retirement-transaction-error-modal", + onSubmit: () => { + navigate(PATHS.dashboard); + closeModal(); + }, + }, + }); + } finally { + setIsLoading(false); + } + }, [ + buildDRepRetirementCert, + buildSignSubmitConwayCertTx, + isPendingTransaction, + openModal, + ]); + + return ( + <> + + navigate(PATHS.dashboard)} + rightButtonAction={onRetire} + rightButtonIsLoading={isLoading} + /> + + ); +}; diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx new file mode 100644 index 000000000..67fcc97d6 --- /dev/null +++ b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx @@ -0,0 +1,43 @@ +import { Link } from "@mui/material"; +import { Trans } from "react-i18next"; + +import { Typography } from "@atoms"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { correctAdaFormat, openInNewTab } from "@/utils"; +import { useCardano } from "@/context"; + +export const RetireAsSoleVoterBoxContent = () => { + const { isMobile } = useScreenDimension(); + const { t } = useTranslation(); + const { soleVoter } = useCardano(); + + return ( + <> + + {t("soleVoter.retirementHeading")} + + + openInNewTab("https://sancho.network/")} + sx={{ cursor: "pointer" }} + key="0" + />, + ]} + /> + + + ); +}; diff --git a/govtool/frontend/src/components/organisms/SoleVoterInfo.tsx b/govtool/frontend/src/components/organisms/SoleVoterInfo.tsx deleted file mode 100644 index 4eb34dafe..000000000 --- a/govtool/frontend/src/components/organisms/SoleVoterInfo.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { useMemo } from "react"; -import { Box, Link } from "@mui/material"; - -import { LoadingButton, Button, Typography } from "@atoms"; -import { theme } from "@/theme"; -import { useScreenDimension, useTranslation } from "@hooks"; -import { Trans } from "react-i18next"; -import { openInNewTab } from "@/utils"; -import { useNavigate } from "react-router-dom"; -import { PATHS } from "@consts"; - -export const SoleVoterInfo = () => { - const { - palette: { boxShadow2 }, - } = theme; - const { isMobile, pagePadding, screenWidth } = useScreenDimension(); - const navigate = useNavigate(); - const { t } = useTranslation(); - - const renderBackButton = useMemo(() => { - return ( - - ); - }, [isMobile]); - - const renderRegisterButton = useMemo(() => { - return ( - {}} - sx={{ - borderRadius: 50, - textTransform: "none", - px: 6, - width: isMobile ? "100%" : "auto", - height: 48, - }} - variant="contained" - > - {t("soleVoter.continueToRegister")} - - ); - }, [ - // isLoading, - isMobile, - ]); - - return ( - - - - {t("soleVoter.heading")} - - - openInNewTab("https://sancho.network/")} - sx={{ cursor: "pointer" }} - key="0" - />, - ]} - /> - - - - {isMobile ? renderRegisterButton : renderBackButton} - - {isMobile ? renderBackButton : renderRegisterButton} - - - ); -}; diff --git a/govtool/frontend/src/components/organisms/index.ts b/govtool/frontend/src/components/organisms/index.ts index 1906a2e23..5387a425c 100644 --- a/govtool/frontend/src/components/organisms/index.ts +++ b/govtool/frontend/src/components/organisms/index.ts @@ -1,6 +1,7 @@ export * from "./BgCard"; export * from "./ChooseStakeKeyPanel"; export * from "./ChooseWalletModal"; +export * from "./ControlledField"; export * from "./DashboardCards"; export * from "./DashboardCards"; export * from "./DashboardGovernanceActionDetails"; @@ -21,8 +22,10 @@ export * from "./RegisterAsdRepStepOne"; export * from "./RegisterAsdRepStepThree"; export * from "./RegisterAsdRepStepTwo"; export * from "./Slider"; +export * from "./RegisterAsSoleVoterBoxContent"; +export * from "./RegisterAsSoleVoterBox"; +export * from "./RetireAsSoleVoterBoxContent"; +export * from "./RetireAsSoleVoterBox"; export * from "./StatusModal"; export * from "./TopNav"; export * from "./VotingPowerModal"; - -export * from "./ControlledField"; diff --git a/govtool/frontend/src/consts/icons.ts b/govtool/frontend/src/consts/icons.ts index c6facbf60..93574c43b 100644 --- a/govtool/frontend/src/consts/icons.ts +++ b/govtool/frontend/src/consts/icons.ts @@ -2,6 +2,7 @@ export const ICONS = { appLogoIcon: "/icons/AppLogo.svg", arrowDownIcon: "/icons/ArrowDown.svg", arrowRightIcon: "/icons/ArrowRight.svg", + arrowLeftThinIcon: "/icons/ArrowLeftThin.svg", checkCircleIcon: "/icons/CheckCircle.svg", closeDrawerIcon: "/icons/CloseIcon.svg", closeIcon: "/icons/Close.svg", diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index 925f3d418..31eaf2626 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -66,6 +66,7 @@ import { SANCHO_INFO_KEY, VOTE_TRANSACTION_KEY, checkIsMaintenanceOn, + REGISTER_SOLE_VOTER_TRANSACTION_KEY, } from "@utils"; import { getEpochParams, getTransactionStatus } from "@services"; import { @@ -122,7 +123,7 @@ interface CardanoContext { }: { certBuilder?: CertificatesBuilder; votingBuilder?: VotingBuilder; - type?: "delegation" | "registration" | "vote"; + type?: "delegation" | "registration" | "soleVoterRegistration" | "vote"; proposalId?: string; registrationType?: DRepActionType; }) => Promise; @@ -145,6 +146,9 @@ interface CardanoContext { ) => Promise; delegateTransaction: TransactionHistoryItem; registerTransaction: TransactionHistoryItem & { type: DRepActionType }; + soleVoterTransaction: TransactionHistoryItem & { + type: Omit; + }; delegateTo: string; voteTransaction: TransactionHistoryItem & { proposalId: string }; isPendingTransaction: () => boolean; @@ -208,6 +212,9 @@ function CardanoProvider(props: Props) { const [registerTransaction, setRegisterTransaction] = useState< TransactionHistoryItem & { type: DRepActionType } >({ time: undefined, transactionHash: "", type: "" }); + const [soleVoterTransaction, setSoleVoterTransaction] = useState< + TransactionHistoryItem & { type: Omit } + >({ time: undefined, transactionHash: "", type: "" }); const [voteTransaction, setVoteTransaction] = useState< { proposalId: string } & TransactionHistoryItem >({ time: undefined, transactionHash: "", proposalId: "" }); @@ -219,6 +226,7 @@ function CardanoProvider(props: Props) { const isPendingTransaction = useCallback(() => { if ( registerTransaction?.transactionHash || + soleVoterTransaction?.transactionHash || delegateTransaction?.transactionHash || voteTransaction?.transactionHash ) { @@ -243,6 +251,7 @@ function CardanoProvider(props: Props) { delegateTransaction?.transactionHash, openModal, registerTransaction?.transactionHash, + soleVoterTransaction?.transactionHash, voteTransaction?.transactionHash, ]); @@ -253,6 +262,11 @@ function CardanoProvider(props: Props) { const registerTransaction = JSON.parse( getItemFromLocalStorage(REGISTER_TRANSACTION_KEY + `_${stakeKey}`) ); + const soleVoterTransaction = JSON.parse( + getItemFromLocalStorage( + REGISTER_SOLE_VOTER_TRANSACTION_KEY + `_${stakeKey}` + ) + ); const voteTransaction = JSON.parse( getItemFromLocalStorage(VOTE_TRANSACTION_KEY + `_${stakeKey}`) ); @@ -265,6 +279,9 @@ function CardanoProvider(props: Props) { if (registerTransaction?.transactionHash) { setRegisterTransaction(registerTransaction); } + if (soleVoterTransaction?.transactionHash) { + setSoleVoterTransaction(soleVoterTransaction); + } if (voteTransaction?.transactionHash) { setVoteTransaction(voteTransaction); } @@ -385,6 +402,71 @@ function CardanoProvider(props: Props) { let interval = setInterval(checkRegisterTransaction, REFRESH_TIME); checkRegisterTransaction(); } + if (soleVoterTransaction?.transactionHash) { + const checkRegisterTransaction = async () => { + const resetRegisterTransaction = () => { + clearInterval(interval); + removeItemFromLocalStorage( + REGISTER_SOLE_VOTER_TRANSACTION_KEY + `_${stakeKey}` + ); + setSoleVoterTransaction({ + time: undefined, + transactionHash: "", + type: "", + }); + }; + const status = await getTransactionStatus( + soleVoterTransaction.transactionHash + ); + if (status.transactionConfirmed) { + if (isEnabled) { + await setLimitedRegistrationInterval( + 3000, + 10, + dRepID, + soleVoterTransaction.type, + setDRep + ).then((isRegistered) => { + if (soleVoterTransaction.type === "registration") { + if (isRegistered) { + addSuccessAlert(t("alerts.soleVoterRegistration.success")); + } else { + addWarningAlert( + t("alerts.soleVoterRegistration.refreshPage") + ); + } + } else if (soleVoterTransaction.type === "retirement") { + if (!isRegistered) { + addSuccessAlert(t("alerts.soleVoterRetirement.success")); + } else { + addWarningAlert(t("alerts.soleVoterRetirement.refreshPage")); + } + } + }); + } + resetRegisterTransaction(); + } + if ( + new Date().getTime() - + new Date(soleVoterTransaction?.time).getTime() > + TIME_TO_EXPIRE_TRANSACTION + ) { + resetRegisterTransaction(); + if (isEnabled) + addErrorAlert( + t( + `alerts.${ + soleVoterTransaction.type === "retirement" + ? "retirement.failed" + : "registration.failed" + }` + ) + ); + } + }; + let interval = setInterval(checkRegisterTransaction, REFRESH_TIME); + checkRegisterTransaction(); + } if (voteTransaction?.transactionHash) { const checkVoteTransaction = async () => { const resetVoteTransaction = () => { @@ -418,11 +500,17 @@ function CardanoProvider(props: Props) { isEnabled && (voteTransaction?.transactionHash || registerTransaction?.transactionHash || + soleVoterTransaction?.transactionHash || delegateTransaction?.transactionHash) ) { addWarningAlert(t("alerts.transactionInProgress"), 10000); } - }, [delegateTransaction, registerTransaction, voteTransaction]); + }, [ + delegateTransaction, + registerTransaction, + soleVoterTransaction, + voteTransaction, + ]); const getChangeAddress = async (enabledApi: CardanoApiWallet) => { try { @@ -726,7 +814,7 @@ function CardanoProvider(props: Props) { }: { certBuilder?: CertificatesBuilder; votingBuilder?: VotingBuilder; - type?: "delegation" | "registration" | "vote"; + type?: "delegation" | "registration" | "soleVoterRegistration" | "vote"; proposalId?: string; registrationType?: DRepActionType; }) => { @@ -849,6 +937,21 @@ function CardanoProvider(props: Props) { }) ); } + if (type === "soleVoterRegistration" && registrationType !== "update") { + setSoleVoterTransaction({ + time: new Date(), + transactionHash: resultHash, + type: registrationType ?? "", + }); + setItemToLocalStorage( + REGISTER_SOLE_VOTER_TRANSACTION_KEY + `_${stakeKey}`, + JSON.stringify({ + time: new Date(), + transactionHash: resultHash, + type: registrationType, + }) + ); + } if (type === "delegation") { setDelegateTransaction({ time: new Date(), @@ -899,6 +1002,7 @@ function CardanoProvider(props: Props) { walletApi, getUtxos, registerTransaction.transactionHash, + soleVoterTransaction.transactionHash, delegateTransaction.transactionHash, voteTransaction.transactionHash, stakeKey, @@ -1148,6 +1252,7 @@ function CardanoProvider(props: Props) { buildVoteDelegationCert, delegateTransaction, registerTransaction, + soleVoterTransaction, delegateTo, voteTransaction, isPendingTransaction, @@ -1183,6 +1288,7 @@ function CardanoProvider(props: Props) { buildVoteDelegationCert, delegateTransaction, registerTransaction, + soleVoterTransaction, delegateTo, voteTransaction, isPendingTransaction, diff --git a/govtool/frontend/src/context/walletUtils.ts b/govtool/frontend/src/context/walletUtils.ts index 5bf0be32a..e722e4c84 100644 --- a/govtool/frontend/src/context/walletUtils.ts +++ b/govtool/frontend/src/context/walletUtils.ts @@ -6,7 +6,7 @@ export const setLimitedRegistrationInterval = ( intervalTime: number, attemptsNumber: number, dRepID: string, - transactionType: DRepActionType, + transactionType: DRepActionType | Omit, setDRep: (key: undefined | DRepInfo) => void ): Promise => { return new Promise(async (resolve) => { diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index b1d413e2e..267f26abf 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -23,6 +23,16 @@ export const en = { "You have successfully retired from being a DRep! Please refresh the page.", success: "You have successfully retired from being a DRep!", }, + soleVoterRegistration: { + refreshPage: + "You have successfully registered as a Sole Voter! Please refresh the page.", + success: "You have successfully registered as a Sole Voter!", + }, + soleVoterRetirement: { + refreshPage: + "You have successfully retired from being a Sole Voter! Please refresh the page.", + success: "You have successfully retired from being a SoleVoter!", + }, voting: { failed: "Vote transaction failed", success: "You have successfully voted!", @@ -37,11 +47,8 @@ export const en = { headingTwo: "See Active Governance Actions", delegation: { changeDelegation: "Change delegation", - connectToDelegate: "Connect to delegate", delegateOwnPower: "If you want to delegate your own voting power of ₳{{ada}}.", - description: - "If you want to delegate to a DRep or select a default option.", dRepDelegatedTo: "DRep you delegated to", toDRep: "You have delegated your voting power of ₳{{ada}} to a selected DRep.", @@ -72,23 +79,11 @@ export const en = { title: "Governance Actions", view: "View governance actions", }, - cards: { - retire: "Retire", - youAreSoleVoterTitle: "You are a Sole Voter", - youAreSoleVoterDescription: - "Your Voting Power of ₳{{votingPower}} can be used to vote.", - registerAsSoleVoterTitle: "Become a Sole Voter", - registerAsSoleVoterDescription: - "Vote on Governance Actions using your own voting power of ₳{{votingPower}}.", - }, registration: { changeMetadata: "Change metadata", - connectToRegister: "Connect to register", dRepRegistration: "DRep Registration", dRepRetirement: "DRep Retirement", dRepUpdate: "DRep Update", - description: - "If you want to directly participate in voting and have other ada holders delegate their voting power to you.", holdersCanDelegate: "Ada holders can delegate their voting power to you.", ifYouWant: @@ -105,24 +100,15 @@ export const en = { "The retirement process is ongoing. This may take several minutes.", youAreRegistered: "You are Registered as a DRep", }, - }, - home: { - cards: { - delegateDescription: "Find a DRep to vote on your behalf.", - delegateFirstButtonLabel: "View DRep Direcotry", - delegateTitle: "Delegate your Voting Power", - governaneActionsDescription: - "See all the Governance Actions submitted on chain. ", - governanceActionsFirstButtonLabel: "View Governance Actions", - governaneActionsTitle: "View Governance Actions", - registerAsDRepDescription: - "Accept delegated voting power from other ADA holders, and combine it with your own voting power. Vote with the accumulated Power on Governance Actions.", - registerAsDRepFirstButtonLabel: "Connect to Register", - registerAsDRepTitle: "Become a DRep", + soleVoter: { + register: "Register", registerAsSoleVoterDescription: - "Vote on Governance Actions using your own voting power", - registerAsSoleVoterFirstButtonLabel: "Connect to Register", + "Vote on Governance Actions using your own voting power of ₳{{votingPower}}.", registerAsSoleVoterTitle: "Become a Sole Voter", + retire: "Retire", + youAreSoleVoterDescription: + "Your Voting Power of ₳{{votingPower}} can be used to vote.", + youAreSoleVoterTitle: "You are a Sole Voter", }, }, delegation: { @@ -246,6 +232,25 @@ export const en = { }, headline: "SanchoNet \n Governance Tool", }, + home: { + cards: { + delegateDescription: "Find a DRep to vote on your behalf.", + delegateFirstButtonLabel: "View DRep Direcotry", + delegateTitle: "Delegate your Voting Power", + governaneActionsDescription: + "See all the Governance Actions submitted on chain. ", + governanceActionsFirstButtonLabel: "View Governance Actions", + governaneActionsTitle: "View Governance Actions", + registerAsDRepDescription: + "Accept delegated voting power from other ADA holders, and combine it with your own voting power. Vote with the accumulated Power on Governance Actions.", + registerAsDRepFirstButtonLabel: "Connect to Register", + registerAsDRepTitle: "Become a DRep", + registerAsSoleVoterDescription: + "Vote on Governance Actions using your own voting power", + registerAsSoleVoterFirstButtonLabel: "Connect to Register", + registerAsSoleVoterTitle: "Become a Sole Voter", + }, + }, menu: { faqs: "FAQs", guides: "Guides", @@ -320,13 +325,12 @@ export const en = { soleVoter: { retireSoleVoter: "Retire as a Sole Voter", becomeSoleVoter: "Become a Sole Voter", - continueToRegister: "Continue to register", - description: - "A Sole Voter is someone that can vote on any Governance Action with their own Voting Power, which is equal to the balance of ADA in their connected wallet. <0>Learn More about Sole Voter.\n\nBecoming a Sole Voter will require a refundable deposit of ₳2.\n\nYour deposit will be refunded if you either retire or delegate your voting power to someone else (a DRep)", - heading: "What this Means", + registerDescription: + "A Sole Voter is someone that can vote on any Governance Action with their own Voting Power, which is equal to the balance of ADA in their connected wallet. <0>Learn More about Sole Voter.\n\nBecoming a Sole Voter will require a refundable deposit of ₳{{deposit}}.\n\nYour deposit will be refunded if you either retire or delegate your voting power to someone else (a DRep)", + registerHeading: "What this Means", retirementHeading: "What Retirement Means", retirementDescription: - "By Retiring you are giving up your Voting Power. You will not be able to vote on any Governance Actions. Your deposit of {{deposit}} ADA will be refunded.\n\nYou can at any time in the future re-register to become a Sole Voter, or you can delegate your Voting Power to someone else, or become a DRep.\n\n<0>These options are listed in our Guides here: <1>Voting options and Roles", + "By Retiring you are giving up your Voting Power. You will not be able to vote on any Governance Actions. Your deposit of {{deposit}} ADA will be refunded.\n\nYou can at any time in the future re-register to become a Sole Voter, or you can delegate your Voting Power to someone else, or become a DRep.\n\nThese options are listed in our Guides here: <0>Voting options and Roles", }, system: { sanchoNet: "SanchoNet", diff --git a/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx index 370a5fefc..ea7018a85 100644 --- a/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx +++ b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx @@ -1,16 +1,13 @@ import { useEffect } from "react"; -import { Box, Link } from "@mui/material"; - -import { Background, Typography } from "@atoms"; -import { ICONS, PATHS } from "@consts"; -import { DashboardTopNav, Footer } from "@organisms"; -import { useScreenDimension, useTranslation } from "@hooks"; import { useNavigate } from "react-router-dom"; + +import { PATHS } from "@consts"; +import { RegisterAsSoleVoterBox } from "@organisms"; +import { useTranslation } from "@hooks"; import { WALLET_LS_KEY, getItemFromLocalStorage } from "@/utils/localStorage"; -import { SoleVoterInfo } from "@/components/organisms/SoleVoterInfo"; +import { CenteredBoxPageWrapper } from "@molecules"; export const RegisterAsSoleVoter = () => { - const { isMobile, screenWidth } = useScreenDimension(); const navigate = useNavigate(); const { t } = useTranslation(); @@ -24,87 +21,13 @@ export const RegisterAsSoleVoter = () => { }, []); return ( - - - - - - {isMobile && ( - - - {t("soleVoter.becomeSoleVoter")} - - - )} - navigate(PATHS.dashboard)} - > - arrow - - {t("backToDashboard")} - - - - - {isMobile &&
} - - + + + ); }; diff --git a/govtool/frontend/src/pages/RetireAsSoleVoter.tsx b/govtool/frontend/src/pages/RetireAsSoleVoter.tsx index 830f4ffd5..c661be2cd 100644 --- a/govtool/frontend/src/pages/RetireAsSoleVoter.tsx +++ b/govtool/frontend/src/pages/RetireAsSoleVoter.tsx @@ -1,180 +1,32 @@ -import { useCallback, useEffect, useMemo } from "react"; -import { useNavigate } from "react-router-dom"; -import { Trans } from "react-i18next"; -import { Box, Link } from "@mui/material"; -import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; +import { useEffect } from "react"; -import { Background, Button, Typography } from "@atoms"; -import { useCardano } from "@context"; -import { ICONS, PATHS } from "@consts"; -import { useScreenDimension, useTranslation } from "@hooks"; -import { DashboardTopNav, Footer } from "@organisms"; -import { - WALLET_LS_KEY, - correctAdaFormat, - getItemFromLocalStorage, - openInNewTab, -} from "@utils"; -import { theme } from "@/theme"; +import { PATHS } from "@consts"; +import { RetireAsSoleVoterBox } from "@organisms"; +import { useTranslation } from "@hooks"; +import { useNavigate } from "react-router-dom"; +import { WALLET_LS_KEY, getItemFromLocalStorage } from "@/utils/localStorage"; +import { CenteredBoxPageWrapper } from "@molecules"; export const RetireAsSoleVoter = () => { - const { - palette: { boxShadow2 }, - } = theme; - const { isMobile, screenWidth } = useScreenDimension(); const navigate = useNavigate(); const { t } = useTranslation(); - const { soleVoter } = useCardano(); - - const navigateToDashboard = useCallback( - () => navigate(PATHS.dashboard), - [navigate] - ); useEffect(() => { if ( !getItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`) || - !getItemFromLocalStorage(`${WALLET_LS_KEY}_name`) || - !soleVoter?.isRegistered + !getItemFromLocalStorage(`${WALLET_LS_KEY}_name`) ) { navigate(PATHS.home); } }, []); - const renderBackButton = useMemo(() => { - return ( - - ); - }, [isMobile, navigateToDashboard]); - - const renderRegisterButton = useMemo(() => { - return ( - - ); - }, [isMobile]); - return ( - - - - - = 768 ? "center" : "inherit", - marginTop: screenWidth < 1440 ? "97px" : "153px", - display: screenWidth < 1440 ? "flex" : "grid", - ...(screenWidth < 1440 && { - flexDirection: "column", - }), - ...(screenWidth >= 1440 && { gridTemplateColumns: "1fr auto 1fr" }), - }} - > - {isMobile && ( - - - {t("soleVoter.retireSoleVoter")} - - - )} - - - - {t("backToDashboard")} - - - 768 ? 600 : undefined} - px={isMobile ? 2 : 18.75} - py={isMobile ? 6.25 : 10} - > - - - {t("soleVoter.retirementHeading")} - - - , - openInNewTab("https://sancho.network/")} - sx={{ cursor: "pointer" }} - />, - ]} - i18nKey={"soleVoter.retirementDescription"} - values={{ deposit: correctAdaFormat(soleVoter?.deposit) }} - /> - - - - {isMobile ? renderRegisterButton : renderBackButton} - - {isMobile ? renderBackButton : renderRegisterButton} - - - {isMobile &&
} - - - + + + ); }; diff --git a/govtool/frontend/src/utils/localStorage.ts b/govtool/frontend/src/utils/localStorage.ts index 51d03347f..8655509fb 100644 --- a/govtool/frontend/src/utils/localStorage.ts +++ b/govtool/frontend/src/utils/localStorage.ts @@ -1,6 +1,8 @@ export const WALLET_LS_KEY = "wallet_data"; export const DELEGATE_TRANSACTION_KEY = "delegate_transaction"; export const REGISTER_TRANSACTION_KEY = "register_transaction"; +export const REGISTER_SOLE_VOTER_TRANSACTION_KEY = + "register_sole_voter_transaction"; export const DELEGATE_TO_KEY = "delegate_to_transaction"; export const PROTOCOL_PARAMS_KEY = "protocol_params"; export const SANCHO_INFO_KEY = "sancho_info"; From 758b83c3e91a53675df7dbab29f1edfa281154c0 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Wed, 21 Feb 2024 10:56:02 +0100 Subject: [PATCH 025/157] Minor refactor --- ...ttons.tsx => CenteredBoxBottomButtons.tsx} | 40 +++++++++---------- .../src/components/molecules/index.ts | 2 +- .../organisms/RegisterAsSoleVoterBox.tsx | 10 ++--- .../organisms/RetireAsSoleVoterBox.tsx | 10 ++--- .../organisms/RetireAsSoleVoterBoxContent.tsx | 1 + 5 files changed, 32 insertions(+), 31 deletions(-) rename govtool/frontend/src/components/molecules/{BottomBoxButtons.tsx => CenteredBoxBottomButtons.tsx} (62%) diff --git a/govtool/frontend/src/components/molecules/BottomBoxButtons.tsx b/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx similarity index 62% rename from govtool/frontend/src/components/molecules/BottomBoxButtons.tsx rename to govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx index c54a6627c..3da36563c 100644 --- a/govtool/frontend/src/components/molecules/BottomBoxButtons.tsx +++ b/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx @@ -5,19 +5,19 @@ import { Button, LoadingButton } from "@atoms"; import { useScreenDimension, useTranslation } from "@hooks"; interface Props { - leftButtonAction: () => void; - rightButtonAction: () => void; - rightButtonIsLoading?: boolean; - leftButtonText?: string; - rightButtonText?: string; + onBackButton: () => void; + onActionButton: () => void; + isLoading?: boolean; + backButtonText?: string; + actionButtonText?: string; } -export const BottomBoxButtons = ({ - leftButtonAction, - rightButtonAction, - rightButtonIsLoading, - leftButtonText, - rightButtonText, +export const CenteredBoxBottomButtons = ({ + onBackButton, + onActionButton, + isLoading, + backButtonText, + actionButtonText, }: Props) => { const { isMobile } = useScreenDimension(); const { t } = useTranslation(); @@ -26,7 +26,7 @@ export const BottomBoxButtons = ({ return ( ); }, [isMobile]); - const renderRegisterButton = useMemo(() => { + const renderActionButton = useMemo(() => { return ( - {rightButtonText ?? t("continue")} + {actionButtonText ?? t("continue")} ); - }, [rightButtonIsLoading, isMobile]); + }, [isLoading, isMobile]); return ( - {isMobile ? renderRegisterButton : renderBackButton} + {isMobile ? renderActionButton : renderBackButton} - {isMobile ? renderBackButton : renderRegisterButton} + {isMobile ? renderBackButton : renderActionButton} ); }; diff --git a/govtool/frontend/src/components/molecules/index.ts b/govtool/frontend/src/components/molecules/index.ts index cb5e9115b..7b4c1668f 100644 --- a/govtool/frontend/src/components/molecules/index.ts +++ b/govtool/frontend/src/components/molecules/index.ts @@ -1,5 +1,5 @@ export * from "./ActionCard"; -export * from "./BottomBoxButtons"; +export * from "./CenteredBoxBottomButtons"; export * from "./CenteredBoxPageWrapper"; export * from "./DashboardActionCard"; export * from "./DataActionsBar"; diff --git a/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx b/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx index 4034e6f01..1794a7042 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx +++ b/govtool/frontend/src/components/organisms/RegisterAsSoleVoterBox.tsx @@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next"; import { PATHS } from "@consts"; import { RegisterAsSoleVoterBoxContent } from "@organisms"; -import { BottomBoxButtons } from "@molecules"; +import { CenteredBoxBottomButtons } from "@molecules"; import { useCardano, useModal } from "@context"; export const RegisterAsSoleVoterBox = () => { @@ -66,10 +66,10 @@ export const RegisterAsSoleVoterBox = () => { return ( <> - navigate(PATHS.dashboard)} - rightButtonAction={onRegister} - rightButtonIsLoading={isLoading} + navigate(PATHS.dashboard)} + onActionButton={onRegister} + isLoading={isLoading} /> ); diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx index 0b41dba29..b2518b9e4 100644 --- a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx +++ b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx @@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { PATHS } from "@consts"; -import { BottomBoxButtons } from "@molecules"; +import { CenteredBoxBottomButtons } from "@molecules"; import { useCardano, useModal } from "@context"; import { RetireAsSoleVoterBoxContent } from "@organisms"; @@ -76,10 +76,10 @@ export const RetireAsSoleVoterBox = () => { return ( <> - navigate(PATHS.dashboard)} - rightButtonAction={onRetire} - rightButtonIsLoading={isLoading} + navigate(PATHS.dashboard)} + onActionButton={onRetire} + isLoading={isLoading} /> ); diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx index 67fcc97d6..a05bb424b 100644 --- a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx +++ b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx @@ -23,6 +23,7 @@ export const RetireAsSoleVoterBoxContent = () => { mt: isMobile ? 4 : 10, textAlign: "center", whiteSpace: "pre-line", + textDecoration: "underline", }} variant="body1" > From b0b5c87a6c6a9f7b2ba55f72ce6bc918efe02f29 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Mon, 26 Feb 2024 14:24:25 +0100 Subject: [PATCH 026/157] [#119] Fixes after CR --- .../components/molecules/CenteredBoxBottomButtons.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx b/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx index 3da36563c..5ca687317 100644 --- a/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx +++ b/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx @@ -30,7 +30,6 @@ export const CenteredBoxBottomButtons = ({ size="extraLarge" sx={{ px: 6, - width: isMobile ? "100%" : "auto", }} variant="outlined" > @@ -46,10 +45,7 @@ export const CenteredBoxBottomButtons = ({ isLoading={isLoading} onClick={onActionButton} sx={{ - borderRadius: 50, - textTransform: "none", px: 6, - width: isMobile ? "100%" : "auto", height: 48, fontSize: 16, }} @@ -63,13 +59,13 @@ export const CenteredBoxBottomButtons = ({ return ( - {isMobile ? renderActionButton : renderBackButton} + {renderBackButton} - {isMobile ? renderBackButton : renderActionButton} + {renderActionButton} ); }; From 60b67444eedb6efff9a3c22feacb66a9df4f61e4 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Thu, 22 Feb 2024 09:46:28 +0100 Subject: [PATCH 027/157] [#210] Sole voter wallet logic for registration and retirement --- govtool/frontend/src/App.tsx | 6 +-- .../src/components/atoms/VotingPowerChips.tsx | 10 ++-- .../components/molecules/VoteActionForm.tsx | 4 +- .../components/organisms/DashboardCards.tsx | 53 +++++++++---------- .../DashboardGovernanceActionDetails.tsx | 4 +- .../organisms/DashboardGovernanceActions.tsx | 4 +- .../components/organisms/DashboardTopNav.tsx | 4 +- .../organisms/DelegateTodRepStepOne.tsx | 6 +-- .../src/components/organisms/Drawer.tsx | 4 +- .../organisms/RetireAsSoleVoterBoxContent.tsx | 4 +- govtool/frontend/src/context/wallet.tsx | 30 +++++------ govtool/frontend/src/context/walletUtils.ts | 8 +-- govtool/frontend/src/hooks/index.ts | 1 - govtool/frontend/src/hooks/mutations/index.ts | 7 --- .../useAdaHolderDelegateAbstainMutation.ts | 10 ---- .../mutations/useAdaHolderDelegateMutation.ts | 10 ---- .../useAdaHolderDelegateNoMutation.ts | 10 ---- .../useAdaHolderRemoveDelegationMutation.ts | 10 ---- .../mutations/useDRepRegisterMutation.ts | 22 -------- .../mutations/useDRepRemoveVoteMutation.ts | 10 ---- .../hooks/mutations/useDRepRetireMutation.ts | 23 -------- govtool/frontend/src/i18n/locales/en.ts | 9 ++-- govtool/frontend/src/models/api.ts | 10 ++-- .../DashboardGovernanceActionsCategory.tsx | 4 +- .../src/pages/GovernanceActionsCategory.tsx | 4 +- .../src/services/requests/getDRepInfo.ts | 4 +- 26 files changed, 84 insertions(+), 187 deletions(-) delete mode 100644 govtool/frontend/src/hooks/mutations/index.ts delete mode 100644 govtool/frontend/src/hooks/mutations/useAdaHolderDelegateAbstainMutation.ts delete mode 100644 govtool/frontend/src/hooks/mutations/useAdaHolderDelegateMutation.ts delete mode 100644 govtool/frontend/src/hooks/mutations/useAdaHolderDelegateNoMutation.ts delete mode 100644 govtool/frontend/src/hooks/mutations/useAdaHolderRemoveDelegationMutation.ts delete mode 100644 govtool/frontend/src/hooks/mutations/useDRepRegisterMutation.ts delete mode 100644 govtool/frontend/src/hooks/mutations/useDRepRemoveVoteMutation.ts delete mode 100644 govtool/frontend/src/hooks/mutations/useDRepRetireMutation.ts diff --git a/govtool/frontend/src/App.tsx b/govtool/frontend/src/App.tsx index a36a89f8f..fc659e428 100644 --- a/govtool/frontend/src/App.tsx +++ b/govtool/frontend/src/App.tsx @@ -34,7 +34,7 @@ import { useGetDRepInfo, useWalletConnectionListener } from "./hooks"; import { RegisterAsSoleVoter } from "./pages/RegisterAsSoleVoter"; export default function App() { - const { enable, setDRep, setIsDrepLoading } = useCardano(); + const { enable, setUser, setIsDrepLoading } = useCardano(); const navigate = useNavigate(); const { data } = useGetDRepInfo(); const { modal, openModal, modals } = useModal(); @@ -47,11 +47,11 @@ export default function App() { useEffect(() => { setIsDrepLoading(true); - setDRep(data); + setUser(data); const timer = setTimeout(() => setIsDrepLoading(false), 1000); return () => clearTimeout(timer); - }, [data?.isRegistered]); + }, [data?.isRegisteredAsDRep]); const checkTheWalletIsActive = useCallback(() => { const hrefCondition = diff --git a/govtool/frontend/src/components/atoms/VotingPowerChips.tsx b/govtool/frontend/src/components/atoms/VotingPowerChips.tsx index 897ec0ce8..6dbeb0d6a 100644 --- a/govtool/frontend/src/components/atoms/VotingPowerChips.tsx +++ b/govtool/frontend/src/components/atoms/VotingPowerChips.tsx @@ -13,7 +13,7 @@ import { correctAdaFormat } from "@utils"; import { Tooltip } from "@atoms"; export const VotingPowerChips = () => { - const { dRep, stakeKey, isDrepLoading } = useCardano(); + const { user, stakeKey, isDrepLoading } = useCardano(); const { dRepVotingPower, isDRepVotingPowerLoading } = useGetDRepVotingPowerQuery(); const { votingPower, powerIsLoading } = @@ -33,7 +33,7 @@ export const VotingPowerChips = () => { alignItems="center" maxHeight={isMobile ? undefined : 48} > - {dRep?.isRegistered && ( + {user?.isRegisteredAsDRep && ( { {t("votingPower")} )} - {(dRep?.isRegistered && isDRepVotingPowerLoading) || - (!dRep?.isRegistered && powerIsLoading) || + {(user?.isRegisteredAsDRep && isDRepVotingPowerLoading) || + (!user?.isRegisteredAsDRep && powerIsLoading) || isDrepLoading ? ( ) : ( @@ -67,7 +67,7 @@ export const VotingPowerChips = () => { sx={{ whiteSpace: "nowrap" }} > ₳{" "} - {dRep?.isRegistered + {user?.isRegisteredAsDRep ? correctAdaFormat(dRepVotingPower) ?? 0 : correctAdaFormat(votingPower) ?? 0} diff --git a/govtool/frontend/src/components/molecules/VoteActionForm.tsx b/govtool/frontend/src/components/molecules/VoteActionForm.tsx index 3c1645bd2..9a4efbb95 100644 --- a/govtool/frontend/src/components/molecules/VoteActionForm.tsx +++ b/govtool/frontend/src/components/molecules/VoteActionForm.tsx @@ -25,7 +25,7 @@ export const VoteActionForm = ({ const [isContext, setIsContext] = useState(false); const { isMobile, screenWidth } = useScreenDimension(); const { openModal } = useModal(); - const { dRep } = useCardano(); + const { user } = useCardano(); const { t } = useTranslation(); const { @@ -142,7 +142,7 @@ export const VoteActionForm = ({ /> - {dRep?.isRegistered && ( + {user?.isRegisteredAsDRep && ( + ); + }, [isMobile]); + + const renderRegisterButton = useMemo(() => { + return ( + {}} + sx={{ + borderRadius: 50, + textTransform: "none", + px: 6, + width: isMobile ? "100%" : "auto", + height: 48, + }} + variant="contained" + > + {t("soleVoter.continueToRegister")} + + ); + }, [ + // isLoading, + isMobile, + ]); + + return ( + + + + {t("soleVoter.heading")} + + + openInNewTab("https://sancho.network/")} + sx={{ cursor: "pointer" }} + key="0" + />, + ]} + /> + + + + {isMobile ? renderRegisterButton : renderBackButton} + + {isMobile ? renderBackButton : renderRegisterButton} + + + ); +}; diff --git a/govtool/frontend/src/consts/paths.ts b/govtool/frontend/src/consts/paths.ts index 645f4e695..8af3a6381 100644 --- a/govtool/frontend/src/consts/paths.ts +++ b/govtool/frontend/src/consts/paths.ts @@ -16,6 +16,7 @@ export const PATHS = { faqs: "/faqs", delegateTodRep: "/delegate", registerAsdRep: "/register", + registerAsSoleVoter: "/register_sole_voter", stakeKeys: "/stake_keys", updateMetadata: "/update_metadata", }; diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index 9204175a4..68cd48743 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -286,6 +286,13 @@ export const en = { showAll: "Show all", viewAll: "View all", }, + soleVoter: { + becomeSoleVoter: "Become a Sole Voter", + continueToRegister: "Continue to register", + description: + "A Sole Voter is someone that can vote on any Governance Action with their own Voting Power, which is equal to the balance of ADA in their connected wallet. <0>Learn More about Sole Voter.\n\nBecoming a Sole Voter will require a refundable deposit of ₳2.\n\nYour deposit will be refunded if you either retire or delegate your voting power to someone else (a DRep)", + heading: "What this Means", + }, system: { sanchoNet: "SanchoNet", sanchoNetIsBeta: @@ -360,6 +367,7 @@ export const en = { back: "Back", backToDashboard: "Back to dashboard", backToList: "Back to the list", + backToDashboard: "Back to dashboard", cancel: "Cancel", clear: "Clear", confirm: "Confirm", diff --git a/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx new file mode 100644 index 000000000..370a5fefc --- /dev/null +++ b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx @@ -0,0 +1,110 @@ +import { useEffect } from "react"; +import { Box, Link } from "@mui/material"; + +import { Background, Typography } from "@atoms"; +import { ICONS, PATHS } from "@consts"; +import { DashboardTopNav, Footer } from "@organisms"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { useNavigate } from "react-router-dom"; +import { WALLET_LS_KEY, getItemFromLocalStorage } from "@/utils/localStorage"; +import { SoleVoterInfo } from "@/components/organisms/SoleVoterInfo"; + +export const RegisterAsSoleVoter = () => { + const { isMobile, screenWidth } = useScreenDimension(); + const navigate = useNavigate(); + const { t } = useTranslation(); + + useEffect(() => { + if ( + !getItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`) || + !getItemFromLocalStorage(`${WALLET_LS_KEY}_name`) + ) { + navigate(PATHS.home); + } + }, []); + + return ( + + + + + + {isMobile && ( + + + {t("soleVoter.becomeSoleVoter")} + + + )} + navigate(PATHS.dashboard)} + > + arrow + + {t("backToDashboard")} + + + + + {isMobile &&
+ } + /> + + + + + ), ], diff --git a/govtool/frontend/src/stories/DashboardCard.stories.ts b/govtool/frontend/src/stories/DashboardCard.stories.ts index 21bac97e4..fc47278eb 100644 --- a/govtool/frontend/src/stories/DashboardCard.stories.ts +++ b/govtool/frontend/src/stories/DashboardCard.stories.ts @@ -21,9 +21,7 @@ export const DashboardCardComponent: Story = { args: { description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", firstButtonLabel: "first button", - imageHeight: 80, imageURL: IMAGES.govActionDelegateImage, - imageWidth: 115, secondButtonLabel: "second button", title: "Action card", }, @@ -38,13 +36,22 @@ export const DashboardCardComponent: Story = { }, }; +export const WithDRepIdDashboardCardComponent: Story = { + args: { + description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", + firstButtonLabel: "first button", + imageURL: IMAGES.govActionDelegateImage, + secondButtonLabel: "second button", + title: "Action card", + cardId: "drep1gwsw9ckkhuwscj9savt5f7u9xsrudw209hne7pggcktzuw5sv32", + }, +}; + export const isLoadingDashboardCard: Story = { args: { description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", firstButtonLabel: "first button", - imageHeight: 80, imageURL: IMAGES.govActionDelegateImage, - imageWidth: 115, secondButtonLabel: "second button", title: "Action card", isLoading: true, @@ -62,9 +69,7 @@ export const isProgressDashboardCard: Story = { args: { description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit.", firstButtonLabel: "first button", - imageHeight: 80, imageURL: IMAGES.govActionDelegateImage, - imageWidth: 115, secondButtonLabel: "second button", title: "Action card", inProgress: true, diff --git a/govtool/frontend/src/stories/DashboardTopNav.stories.ts b/govtool/frontend/src/stories/DashboardTopNav.stories.ts index 06508f3aa..3ecbb15b7 100644 --- a/govtool/frontend/src/stories/DashboardTopNav.stories.ts +++ b/govtool/frontend/src/stories/DashboardTopNav.stories.ts @@ -1,7 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { DashboardTopNav } from "@organisms"; -import { IMAGES } from "@/consts"; import { within, userEvent, waitFor, screen } from "@storybook/testing-library"; import { expect } from "@storybook/jest"; @@ -15,7 +14,7 @@ export default meta; type Story = StoryObj; export const DashboardTopNavComponent: Story = { - args: { title: "Example title", isDrawer: true }, + args: { title: "Example title" }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); expect(canvas.getByText("Example title")).toBeInTheDocument(); @@ -31,16 +30,3 @@ export const DashboardTopNavComponent: Story = { }); }, }; - -export const DashboardTopNavWithIcon: Story = { - args: { - title: "Example title", - isDrawer: true, - imageSRC: IMAGES.appLogoWithoutText, - imageHeight: 24, - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - expect(canvas.getByRole("img")).toBeInTheDocument(); - }, -}; diff --git a/govtool/frontend/src/stories/DelegateActionRadio.stories.ts b/govtool/frontend/src/stories/DelegateActionRadio.stories.ts index a05563d28..49c24295c 100644 --- a/govtool/frontend/src/stories/DelegateActionRadio.stories.ts +++ b/govtool/frontend/src/stories/DelegateActionRadio.stories.ts @@ -68,3 +68,19 @@ export const ActionRadioActive: Story = { ); }, }; + +export const ActionRadioOnlyTitle: Story = { + args: { + title: "Title", + value: "", + isChecked: false, + }, +}; + +export const ActionRadioOnlyTitleChecked: Story = { + args: { + title: "Title", + value: "", + isChecked: true, + }, +}; diff --git a/govtool/frontend/src/stories/Input.stories.tsx b/govtool/frontend/src/stories/Input.stories.tsx index cbe95a400..95a134c60 100644 --- a/govtool/frontend/src/stories/Input.stories.tsx +++ b/govtool/frontend/src/stories/Input.stories.tsx @@ -60,3 +60,8 @@ ErrorAndLabel.play = async ({ canvasElement }) => { expect(canvas.getByText("Label")).toBeInTheDocument(); expect(canvas.getByTestId("error-message-error")).toBeInTheDocument(); }; + +export const WithHelpfulText = Template.bind({}); +WithHelpfulText.args = { + helpfulText: "Helpful text", +}; diff --git a/govtool/frontend/src/stories/LinkWithIcon.stories.tsx b/govtool/frontend/src/stories/LinkWithIcon.stories.tsx new file mode 100644 index 000000000..83e533f25 --- /dev/null +++ b/govtool/frontend/src/stories/LinkWithIcon.stories.tsx @@ -0,0 +1,26 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { LinkWithIcon } from "@molecules"; +import { ICONS } from "@consts"; + +const meta: Meta = { + title: "Example/LinkWithIcon", + component: LinkWithIcon, + parameters: { + layout: "centered", + }, +}; + +export default meta; + +export const Default: StoryObj = { + args: { + label: "Default Link", + }, +}; + +export const WithCustomIcon: StoryObj = { + args: { + label: "Custom Icon Link", + icon: , + }, +}; diff --git a/govtool/frontend/src/stories/LoadingButton.stories.tsx b/govtool/frontend/src/stories/LoadingButton.stories.tsx new file mode 100644 index 000000000..935014cd1 --- /dev/null +++ b/govtool/frontend/src/stories/LoadingButton.stories.tsx @@ -0,0 +1,31 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { LoadingButton } from "@atoms"; + +const meta = { + title: "Example/LoadingButton", + component: LoadingButton, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + children: "Button", + variant: "contained", + isLoading: false, + }, +}; + +export const Loading: Story = { + args: { + children: "Button", + variant: "contained", + isLoading: true, + }, +}; diff --git a/govtool/frontend/src/stories/Step.stories.tsx b/govtool/frontend/src/stories/Step.stories.tsx new file mode 100644 index 000000000..aecebae56 --- /dev/null +++ b/govtool/frontend/src/stories/Step.stories.tsx @@ -0,0 +1,62 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { Button } from "@atoms"; +import OpenInNewIcon from "@mui/icons-material/OpenInNew"; + +import { Field, Step } from "@molecules"; + +const meta: Meta = { + title: "Example/Step", + component: Step, + parameters: { + layout: "centered", + }, +}; + +export default meta; + +export const WithButton: StoryObj = { + args: { + label: "Download this file", + stepNumber: 1, + component: ( + + ), + }, +}; + +export const WithIconButton: StoryObj = { + args: { + label: + "Save this file in a location that provides a public URL (ex. github)", + stepNumber: 2, + component: ( + + ), + }, +}; + +export const WithInput: StoryObj = { + args: { + label: + "Save this file in a location that provides a public URL (ex. github)", + stepNumber: 2, + component: , + }, +}; diff --git a/govtool/frontend/src/stories/TextArea.stories.tsx b/govtool/frontend/src/stories/TextArea.stories.tsx new file mode 100644 index 000000000..8f6cc178b --- /dev/null +++ b/govtool/frontend/src/stories/TextArea.stories.tsx @@ -0,0 +1,42 @@ +import type { Meta, StoryFn } from "@storybook/react"; + +import { Field } from "@molecules"; +import { ComponentProps } from "react"; + +const meta: Meta = { + title: "Example/TextArea", + component: Field.TextArea, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +}; + +export default meta; + +const Template: StoryFn> = (args) => { + return ; +}; + +export const Default = Template.bind({}); + +export const WithLabel = Template.bind({}); +WithLabel.args = { + label: "Label", +}; + +export const WithHelpfulText = Template.bind({}); +WithHelpfulText.args = { + helpfulText: "Helpful text here", +}; + +export const Error = Template.bind({}); +Error.args = { + errorMessage: "Error message", +}; + +export const ErrorAndLabel = Template.bind({}); +ErrorAndLabel.args = { + errorMessage: "Error message", + label: "Label", +}; diff --git a/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx b/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx index dc2df8b5d..236943ac5 100644 --- a/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx +++ b/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx @@ -1,28 +1,22 @@ -import { ComponentProps, useEffect } from "react"; -import { Story, Meta, StoryFn } from "@storybook/react"; +import { useEffect } from "react"; +import { Meta, StoryFn } from "@storybook/react"; import { Modal } from "@atoms"; import { ExternalLinkModal, ExternalLinkModalState } from "@organisms"; -import { ModalProvider, useModal } from "../../context/modal"; +import { useModal } from "../../context/modal"; import { userEvent, within, screen, waitFor } from "@storybook/testing-library"; import { expect, jest } from "@storybook/jest"; +import { callAll } from "@/utils"; const meta = { title: "Example/Modals/ExternalLinkModal", component: ExternalLinkModal, - decorators: [ - (Story) => ( - - - - ), - ], } satisfies Meta; export default meta; const Template: StoryFn = (args) => { - const { openModal, modal, closeModal } = useModal(); + const { openModal, modal, modals } = useModal(); const open = () => { openModal({ @@ -40,12 +34,18 @@ const Template: StoryFn = (args) => { - {modal?.component && ( + {modals[modal.type]?.component && ( + openModal({ type: "none", state: null }) + ) + : undefined + } > - {modal.component} + {modals[modal.type]?.component ?? <>} )} diff --git a/govtool/frontend/src/stories/modals/StatusModal.stories.tsx b/govtool/frontend/src/stories/modals/StatusModal.stories.tsx index 24bb364b1..d7c0b56ce 100644 --- a/govtool/frontend/src/stories/modals/StatusModal.stories.tsx +++ b/govtool/frontend/src/stories/modals/StatusModal.stories.tsx @@ -1,22 +1,16 @@ import { useEffect } from "react"; -import { Story, Meta, StoryFn } from "@storybook/react"; +import { Meta, StoryFn } from "@storybook/react"; +import { expect } from "@storybook/jest"; +import { within, waitFor, screen, userEvent } from "@storybook/testing-library"; import { Modal } from "@atoms"; import { StatusModal, StatusModalState } from "@organisms"; -import { ModalProvider, useModal } from "../../context/modal"; -import { within, waitFor, screen, userEvent } from "@storybook/testing-library"; -import { expect } from "@storybook/jest"; +import { useModal } from "../../context/modal"; +import { callAll } from "@utils"; const meta = { title: "Example/Modals/StatusModal", component: StatusModal, - decorators: [ - (Story) => ( - - - - ), - ], } satisfies Meta; export default meta; @@ -40,7 +34,7 @@ const performCommonAction = async (canvas: any, args: any) => { }); }; const Template: StoryFn = (args) => { - const { openModal, modal, closeModal } = useModal(); + const { openModal, modal, modals, closeModal } = useModal(); const open = () => { openModal({ @@ -67,12 +61,18 @@ const Template: StoryFn = (args) => { - {modal?.component && ( + {modals[modal.type]?.component && ( + openModal({ type: "none", state: null }) + ) + : undefined + } > - {modal.component} + {modals[modal.type]?.component ?? <>} )} diff --git a/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx b/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx index e331a14bb..1181fb143 100644 --- a/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx +++ b/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx @@ -1,28 +1,22 @@ import { useEffect } from "react"; -import { Story, Meta, StoryFn } from "@storybook/react"; +import { Meta, StoryFn } from "@storybook/react"; +import { expect, jest } from "@storybook/jest"; +import { userEvent, waitFor, within, screen } from "@storybook/testing-library"; import { Modal } from "@atoms"; import { StatusModal, StatusModalState } from "@organisms"; -import { ModalProvider, useModal } from "../../context/modal"; -import { userEvent, waitFor, within, screen } from "@storybook/testing-library"; -import { expect, jest } from "@storybook/jest"; +import { useModal } from "../../context/modal"; +import { callAll } from "@utils"; const meta = { title: "Example/Modals/StatusModalWithLink", component: StatusModal, - decorators: [ - (Story) => ( - - - - ), - ], } satisfies Meta; export default meta; const Template: StoryFn = (args) => { - const { openModal, modal, closeModal } = useModal(); + const { openModal, modal, modals, closeModal } = useModal(); const open = () => { openModal({ @@ -48,12 +42,18 @@ const Template: StoryFn = (args) => { - {modal?.component && ( + {modals[modal.type]?.component && ( + openModal({ type: "none", state: null }) + ) + : undefined + } > - {modal.component} + {modals[modal.type]?.component ?? <>} )} diff --git a/govtool/frontend/src/stories/modals/VotingPowerModal.stories.tsx b/govtool/frontend/src/stories/modals/VotingPowerModal.stories.tsx new file mode 100644 index 000000000..5820c9bb3 --- /dev/null +++ b/govtool/frontend/src/stories/modals/VotingPowerModal.stories.tsx @@ -0,0 +1,56 @@ +import { Meta, StoryFn } from "@storybook/react"; + +import { Modal } from "@atoms"; +import { StatusModal, VotingPowerModalState } from "@organisms"; +import { useModal } from "@context"; +import { callAll } from "@utils"; + +const meta = { + title: "Example/Modals/VotingPowerModal", + component: StatusModal, +} satisfies Meta; + +export default meta; + +const Template: StoryFn = (args) => { + const { openModal, modal, modals } = useModal(); + + const open = () => { + openModal({ + type: "votingPower", + state: { + ...args, + }, + }); + }; + + return ( + <> + + {modals[modal.type]?.component && ( + + openModal({ type: "none", state: null }) + ) + : undefined + } + > + {modals[modal.type]?.component ?? <>} + + )} + + ); +}; + +export const Default = Template.bind({}); +Default.args = { + yesVotes: 1000000000000, + noVotes: 10000000000, + abstainVotes: 324000000, + vote: "yes", +}; From b17a9c2f86635285936f73106320a25d41732137 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Wed, 13 Mar 2024 13:21:16 +0100 Subject: [PATCH 121/157] [#453] Fixes after CR --- govtool/frontend/src/stories/Input.stories.tsx | 7 +++++++ govtool/frontend/src/stories/TextArea.stories.tsx | 7 +++++++ .../src/stories/modals/ExternalLinkModal.stories.tsx | 10 +++------- .../src/stories/modals/StatusModal.stories.tsx | 10 +++------- .../src/stories/modals/StatusWithLink.stories.tsx | 10 +++------- .../src/stories/modals/VotingPowerModal.stories.tsx | 10 +++------- 6 files changed, 26 insertions(+), 28 deletions(-) diff --git a/govtool/frontend/src/stories/Input.stories.tsx b/govtool/frontend/src/stories/Input.stories.tsx index 95a134c60..e863f036b 100644 --- a/govtool/frontend/src/stories/Input.stories.tsx +++ b/govtool/frontend/src/stories/Input.stories.tsx @@ -65,3 +65,10 @@ export const WithHelpfulText = Template.bind({}); WithHelpfulText.args = { helpfulText: "Helpful text", }; + +export const WithAllProps = Template.bind({}); +WithAllProps.args = { + label: "Label", + helpfulText: "Helpful text", + errorMessage: "Error message", +}; diff --git a/govtool/frontend/src/stories/TextArea.stories.tsx b/govtool/frontend/src/stories/TextArea.stories.tsx index 8f6cc178b..c378c6749 100644 --- a/govtool/frontend/src/stories/TextArea.stories.tsx +++ b/govtool/frontend/src/stories/TextArea.stories.tsx @@ -40,3 +40,10 @@ ErrorAndLabel.args = { errorMessage: "Error message", label: "Label", }; + +export const WithAllProps = Template.bind({}); +WithAllProps.args = { + label: "Label", + helpfulText: "Helpful text", + errorMessage: "Error message", +}; diff --git a/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx b/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx index 236943ac5..05ac4c018 100644 --- a/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx +++ b/govtool/frontend/src/stories/modals/ExternalLinkModal.stories.tsx @@ -37,13 +37,9 @@ const Template: StoryFn = (args) => { {modals[modal.type]?.component && ( - openModal({ type: "none", state: null }) - ) - : undefined - } + handleClose={callAll(modals[modal.type]?.onClose, () => + openModal({ type: "none", state: null }) + )} > {modals[modal.type]?.component ?? <>} diff --git a/govtool/frontend/src/stories/modals/StatusModal.stories.tsx b/govtool/frontend/src/stories/modals/StatusModal.stories.tsx index d7c0b56ce..c8474d741 100644 --- a/govtool/frontend/src/stories/modals/StatusModal.stories.tsx +++ b/govtool/frontend/src/stories/modals/StatusModal.stories.tsx @@ -64,13 +64,9 @@ const Template: StoryFn = (args) => { {modals[modal.type]?.component && ( - openModal({ type: "none", state: null }) - ) - : undefined - } + handleClose={callAll(modals[modal.type]?.onClose, () => + openModal({ type: "none", state: null }) + )} > {modals[modal.type]?.component ?? <>} diff --git a/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx b/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx index 1181fb143..8c8ca391b 100644 --- a/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx +++ b/govtool/frontend/src/stories/modals/StatusWithLink.stories.tsx @@ -45,13 +45,9 @@ const Template: StoryFn = (args) => { {modals[modal.type]?.component && ( - openModal({ type: "none", state: null }) - ) - : undefined - } + handleClose={callAll(modals[modal.type]?.onClose, () => + openModal({ type: "none", state: null }) + )} > {modals[modal.type]?.component ?? <>} diff --git a/govtool/frontend/src/stories/modals/VotingPowerModal.stories.tsx b/govtool/frontend/src/stories/modals/VotingPowerModal.stories.tsx index 5820c9bb3..fbca8d633 100644 --- a/govtool/frontend/src/stories/modals/VotingPowerModal.stories.tsx +++ b/govtool/frontend/src/stories/modals/VotingPowerModal.stories.tsx @@ -32,13 +32,9 @@ const Template: StoryFn = (args) => { {modals[modal.type]?.component && ( - openModal({ type: "none", state: null }) - ) - : undefined - } + handleClose={callAll(modals[modal.type]?.onClose, () => + openModal({ type: "none", state: null }) + )} > {modals[modal.type]?.component ?? <>} From bb1bc51ec3b657c11cd22961fc35b14bcddf3fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Wed, 13 Mar 2024 14:03:44 +0100 Subject: [PATCH 122/157] Introduce frontend image build environment tag To ensure frontend image builds can distinguish between different environments, an additional distinction based on the environment tag has been introduced. This change was necessary as the commit altering the frontend module alone was insufficient. By adding an environment tag to the image tag name, applications with the same version can now be uniquely identified across various environments. Changes Made: - Modified the Makefile in the govtool/frontend directory to introduce an environment tag to the image tag name used in frontend image builds. The new tag is generated by appending the environment variable to the commit hash obtained from the git log command, ensuring each build is uniquely identified per environment. --- govtool/frontend/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/Makefile b/govtool/frontend/Makefile index 2721792b7..24f0702dc 100644 --- a/govtool/frontend/Makefile +++ b/govtool/frontend/Makefile @@ -7,7 +7,7 @@ endif .DEFAULT_GOAL := push-frontend # image tags -frontend_image_tag := $(shell git log -n 1 --format="%H" -- $(root_dir)/govtool/frontend) +frontend_image_tag := $(shell git log -n 1 --format="%H" -- $(root_dir)/govtool/frontend)-$(env) .PHONY: build-frontend build-frontend: docker-login From b65aa9fc33fec37d8d86993ca0a4902945ccbc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Thu, 14 Mar 2024 11:17:09 +0100 Subject: [PATCH 123/157] [#364] fix: i18n labels of storage information screen --- govtool/frontend/src/i18n/locales/en.ts | 37 +++++++++++++------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index 98999d447..b32f08b3b 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -169,24 +169,6 @@ export const en = { placeholder: "A name for this Action", }, }, - formTitle: "Governance Action details", - references: "References and Supporting Information", - reviewSubmission: "Review your submission", - storeDataCheckboxLabel: - "I agree to store correctly this information and to maintain them over the years", - storeDataLink: "Learn more about storing information", - storeDataTitle: "Store and Maintain the Data Yourself", - storingInformationDescription: - "Download your file, save it to your chosen location, and enter the URL of that location in step 3", - storingInformationStep1Label: "Download this file", - storingInformationStep2Label: - "Save this file in a location that provides a public URL (ex. github)", - storingInformationStep2Link: "Read full guide", - storingInformationStep3Label: "Paste the URL here", - storingInformationTitle: "Information Storage Steps", - storingInformationURLPlaceholder: "URL", - supportingLinks: "Supporting links", - title: "Create a Governance Action", validations: { bech32: "Invalid bech32 address", maxLength: "Max {{maxLength}} characters", @@ -195,6 +177,24 @@ export const en = { url: "Invalid URL", }, }, + formTitle: "Governance Action details", + references: "References and Supporting Information", + reviewSubmission: "Review your submission", + storeDataCheckboxLabel: + "I agree to store correctly this information and to maintain them over the years", + storeDataLink: "Learn more about storing information", + storeDataTitle: "Store and Maintain the Data Yourself", + storingInformationDescription: + "Download your file, save it to your chosen location, and enter the URL of that location in step 3", + storingInformationStep1Label: "Download this file", + storingInformationStep2Label: + "Save this file in a location that provides a public URL (ex. github)", + storingInformationStep2Link: "Read full guide", + storingInformationStep3Label: "Paste the URL here", + storingInformationTitle: "Information Storage Steps", + storingInformationURLPlaceholder: "URL", + supportingLinks: "Supporting links", + title: "Create a Governance Action", modals: { externalDataDoesntMatch: { buttonText: "Go to Data Edit Screen", @@ -261,6 +261,7 @@ export const en = { checkIsWalletConnected: "Check if the wallet is connected.", dRepIdNotFound: "DrepId not found", invalidGovernanceActionType: "Invalid Governance Action Type", + invalidTreasuryGovernanceActionType: "Invalid Treasury Governance Action", noAddressesFound: "No addresses found", noStakeKeySelected: "No stake key selected", notUsingAnchor: "DRep Registration - not using anchor", From e662a3f67624d42bf0feb489633c1a94f85e7a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Thu, 14 Mar 2024 14:42:09 +0100 Subject: [PATCH 124/157] [#462] [#463] fix cards width and fonts for RWDs --- .../src/components/atoms/Typography.tsx | 4 +-- .../src/components/molecules/ActionCard.tsx | 24 +++++----------- .../ReviewCreatedGovernanceAction.tsx | 2 +- .../components/organisms/DashboardCards.tsx | 28 +++++++++---------- .../src/components/organisms/Hero.tsx | 2 +- .../src/components/organisms/HomeCards.tsx | 10 +++++-- .../src/components/organisms/TopNav.tsx | 4 +-- 7 files changed, 34 insertions(+), 40 deletions(-) diff --git a/govtool/frontend/src/components/atoms/Typography.tsx b/govtool/frontend/src/components/atoms/Typography.tsx index 1bcaf6131..34e1af742 100644 --- a/govtool/frontend/src/components/atoms/Typography.tsx +++ b/govtool/frontend/src/components/atoms/Typography.tsx @@ -8,7 +8,7 @@ export const Typography = ({ }: TypographyProps) => { const fontSize = { headline1: 100, - headline2: 50, + headline2: 57, headline3: 36, headline4: 32, headline5: 28, @@ -21,7 +21,7 @@ export const Typography = ({ const fontWeight = { headline1: 600, - headline2: 600, + headline2: 700, headline3: 400, headline4: 600, headline5: 500, diff --git a/govtool/frontend/src/components/molecules/ActionCard.tsx b/govtool/frontend/src/components/molecules/ActionCard.tsx index 2ac0dd63f..548af7091 100644 --- a/govtool/frontend/src/components/molecules/ActionCard.tsx +++ b/govtool/frontend/src/components/molecules/ActionCard.tsx @@ -33,7 +33,7 @@ export const ActionCard: FC = ({ ...props }) => { secondButtonLabel, title, } = props; - const { isMobile, screenWidth } = useScreenDimension(); + const { screenWidth } = useScreenDimension(); const { palette: { boxShadow2 }, @@ -52,23 +52,14 @@ export const ActionCard: FC = ({ ...props }) => { > {imageURL ? ( - + ) : null} {title ? ( {title} @@ -79,9 +70,8 @@ export const ActionCard: FC = ({ ...props }) => { sx={{ mb: 4.25, mt: 1.75, - textAlign: screenWidth < 640 ? "center" : "left", }} - variant={isMobile ? "body2" : "body1"} + variant={"body1"} > {description} @@ -103,11 +93,11 @@ export const ActionCard: FC = ({ ...props }) => { data-testid={dataTestIdSecondButton} onClick={secondButtonAction} sx={{ - visibility: secondButtonLabel ? "visible" : "hidden", + display: !secondButtonLabel && screenWidth < 768 ? "none" : "block", ml: screenWidth < 640 ? 0 : 2, mt: screenWidth < 640 ? 2 : 0, + visibility: secondButtonLabel ? "visible" : "hidden", width: screenWidth < 640 ? "100%" : "auto", - display: !secondButtonLabel && screenWidth < 768 ? "none" : "block", }} variant="outlined" > diff --git a/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/ReviewCreatedGovernanceAction.tsx b/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/ReviewCreatedGovernanceAction.tsx index aaefa6d6f..0d8e74b33 100644 --- a/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/ReviewCreatedGovernanceAction.tsx +++ b/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/ReviewCreatedGovernanceAction.tsx @@ -58,7 +58,7 @@ export const ReviewCreatedGovernanceAction = ({ {label} {value as string} diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index ed3fefc52..ffa2e6c99 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -33,7 +33,7 @@ export const DashboardCards = () => { const navigate = useNavigate(); const { currentDelegation, isCurrentDelegationLoading } = useGetAdaHolderCurrentDelegationQuery(stakeKey); - const { isMobile, screenWidth } = useScreenDimension(); + const { screenWidth } = useScreenDimension(); const { openModal } = useModal(); const [isRetirementLoading, setIsRetirementLoading] = useState(false); @@ -187,13 +187,12 @@ export const DashboardCards = () => { ); const onClickGovernanceActionCardActionButton = useCallback(() => { - if(govActionTransaction.transactionHash) { - navigate(PATHS.dashboardGovernanceActions) - return + if (govActionTransaction.transactionHash) { + navigate(PATHS.dashboardGovernanceActions); + return; } - navigate(PATHS.createGovernanceAction) - - }, [govActionTransaction.transactionHash, navigate]) + navigate(PATHS.createGovernanceAction); + }, [govActionTransaction.transactionHash, navigate]); const displayedDelegationId = useMemo(() => { const restrictedNames = [ @@ -333,11 +332,12 @@ export const DashboardCards = () => { display: "grid", gridTemplateColumns: screenWidth < 1280 - ? "1fr" - : screenWidth > 1728 - ? "repeat(3, minmax(300px, 572px))" - : "repeat(2, minmax(300px, 572px))", - px: isMobile ? 2 : 5, + ? "repeat(1, minmax(300px, 530px))" + : screenWidth >= 1728 + ? "repeat(3, minmax(300px, 570px))" + : "repeat(2, minmax(300px, 530px))", + justifyContent: screenWidth < 1024 ? "center" : "flex-start", + px: screenWidth < 640 ? 2 : 5, py: 3, rowGap: 3, }} @@ -538,9 +538,9 @@ export const DashboardCards = () => { firstButtonAction={onClickGovernanceActionCardActionButton} firstButtonLabel={t( `dashboard.proposeGovernanceAction.${ - govActionTransaction.transactionHash ? "view" : "propose" + govActionTransaction.transactionHash ? "view" : "propose" }` - )} + )} inProgress={!!govActionTransaction.transactionHash} secondButtonLabel={t("learnMore")} secondButtonAction={() => diff --git a/govtool/frontend/src/components/organisms/Hero.tsx b/govtool/frontend/src/components/organisms/Hero.tsx index bdc6bcbbe..baae0bca4 100644 --- a/govtool/frontend/src/components/organisms/Hero.tsx +++ b/govtool/frontend/src/components/organisms/Hero.tsx @@ -38,7 +38,7 @@ export const Hero = () => { {t("hero.headline")} diff --git a/govtool/frontend/src/components/organisms/HomeCards.tsx b/govtool/frontend/src/components/organisms/HomeCards.tsx index 4539587c1..fca3f2c2c 100644 --- a/govtool/frontend/src/components/organisms/HomeCards.tsx +++ b/govtool/frontend/src/components/organisms/HomeCards.tsx @@ -53,9 +53,13 @@ export const HomeCards = () => { return ( = 1920 ? "1fr 1fr" : "1fr"} + gridTemplateColumns={ + screenWidth < 2560 + ? "repeat(1, minmax(300px, 866px))" + : "repeat(2, minmax(300px, 866px))" + } justifyItems="center" mb={screenWidth < 640 ? 10 : 17} mt={screenWidth < 640 ? 10 : 14.5} @@ -68,7 +72,7 @@ export const HomeCards = () => { ? 10 : 34 } - rowGap={5} + rowGap={4.625} > {/* DELEGATE CARD */} { : "transparent", borderBottom: isMobile ? 1 : 0, borderColor: "lightblue", + borderRadius: 0, boxShadow: 0, justifyContent: "center", flex: 1, From fa32861f78f525853a8aa0fa68b25471f0b35634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Thu, 14 Mar 2024 15:18:39 +0100 Subject: [PATCH 125/157] [#451] fix: whitelist any jsonld file in CSP --- CHANGELOG.md | 2 ++ scripts/govtool/config/templates/docker-compose.yml.tpl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cb0840cf..0188ff91d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ As a minor extension, we also keep a semantic version for the `UNRELEASED` changes. ## [Unreleased] + - Add generate jsonld function [Issue 451](https://github.com/IntersectMBO/govtool/issues/451) - Create GA review subbmision page [Issue 362](https://github.com/IntersectMBO/govtool/issues/362) - Create GA creation form [Issue 360](https://github.com/IntersectMBO/govtool/issues/360) @@ -16,6 +17,7 @@ changes. - Choose GA type - GA Submiter [Issue 358](https://github.com/IntersectMBO/govtool/issues/358) - Add on-chain inputs validation [Issue 377](https://github.com/IntersectMBO/govtool/issues/377) - Add hash and validation of the metadata [Issue 378](https://github.com/IntersectMBO/govtool/issues/378) +- Add githubusercontent.com and ipfs.io to content security policy header [Issue 451](https://github.com/IntersectMBO/govtool/issues/451) ### Added diff --git a/scripts/govtool/config/templates/docker-compose.yml.tpl b/scripts/govtool/config/templates/docker-compose.yml.tpl index 9ef1ce811..03c05abee 100644 --- a/scripts/govtool/config/templates/docker-compose.yml.tpl +++ b/scripts/govtool/config/templates/docker-compose.yml.tpl @@ -225,7 +225,7 @@ services: - "traefik.http.routers.frontend.rule=Host(``)" - "traefik.http.routers.frontend.entrypoints=websecure" - "traefik.http.routers.frontend.tls.certresolver=myresolver" - - "traefik.http.middlewares.frontend-csp.headers.contentSecurityPolicy=default-src 'self'; img-src *.usersnap.com 'self' data:; script-src *.usersnap.com 'self' 'unsafe-inline' https://www.googletagmanager.com https://browser.sentry-cdn.com; style-src *.usersnap.com *.googleapis.com 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src *.usersnap.com https://s3.eu-central-1.amazonaws.com/upload.usersnap.com 'self' o4506155985141760.ingest.sentry.io *.google-analytics.com; font-src *.usersnap.com *.gstatic.com 'self' 'unsafe-inline' https://fonts.gstatic.com; worker-src blob:" + - "traefik.http.middlewares.frontend-csp.headers.contentSecurityPolicy=default-src 'self'; img-src *.usersnap.com 'self' data:; script-src *.usersnap.com 'self' 'unsafe-inline' https://www.googletagmanager.com https://browser.sentry-cdn.com; style-src *.usersnap.com *.googleapis.com 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src *.usersnap.com https://s3.eu-central-1.amazonaws.com/upload.usersnap.com 'self' o4506155985141760.ingest.sentry.io *.google-analytics.com *.githubusercontent.com *.ipfs.io; font-src *.usersnap.com *.gstatic.com 'self' 'unsafe-inline' https://fonts.gstatic.com; worker-src blob:" - "traefik.http.routers.frontend.middlewares=frontend-csp@docker" - "traefik.http.services.frontend.loadbalancer.server.port=80" From 5b409c4ac887f832166cff4f2923fba17603bbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Thu, 14 Mar 2024 23:14:42 +0100 Subject: [PATCH 126/157] [#481] ]wrap too long link --- govtool/frontend/src/components/organisms/ExternalLinkModal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/govtool/frontend/src/components/organisms/ExternalLinkModal.tsx b/govtool/frontend/src/components/organisms/ExternalLinkModal.tsx index 77d2cf509..2a111ed6f 100644 --- a/govtool/frontend/src/components/organisms/ExternalLinkModal.tsx +++ b/govtool/frontend/src/components/organisms/ExternalLinkModal.tsx @@ -42,6 +42,7 @@ export function ExternalLinkModal() { marginBottom: "38px", color: primaryBlue, textDecoration: "underline", + wordBreak: "break-word", }} > {state?.externalLink} From 5ce3e4bbfc30ea2a28f1967376e122b31f638b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Fri, 5 Apr 2024 17:09:48 +0200 Subject: [PATCH 127/157] bugfix: change dispatch condition on deployment workflows --- .github/workflows/build-and-deploy-staging.yml | 4 +--- .github/workflows/build-and-deploy-test.yml | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-deploy-staging.yml b/.github/workflows/build-and-deploy-staging.yml index 54fb51634..f53352b35 100644 --- a/.github/workflows/build-and-deploy-staging.yml +++ b/.github/workflows/build-and-deploy-staging.yml @@ -2,11 +2,9 @@ name: Build and deploy GovTool to STAGING server run-name: Deploy by @${{ github.actor }} on: - pull_request: + push: branches: - staging - types: - - closed env: ENVIRONMENT: "staging" diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index a254023df..8c4a3424c 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -2,11 +2,9 @@ name: Build and deploy GovTool to TEST server run-name: Deploy by @${{ github.actor }} on: - pull_request: + push: branches: - test - types: - - closed env: ENVIRONMENT: "test" From 8e2a22bbc88330fe7576322914be87fa751c9d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Thu, 11 Apr 2024 12:53:52 +0200 Subject: [PATCH 128/157] fix: fix api connection --- govtool/frontend/src/services/API.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/govtool/frontend/src/services/API.ts b/govtool/frontend/src/services/API.ts index 1815ecbc2..2e084a29b 100644 --- a/govtool/frontend/src/services/API.ts +++ b/govtool/frontend/src/services/API.ts @@ -7,12 +7,12 @@ const TIMEOUT_IN_SECONDS = 30 * 1000; // 1000 ms is 1 s then its 10 s const BASE_URL = import.meta.env.VITE_BASE_URL; export const API = axios.create({ - baseURL: `${BASE_URL}api`, + baseURL: `${BASE_URL}/api`, timeout: TIMEOUT_IN_SECONDS, }); export const METADATA_VALIDATION_API = axios.create({ - baseURL: `${BASE_URL}metadata-validation`, + baseURL: `${BASE_URL}/metadata-validation`, timeout: TIMEOUT_IN_SECONDS, }); From 94fb7de29f34d199df318707639af98c6c900f57 Mon Sep 17 00:00:00 2001 From: jankun4 Date: Wed, 10 Apr 2024 11:26:10 +0200 Subject: [PATCH 129/157] [#685] fix getVotes 500 error Signed-off-by: jankun4 --- CHANGELOG.md | 1 + govtool/backend/sql/get-votes.sql | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f42ac266..018b544e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ changes. ### Fixed +- drep/getVotes no longer returns 500 [Issue 685](https://github.com/IntersectMBO/govtool/issues/685) - drep/info no longer returns 500 [Issue 676](https://github.com/IntersectMBO/govtool/issues/676) - proposal/list search is case insensitive now [Issue 582](https://github.com/IntersectMBO/govtool/issues/582) - proposal/list now takes optional `search` query param [Issue 566](https://github.com/IntersectMBO/govtool/issues/566) diff --git a/govtool/backend/sql/get-votes.sql b/govtool/backend/sql/get-votes.sql index 1e9a49cfe..7a875aba8 100644 --- a/govtool/backend/sql/get-votes.sql +++ b/govtool/backend/sql/get-votes.sql @@ -1,4 +1,5 @@ select DISTINCT ON (voting_procedure.gov_action_proposal_id, voting_procedure.drep_voter) voting_procedure.gov_action_proposal_id, concat(encode(gov_action_tx.hash,'hex'),'#',gov_action_proposal.index), encode(drep_hash.raw, 'hex'), voting_procedure.vote::text, voting_anchor.url, encode(voting_anchor.data_hash, 'hex'), block.epoch_no as epoch_no, block.time as time, encode(vote_tx.hash, 'hex') as vote_tx_hash +from voting_procedure join gov_action_proposal on gov_action_proposal.id = voting_procedure.gov_action_proposal_id join drep_hash From d868fe985ad7a189f9b5c5318390cb1281a4fe19 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 29 Apr 2024 17:23:04 +0545 Subject: [PATCH 130/157] Add metadata api for tests --- tests/test-metadata-api/.dockerignore | 3 + tests/test-metadata-api/.gitignore | 2 + tests/test-metadata-api/Dockerfile | 8 ++ tests/test-metadata-api/README.md | 35 ++++++++ tests/test-metadata-api/index.js | 110 ++++++++++++++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 tests/test-metadata-api/.dockerignore create mode 100644 tests/test-metadata-api/.gitignore create mode 100644 tests/test-metadata-api/Dockerfile create mode 100644 tests/test-metadata-api/README.md create mode 100644 tests/test-metadata-api/index.js diff --git a/tests/test-metadata-api/.dockerignore b/tests/test-metadata-api/.dockerignore new file mode 100644 index 000000000..7501e1983 --- /dev/null +++ b/tests/test-metadata-api/.dockerignore @@ -0,0 +1,3 @@ +json_files +Dockerfile +README.md \ No newline at end of file diff --git a/tests/test-metadata-api/.gitignore b/tests/test-metadata-api/.gitignore new file mode 100644 index 000000000..995da051a --- /dev/null +++ b/tests/test-metadata-api/.gitignore @@ -0,0 +1,2 @@ +json_files +node_modules \ No newline at end of file diff --git a/tests/test-metadata-api/Dockerfile b/tests/test-metadata-api/Dockerfile new file mode 100644 index 000000000..3e589c8ea --- /dev/null +++ b/tests/test-metadata-api/Dockerfile @@ -0,0 +1,8 @@ +FROM node:18-alpine +WORKDIR /src +COPY package.json yarn.lock ./ +RUN yarn install +COPY . . +VOLUME /data +EXPOSE 3000 +CMD [ "yarn", "start"] \ No newline at end of file diff --git a/tests/test-metadata-api/README.md b/tests/test-metadata-api/README.md new file mode 100644 index 000000000..a876a802e --- /dev/null +++ b/tests/test-metadata-api/README.md @@ -0,0 +1,35 @@ +Test medatada API +================= + +Simple service to host json metadata during testing. + +## Installation + +``` +git clone https://github.com/your/repository.git +yarn install +yarn start +``` +#### Swagger UI + +``` +http://localhost:3000/docs +``` + + +## Available Endpoints + +### Save File + +- **Endpoint:** `PUT /data/{filename}` +- **Description:** Saves data to a file with the specified filename. + +### Get File + +- **Endpoint:** `GET /data/{filename}` +- **Description:** Retrieves the content of the file with the specified filename. + +### Delete File + +- **Endpoint:** `DELETE /data/{filename}` +- **Description:** Deletes the file with the specified filename. \ No newline at end of file diff --git a/tests/test-metadata-api/index.js b/tests/test-metadata-api/index.js new file mode 100644 index 000000000..08e7c8dc7 --- /dev/null +++ b/tests/test-metadata-api/index.js @@ -0,0 +1,110 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const swaggerUi = require('swagger-ui-express'); +const swaggerJsdoc = require('swagger-jsdoc'); + +const app = express(); + + +const dataDir = process.env.DATA_DIR || path.join(__dirname, 'json_files'); + +if (!fs.existsSync(dataDir)) { + fs.mkdirSync(dataDir, { recursive: true }); +} +// Middleware to parse text request bodies +app.use(express.text()); + +// Swagger configuration +const swaggerOptions = { + definition: { + openapi: '3.0.0', + info: { + title: 'File API', + version: '1.0.0', + description: 'API for saving and deleting files', + }, + }, + apis: ['index.js'], // Update the path to reflect the compiled JavaScript file +}; + +const swaggerSpec = swaggerJsdoc(swaggerOptions); + +// Serve Swagger UI +app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); + +// PUT endpoint to save a file +/** + * @swagger + * /data/{filename}: + * put: + * summary: Save data to a file + * parameters: + * - in: path + * name: filename + * schema: + * type: string + * required: true + * description: The name of the file to save + * requestBody: + * required: true + * content: + * text/plain: + * schema: + * type: string + * responses: + * '201': + * description: File saved successfully + */ +app.put('/data/:filename', (req, res) => { + const filename = req.params.filename; + const filePath = path.join(dataDir, filename); + + fs.writeFile(filePath, req.body, (err) => { + if (err) { + console.error(err); + return res.status(500).send('Failed to save file'); + } + res.status(201).send({'success': true}); + }); +}); + + +// DELETE endpoint to delete a file +/** + * @swagger + * /data/{filename}: + * delete: + * summary: Delete a file + * parameters: + * - in: path + * name: filename + * schema: + * type: string + * required: true + * description: The name of the file to delete + * responses: + * '200': + * description: File deleted successfully + */ +app.delete('/data/:filename', (req, res) => { + const filename = req.params.filename; + const filePath = path.join(dataDir, filename); + + fs.unlink(filePath, (err) => { + if (err) { + console.error(err); + return res.status(500).send({'message':'Failed to delete file'}); + } + res.send('File deleted successfully'); + }); +}); + +// Serve the directory where the files are saved +app.use('/json_files', express.static(dataDir)); + +// Start the server +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Server is running on port ${PORT}`); +}); From 68edfe8194dfed7fd68dd435ec0e025bc9e8f332 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 2 May 2024 10:47:54 +0545 Subject: [PATCH 131/157] Add locks api --- .gitignore | 4 + tests/test-metadata-api/Dockerfile | 1 + tests/test-metadata-api/README.md | 26 +- tests/test-metadata-api/index.js | 51 +- tests/test-metadata-api/locks_api.js | 79 ++++ tests/test-metadata-api/package.json | 14 + tests/test-metadata-api/yarn.lock | 678 +++++++++++++++++++++++++++ 7 files changed, 841 insertions(+), 12 deletions(-) create mode 100644 tests/test-metadata-api/locks_api.js create mode 100644 tests/test-metadata-api/package.json create mode 100644 tests/test-metadata-api/yarn.lock diff --git a/.gitignore b/.gitignore index 2bad55163..ce63fca47 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,7 @@ scripts/govtool/dev-postgres_password # nodejs/yarn node_modules + + +# sonar scanner +.scannerwork/ \ No newline at end of file diff --git a/tests/test-metadata-api/Dockerfile b/tests/test-metadata-api/Dockerfile index 3e589c8ea..b30a1fd6b 100644 --- a/tests/test-metadata-api/Dockerfile +++ b/tests/test-metadata-api/Dockerfile @@ -4,5 +4,6 @@ COPY package.json yarn.lock ./ RUN yarn install COPY . . VOLUME /data +ENV DATA_DIR=/data EXPOSE 3000 CMD [ "yarn", "start"] \ No newline at end of file diff --git a/tests/test-metadata-api/README.md b/tests/test-metadata-api/README.md index a876a802e..3a98a748b 100644 --- a/tests/test-metadata-api/README.md +++ b/tests/test-metadata-api/README.md @@ -1,4 +1,4 @@ -Test medatada API +Test metadata API ================= Simple service to host json metadata during testing. @@ -16,20 +16,32 @@ yarn start http://localhost:3000/docs ``` +## Metadata Endpoints -## Available Endpoints - -### Save File +### 1. Save File - **Endpoint:** `PUT /data/{filename}` - **Description:** Saves data to a file with the specified filename. -### Get File +### 2. Get File - **Endpoint:** `GET /data/{filename}` - **Description:** Retrieves the content of the file with the specified filename. -### Delete File +### 3. Delete File - **Endpoint:** `DELETE /data/{filename}` -- **Description:** Deletes the file with the specified filename. \ No newline at end of file +- **Description:** Deletes the file with the specified filename. + +## Locks Endpoint +### 1. Acquire Lock +- **Endpoint:** `POST /lock/{key}?expiry={expiry_secs}` +- **Description:** Acquire a lock for the specified key for given time. By default the lock is set for 180 secs. +- **Responses:** + - `200 OK`: Lock acquired successfully. + - `423 Locked`: Lock not available. + +### 2. Release Lock + +- **Endpoint:** `POST/unlock/{key}` +- **Description:** Release a lock for the specified key. diff --git a/tests/test-metadata-api/index.js b/tests/test-metadata-api/index.js index 08e7c8dc7..b689ac0f1 100644 --- a/tests/test-metadata-api/index.js +++ b/tests/test-metadata-api/index.js @@ -1,9 +1,10 @@ const express = require('express'); const fs = require('fs'); const path = require('path'); +const lock_api = require('./locks_api') + const swaggerUi = require('swagger-ui-express'); const swaggerJsdoc = require('swagger-jsdoc'); - const app = express(); @@ -25,7 +26,7 @@ const swaggerOptions = { description: 'API for saving and deleting files', }, }, - apis: ['index.js'], // Update the path to reflect the compiled JavaScript file + apis: ['index.js','locks_api.js'], // Update the path to reflect the compiled JavaScript file }; const swaggerSpec = swaggerJsdoc(swaggerOptions); @@ -39,6 +40,7 @@ app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); * /data/{filename}: * put: * summary: Save data to a file + * tags: [Metadata File] * parameters: * - in: path * name: filename @@ -70,12 +72,50 @@ app.put('/data/:filename', (req, res) => { }); +// GET endpoint to retrieve a file +/** + * @swagger + * /data/{filename}: + * get: + * summary: Get a file + * tags: [Metadata File] + * parameters: + * - in: path + * name: filename + * schema: + * type: string + * required: true + * description: The name of the file to retrieve + * responses: + * '200': + * description: File retrieved successfully + * content: + * text/plain: + * schema: + * type: string + */ +app.get('/data/:filename', (req, res) => { + const filename = req.params.filename; + const filePath = path.join(dataDir, filename); + + fs.readFile(filePath, 'utf8', (err, data) => { + if (err) { + console.error(err); + return res.status(404).send({'message': 'File not found'}); + } + res.status(200).send(data); + }); +}); + + + // DELETE endpoint to delete a file /** * @swagger * /data/{filename}: * delete: * summary: Delete a file + * tags: [Metadata File] * parameters: * - in: path * name: filename @@ -100,9 +140,10 @@ app.delete('/data/:filename', (req, res) => { }); }); -// Serve the directory where the files are saved -app.use('/json_files', express.static(dataDir)); - +app.get('/', (req, res) => { + res.redirect('/docs'); +}); +lock_api.setup(app) // Start the server const PORT = process.env.PORT || 3000; app.listen(PORT, () => { diff --git a/tests/test-metadata-api/locks_api.js b/tests/test-metadata-api/locks_api.js new file mode 100644 index 000000000..9ad9a4a43 --- /dev/null +++ b/tests/test-metadata-api/locks_api.js @@ -0,0 +1,79 @@ +const lock = {}; + +function acquireLock(key) { + return new Promise((resolve, reject) => { + if (!lock[key]) { + lock[key] = true; + resolve(); + } else { + reject({ status: 423, message: 'Lock not available' }); + } + }); +} + +function releaseLock(key) { + lock[key] = false; +} + +function setup(app) { + /** + * @swagger + * tags: + * name: Locks + * description: API endpoints for managing locks + */ + + /** + * @swagger + * /lock/{key}: + * post: + * summary: Acquire lock + * tags: [Locks] + * parameters: + * - in: path + * name: key + * schema: + * type: string + * required: true + * description: The key of the lock to acquire + * responses: + * '200': + * description: Lock acquired successfully + * '423': + * description: Lock not available + */ + app.post('/lock/:key', async (req, res) => { + const key = req.params.key; + try { + await acquireLock(key); + res.send('Lock acquired.'); + } catch (error) { + res.status(error.status).send(error.message); + } + }); + + /** + * @swagger + * /unlock/{key}: + * post: + * summary: Release lock + * tags: [Locks] + * parameters: + * - in: path + * name: key + * schema: + * type: string + * required: true + * description: The key of the lock to release + * responses: + * '200': + * description: Lock released successfully + */ + app.post('/unlock/:key', (req, res) => { + const key = req.params.key; + releaseLock(key); + res.send('Lock released.'); + }); +} + +module.exports.setup = setup; diff --git a/tests/test-metadata-api/package.json b/tests/test-metadata-api/package.json new file mode 100644 index 000000000..408c3f036 --- /dev/null +++ b/tests/test-metadata-api/package.json @@ -0,0 +1,14 @@ +{ + "name": "test-metadata-api", + "version": "0.0.1", + "main": "index.js", + "license": "MIT", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "express": "^4.19.2", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.0" + } +} \ No newline at end of file diff --git a/tests/test-metadata-api/yarn.lock b/tests/test-metadata-api/yarn.lock new file mode 100644 index 000000000..a23104223 --- /dev/null +++ b/tests/test-metadata-api/yarn.lock @@ -0,0 +1,678 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@apidevtools/json-schema-ref-parser@^9.0.6": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8" + integrity sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg== + dependencies: + "@jsdevtools/ono" "^7.1.3" + "@types/json-schema" "^7.0.6" + call-me-maybe "^1.0.1" + js-yaml "^4.1.0" + +"@apidevtools/openapi-schemas@^2.0.4": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" + integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== + +"@apidevtools/swagger-methods@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" + integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== + +"@apidevtools/swagger-parser@10.0.3": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz#32057ae99487872c4dd96b314a1ab4b95d89eaf5" + integrity sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g== + dependencies: + "@apidevtools/json-schema-ref-parser" "^9.0.6" + "@apidevtools/openapi-schemas" "^2.0.4" + "@apidevtools/swagger-methods" "^3.0.2" + "@jsdevtools/ono" "^7.1.3" + call-me-maybe "^1.0.1" + z-schema "^5.0.1" + +"@jsdevtools/ono@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" + integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== + +"@types/json-schema@^7.0.6": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +call-me-maybe@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" + integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== + +commander@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" + integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q== + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +doctrine@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +express@^4.19.2: + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +swagger-jsdoc@^6.2.8: + version "6.2.8" + resolved "https://registry.yarnpkg.com/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz#6d33d9fb07ff4a7c1564379c52c08989ec7d0256" + integrity sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ== + dependencies: + commander "6.2.0" + doctrine "3.0.0" + glob "7.1.6" + lodash.mergewith "^4.6.2" + swagger-parser "^10.0.3" + yaml "2.0.0-1" + +swagger-parser@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/swagger-parser/-/swagger-parser-10.0.3.tgz#04cb01c18c3ac192b41161c77f81e79309135d03" + integrity sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg== + dependencies: + "@apidevtools/swagger-parser" "10.0.3" + +swagger-ui-dist@>=5.0.0: + version "5.17.2" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.17.2.tgz#de31813b18ff34e9a428cd6b9ede521164621996" + integrity sha512-V/NqUw6QoTrjSpctp2oLQvxrl3vW29UsUtZyq7B1CF0v870KOFbYGDQw8rpKaKm0JxTwHpWnW1SN9YuKZdiCyw== + +swagger-ui-express@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz#7a00a18dd909574cb0d628574a299b9ba53d4d49" + integrity sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA== + dependencies: + swagger-ui-dist ">=5.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +validator@^13.7.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" + integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yaml@2.0.0-1: + version "2.0.0-1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" + integrity sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ== + +z-schema@^5.0.1: + version "5.0.6" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" + integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== + dependencies: + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + validator "^13.7.0" + optionalDependencies: + commander "^10.0.0" From d37fc23ba16adfdb6d74730468950727d5e3d853 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 2 May 2024 11:39:57 +0545 Subject: [PATCH 132/157] Add lock expiry. --- tests/test-metadata-api/locks_api.js | 80 +++++++++++++++++++--------- tests/test-metadata-api/package.json | 5 +- tests/test-metadata-api/yarn.lock | 5 ++ 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/tests/test-metadata-api/locks_api.js b/tests/test-metadata-api/locks_api.js index 9ad9a4a43..5196a70ea 100644 --- a/tests/test-metadata-api/locks_api.js +++ b/tests/test-metadata-api/locks_api.js @@ -1,28 +1,32 @@ +const { v4: uuidv4 } = require('uuid'); const lock = {}; -function acquireLock(key) { - return new Promise((resolve, reject) => { - if (!lock[key]) { - lock[key] = true; - resolve(); - } else { - reject({ status: 423, message: 'Lock not available' }); +function acquireLock(key, expiry_secs = 180) { + const now = Date.now(); + if (!lock[key] || lock[key].expiry < now) { + const uuid = uuidv4(); + lock[key] = { + locked: true, + expiry: now + expiry_secs * 1000, + uuid: uuid, + }; + return uuid + } +} +function releaseLock(key,uuid) { + if(uuid){ + _lock=lock[key] + if(_lock && (_lock.uuid != uuid)){ + // if the uuid doesn't match, the lock should + // have expired and obtained by process. + return; } - }); + } + delete lock[key]; } -function releaseLock(key) { - lock[key] = false; -} function setup(app) { - /** - * @swagger - * tags: - * name: Locks - * description: API endpoints for managing locks - */ - /** * @swagger * /lock/{key}: @@ -36,19 +40,36 @@ function setup(app) { * type: string * required: true * description: The key of the lock to acquire + * - in: query + * name: expiry_secs + * schema: + * type: integer + * minimum: 1 + * default: 180 + * description: The expiration time of the lock in seconds (default is 180s) * responses: * '200': * description: Lock acquired successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * uuid: + * type: string + * description: The UUID of the acquired lock * '423': * description: Lock not available */ - app.post('/lock/:key', async (req, res) => { + app.post('/lock/:key', (req, res) => { const key = req.params.key; - try { - await acquireLock(key); - res.send('Lock acquired.'); - } catch (error) { - res.status(error.status).send(error.message); + const expiry_secs = req.query.expiry_secs ? parseInt(req.query.expiry_secs) : 180; + const lock_uuid=acquireLock(key, expiry_secs) + if(lock_uuid){ + res.json({ uuid: lock_uuid }) + }else{ + res.status(423).json({ status: 423, message: 'Lock not available' }); + } }); @@ -65,14 +86,23 @@ function setup(app) { * type: string * required: true * description: The key of the lock to release + * - in: query + * name: uuid + * schema: + * type: string + * required: false + * description: The UUID of the lock to release * responses: * '200': * description: Lock released successfully */ app.post('/unlock/:key', (req, res) => { const key = req.params.key; - releaseLock(key); + const uuid = req.query.uuid; + + releaseLock(key, uuid); res.send('Lock released.'); + }); } diff --git a/tests/test-metadata-api/package.json b/tests/test-metadata-api/package.json index 408c3f036..520a75019 100644 --- a/tests/test-metadata-api/package.json +++ b/tests/test-metadata-api/package.json @@ -9,6 +9,7 @@ "dependencies": { "express": "^4.19.2", "swagger-jsdoc": "^6.2.8", - "swagger-ui-express": "^5.0.0" + "swagger-ui-express": "^5.0.0", + "uuid": "^9.0.1" } -} \ No newline at end of file +} diff --git a/tests/test-metadata-api/yarn.lock b/tests/test-metadata-api/yarn.lock index a23104223..cf7a4ed22 100644 --- a/tests/test-metadata-api/yarn.lock +++ b/tests/test-metadata-api/yarn.lock @@ -646,6 +646,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + validator@^13.7.0: version "13.11.0" resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" From 0b90757b4dd4838ca87e2d9ffc13e8f69d5caa52 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 11:57:40 +0545 Subject: [PATCH 133/157] Remove un-used services --- tests/test-infrastructure/.env.example | 2 +- tests/test-infrastructure/docker-compose.yml | 74 ++------------------ 2 files changed, 6 insertions(+), 70 deletions(-) diff --git a/tests/test-infrastructure/.env.example b/tests/test-infrastructure/.env.example index fd9687eeb..92570776c 100644 --- a/tests/test-infrastructure/.env.example +++ b/tests/test-infrastructure/.env.example @@ -1,4 +1,4 @@ STACK_NAME=govtool -BASE_DOMAIN=cardanoapi.io +BASE_DOMAIN=govtool.cardanoapi.io BLOCKFROST_API_URL="" BLOCKFROST_PROJECT_ID="" diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index 9e8f77da5..ca923effd 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -39,50 +39,13 @@ networks: external: true services: - metabase: - image: metabase/metabase:v0.46.6.2 - hostname: metabase - volumes: - - /dev/urandom:/dev/random:ro - environment: - VIRTUAL_HOST: https://metabase.${BASE_DOMAIN} - MB_DB_TYPE: postgres - MB_DB_DBNAME: ${STACK_NAME}_metabase - MB_DB_PORT: 5432 - MB_DB_USER_FILE: /run/secrets/postgres_user - MB_DB_PASS_FILE: /run/secrets/postgres_password - MB_DB_HOST: postgres - networks: - - postgres - - frontend - secrets: - - postgres_password - - postgres_user - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 3G - reservations: - memory: 1.8G - - healthcheck: - test: curl --fail -I http://localhost:3000/api/health || exit 1 - interval: 15s - timeout: 5s - retries: 5 - metrics_api: image: voltaire-era/govtool-metrics-api build: context: ../test-metrics-api environment: - VIRTUAL_HOST: https://metrics.${BASE_DOMAIN}/ -> :3000/ + VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ PGHOST: postgres PGDATABASE: ${STACK_NAME}_metrics secrets: @@ -110,7 +73,7 @@ services: lhci-server: image: patrickhulce/lhci-server:0.12.0 environment: - VIRTUAL_HOST: https://lighthouse.${BASE_DOMAIN} -> :9001 + VIRTUAL_HOST: https://lighthouse-${BASE_DOMAIN} -> :9001 volumes: - lhci_data:/data secrets: @@ -137,7 +100,7 @@ services: context: ../../src/gov-action-loader-fe dockerfile: Dockerfile environment: - VIRTUAL_HOST: https://govtool-governance.${BASE_DOMAIN} + VIRTUAL_HOST: https://governance-${BASE_DOMAIN} networks: - frontend deploy: @@ -162,7 +125,7 @@ services: KUBER_API_KEY: "" BLOCKFROST_API_URL: "${BLOCKFROST_API_URL}" BLOCKFROST_PROJECT_ID: "${BLOCKFROST_PROJECT_ID}" - VIRTUAL_HOST: https://govtool-governance.${BASE_DOMAIN}/api/ -> /api/ + VIRTUAL_HOST: https://governance-${BASE_DOMAIN}/api/ -> /api/ networks: - default - frontend @@ -177,33 +140,6 @@ services: memory: 1G reservations: memory: 500M - - sonarqube_server: - image: mc1arke/sonarqube-with-community-branch-plugin:9.9-community - networks: - - frontend - - postgres - environment: - SONAR_JDBC_URL: jdbc:postgresql://postgres:5432/${STACK_NAME}_sonarqube - VIRTUAL_HOST: https+wss://sonarqube.${BASE_DOMAIN} -> :9000 - SONAR_JDBC_USERNAME: postgres - volumes: - - sonar_data:/opt/sonarqube/data - - sonar_logs:/opt/sonarqube/logs - entrypoint: "sh -c 'SONAR_JDBC_PASSWORD=\"$$( cat /run/secrets/postgres_password )\" /opt/sonarqube/docker/entrypoint.sh'" - secrets: - - postgres_password - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: 15s - resources: - limits: - memory: 3.5G - reservations: - memory: 2.2G cardano-node: image: ghcr.io/intersectmbo/cardano-node:8.7.1-pre environment: @@ -233,7 +169,7 @@ services: image: dquadrant/kuber environment: CARDANO_NODE_SOCKET_PATH: /ipc/node.socket - VIRTUAL_HOST: https://kuber.${BASE_DOMAIN} + VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} NETWORK: 4 START_ERA: CONWAY volumes: From d86245ac03e386b85b61eaa1aad32dedf5ada16d Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 12:33:20 +0545 Subject: [PATCH 134/157] Fix paths of gov-action-loader --- tests/test-infrastructure/README.md | 6 +++--- tests/test-infrastructure/docker-compose.yml | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/test-infrastructure/README.md b/tests/test-infrastructure/README.md index d91eeaa44..c0775d8eb 100644 --- a/tests/test-infrastructure/README.md +++ b/tests/test-infrastructure/README.md @@ -20,7 +20,7 @@ Services required for testing GovTool `docker stack deploy` command doesn't support `.env` file secret/config files. There's a helper script `deploy-swarm.sh` to load the environment variables from `.env` file and generate rendered docker compose file. ```bash -cd ./test/test-infrastructire # cd into the test-infrastructure folder +cd ./test/test-infrastructure # cd into the test-infrastructure folder docker swarm init # if swarm mode is not enabled yet. docker compose build # build the images docker node update xxxx --label-add govtool-test-stack=true ## set the node to be used for deploying the services @@ -73,7 +73,7 @@ It is used for visualizing the test metrics and the api response times over time **Docker Image:** [metabase/metabase:v0.46.6.4](https://hub.docker.com/layers/metabase/metabase/v0.46.6.4/images/sha256-95c60db0c87c5da9cb81f6aefd0cd548fe2c14ff8c8dcba2ea58a338865cdbd9?context=explore) ### Initial Configuration - - Setup initial account for ligin via the webapp. + - Setup initial account for login via the webapp. - Under database section in admin settings, add the `govtool_lithghouse` and `govtool_metrics` databases - Select the database and add visualizations, queries for the data. @@ -82,7 +82,7 @@ It is used for visualizing the test metrics and the api response times over time - postgres database #### Used by -- Github Action to submit lighthouse report. +- GitHub Action to submit lighthouse report. Lighthouse has audits for performance, accessibility, progressive web apps, SEO, and more. Lighthouse-Server is used to host and display the audits generated by lighthouse. diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index ca923effd..ae0942db9 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -97,7 +97,7 @@ services: governance-action-loader-ui: image: voltaire-era/govtool-governance-action-loader build: - context: ../../src/gov-action-loader-fe + context: ../../gov-action-loader/frontend dockerfile: Dockerfile environment: VIRTUAL_HOST: https://governance-${BASE_DOMAIN} @@ -118,7 +118,7 @@ services: governance-action-loader-api: image: voltaire-era/govtool-kuber-proposal-loader-proxy build: - context: ../../src/gov-action-loader-be + context: ../../gov-action-loader/backend dockerfile: Dockerfile environment: KUBER_API_URL: "http://kuber:8081" @@ -140,6 +140,7 @@ services: memory: 1G reservations: memory: 500M + cardano-node: image: ghcr.io/intersectmbo/cardano-node:8.7.1-pre environment: @@ -165,8 +166,9 @@ services: restart_policy: condition: on-failure delay: 15s + kuber: - image: dquadrant/kuber + image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 environment: CARDANO_NODE_SOCKET_PATH: /ipc/node.socket VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} From 5dc86402cb2b2407dd65a7634d38900cec90b737 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 13:17:34 +0545 Subject: [PATCH 135/157] Add dbsync service --- .../configs_template/postgres_db_setup.sql | 2 +- tests/test-infrastructure/docker-compose.yml | 40 ++++++++++++++++++- tests/test-infrastructure/gen-configs.sh | 6 ++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/tests/test-infrastructure/configs_template/postgres_db_setup.sql b/tests/test-infrastructure/configs_template/postgres_db_setup.sql index 2934a2840..7a40fccd8 100644 --- a/tests/test-infrastructure/configs_template/postgres_db_setup.sql +++ b/tests/test-infrastructure/configs_template/postgres_db_setup.sql @@ -1,4 +1,4 @@ -CREATE database ${STACK_NAME}_metabase; CREATE database ${STACK_NAME}_lighthouse; CREATE database ${STACK_NAME}_metrics; CREATE database ${STACK_NAME}_sonarqube; +CREATE database ${STACK_NAME}_dbsync; \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index ae0942db9..75281d5ef 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -12,6 +12,9 @@ secrets: metrics_api_secret_token: external: true name: ${STACK_NAME}_metrics_api_secret + dbsync_database: + external: true + name: ${STACK_NAME}_dbsync_database ## secrets syntax for docker compose stack # secrets: @@ -31,6 +34,7 @@ volumes: sonar_logs: node_data: node_ipc: + dbsync_data: networks: postgres: @@ -142,7 +146,7 @@ services: memory: 500M cardano-node: - image: ghcr.io/intersectmbo/cardano-node:8.7.1-pre + image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre environment: NETWORK: sanchonet volumes: @@ -166,7 +170,39 @@ services: restart_policy: condition: on-failure delay: 15s - + dbsync: + image: ghcr.io/intersectmbo/cardano-db-sync:sancho-4-2-1 + networks: + - postgres + environment: + NETWORK: sanchonet + POSTGRES_HOST: postgres + POSTGRES_PORT: 5432 + DISABLE_CACHE: "" + DISABLE_LEDGER: "" + DISABLE_EPOCH: "" + secrets: + - postgres_user + - source: dbsync_database + target: postgres_db + - postgres_password + volumes: + - dbsync_data:/var/lib/cexplorer + - node_ipc:/node-ipc + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + deploy: + labels: + "co_elastic_logs/enable": "false" + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + condition: on-failure + delay: 15s kuber: image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 environment: diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index 19acbcc75..b7e65678b 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -63,7 +63,8 @@ mkdir -p ./secrets; echo -n $POSTGRES_USER > ./secrets/govtool_postgres_user echo -n $POSTGRES_PASSWORD > ./secrets/govtool_postgres_password echo -n $metrics_api_secret > ./secrets/govtool_metrics_api_secret - +$DBSYNC_DATABASE="${STACK_NAME}_dbsync" +echo -n "$DBSYNC_DATABASE" > ./secrets/govtool_dbsync_database ## loop over templates and updaete them. @@ -93,6 +94,9 @@ echo "$POSTGRES_USER" | (docker secret create "${STACK_NAME}_postgres_user" - ) echo "Generating Secret: ${STACK_NAME}_postgres_password" echo "$POSTGRES_PASSWORD" | (docker secret create "${STACK_NAME}_postgres_password" - ) || true +echo "Generating Secret: ${STACK_NAME}_dbsync_database" +echo "$DBSYNC_DATABASE" | (docker secret create "${STACK_NAME}_dbsync_database" - ) || true + echo "Generating Secret: ${STACK_NAME}_metrics_api_secret" echo "$metrics_api_secret" | (docker secret create "${STACK_NAME}_metrics_api_secret" - )|| true From 0fc0f03e12344f1752bd68445e3f0d19c8082509 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 14:07:05 +0545 Subject: [PATCH 136/157] Refactor config generation script --- tests/test-infrastructure/gen-configs.sh | 99 +++++++++++------------- 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index b7e65678b..38497990e 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -2,51 +2,53 @@ ####### Script for generating docker secret files and configs. ####### If the docker is in swarm mode, it will also generate the docker swarm secrets. ####### +set -e if ! [ -f ./.env ] then echo ".env file is missing" exit 1 fi + set -a . ./.env set +a + # Function to generate a random secret in base64 format without padding and '+' function generate_secret() { openssl rand -base64 16 | tr -d '=+/' } -# Generate random secrets -export POSTGRES_USER=postgres -export POSTGRES_PASSWORD=$(generate_secret) -metrics_api_secret=$(generate_secret) - if [ "$1" == "clean" ]; then - set -x - rm -rf ./configs; - rm -rf ./secrets; - - set +x - docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 - for CONFIG_FILE in $(ls ./configs_template) + # Create secrets from files + for SECRET_FILE in $(ls ./secrets) do - echo -n "Removing Config : " - docker config rm "${STACK_NAME}_${CONFIG_FILE}" || true + SECRET_NAME="$(basename $SECRET_FILE)" + echo -n "Removing secret: ${STACK_NAME}_${SECRET_NAME}" + docker secret rm "${STACK_NAME}_${SECRET_NAME}" || true done - for SECRET_FILE in "$(ls ./secrets_template)" "postgres_user" "postgres_password" "metrics_api_secret" + # Create configs from files + for CONFIG_FILE in $(ls ./configs) do - echo -n "Removing Secret : " - docker secret rm "${STACK_NAME}_${SECRET_FILE}" ||true + CONFIG_NAME=$(basename $CONFIG_FILE) + echo -n "Removing config: ${STACK_NAME}_${CONFIG_NAME}" + docker config rm "${STACK_NAME}_${CONFIG_NAME}" || true done + + set -x + rm -rf ./configs; + rm -rf ./secrets; + + set +x; exit 0 fi ## Check if one fo the secrets already exists -if [[ -f ./secrets/govtool_postgres_user ]] +if [[ -f ./secrets/postgres_user ]] then - echo "File ./secrets/govtool_postgres_user already exists." + echo "File ./secrets/postgres_user already exists." echo "Assuming that the secrets were already generated" echo " Use:" echo " > ./gen-configs.sh clean" @@ -58,58 +60,51 @@ fi mkdir -p ./configs; mkdir -p ./secrets; +# Generate random secrets +export POSTGRES_USER=postgres +export POSTGRES_PASSWORD=$(generate_secret) +metrics_api_secret=$(generate_secret) +DBSYNC_DATABASE="${STACK_NAME}_dbsync" + -## save secrets to secrets folder -echo -n $POSTGRES_USER > ./secrets/govtool_postgres_user -echo -n $POSTGRES_PASSWORD > ./secrets/govtool_postgres_password -echo -n $metrics_api_secret > ./secrets/govtool_metrics_api_secret -$DBSYNC_DATABASE="${STACK_NAME}_dbsync" -echo -n "$DBSYNC_DATABASE" > ./secrets/govtool_dbsync_database -## loop over templates and updaete them. +# Save secrets to files +echo -n $POSTGRES_USER > ./secrets/postgres_user +echo -n $POSTGRES_PASSWORD > ./secrets/postgres_password +echo -n $metrics_api_secret > ./secrets/metrics_api_secret +echo -n "$DBSYNC_DATABASE" > ./secrets/dbsync_database +## loop over templates and update them. for CONFIG_FILE in $(ls ./configs_template) do echo -n "Config ${STACK_NAME}_${CONFIG_FILE}: " - envsubst < "./configs_template/$CONFIG_FILE" > "./configs/${STACK_NAME}_${CONFIG_FILE}" + envsubst < "./configs_template/$CONFIG_FILE" > "./configs/${CONFIG_FILE}" done for SECRET_FILE in $(ls ./secrets_template) do echo -n "Secret ${STACK_NAME}_${SECRET_FILE}: " - envsubst < "./secrets_template/$SECRET_FILE" > "./secrets/${STACK_NAME}_${SECRET_FILE}" + envsubst < "./secrets_template/$SECRET_FILE" > "./secrets/${SECRET_FILE}" done - - ################################################################################ ################ Create secret/config for swarm ############################### ################################################################################ docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 -echo "Creating Secret: ${STACK_NAME}_postgres_user" -echo "$POSTGRES_USER" | (docker secret create "${STACK_NAME}_postgres_user" - ) || true - -echo "Generating Secret: ${STACK_NAME}_postgres_password" -echo "$POSTGRES_PASSWORD" | (docker secret create "${STACK_NAME}_postgres_password" - ) || true - -echo "Generating Secret: ${STACK_NAME}_dbsync_database" -echo "$DBSYNC_DATABASE" | (docker secret create "${STACK_NAME}_dbsync_database" - ) || true - -echo "Generating Secret: ${STACK_NAME}_metrics_api_secret" -echo "$metrics_api_secret" | (docker secret create "${STACK_NAME}_metrics_api_secret" - )|| true - - - -for CONFIG_FILE in $(ls ./configs_template) -do - echo -n "Creating Config: ${STACK_NAME}_${CONFIG_FILE} " - cat "./configs/${STACK_NAME}_${CONFIG_FILE}" | docker config create "${STACK_NAME}_${CONFIG_FILE}" - || true +# Create secrets from files +ls ./secrets | while IFS= read -r SECRET_FILE; do + SECRET_NAME=$(basename "$SECRET_FILE") + echo -n "Creating Secret: ${STACK_NAME}_${SECRET_NAME}: " + cat "./secrets/$SECRET_NAME" | (docker secret create "${STACK_NAME}_${SECRET_NAME}" -) || true done -for SECRET_FILE in $(ls ./secrets_template) + +# Create configs from files +for CONFIG_FILE in $(ls ./configs) do - echo -n "Creating Secret: ${STACK_NAME}_${SECRET_FILE} " - cat "./secrets/${STACK_NAME}_${SECRET_FILE}" | docker secret create "${STACK_NAME}_${SECRET_FILE}" - ||true -done + CONFIG_NAME=$(basename $CONFIG_FILE) + echo -n "Creating Config: ${STACK_NAME}_${CONFIG_NAME}: " + cat "./configs/$CONFIG_NAME" | (docker config create "${STACK_NAME}_${CONFIG_NAME}" -) || true +done \ No newline at end of file From d9c5e08a68487af20c2280e3e49e588906321773 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 7 May 2024 12:02:20 +0545 Subject: [PATCH 137/157] Add govtool stack and update configs --- tests/test-infrastructure/.gitignore | 5 +- tests/test-infrastructure/build-images.sh | 7 +++ .../configs_template/backend_config.json | 13 +++++ tests/test-infrastructure/deploy-swarm.sh | 12 ++--- .../docker-compose-govtool.yml | 51 +++++++++++++++++++ tests/test-infrastructure/docker-compose.yml | 3 +- tests/test-infrastructure/gen-configs.sh | 38 ++++++-------- .../scripts/deploy-stack.sh | 47 +++++++++++++++++ 8 files changed, 143 insertions(+), 33 deletions(-) create mode 100755 tests/test-infrastructure/build-images.sh create mode 100644 tests/test-infrastructure/configs_template/backend_config.json create mode 100644 tests/test-infrastructure/docker-compose-govtool.yml create mode 100755 tests/test-infrastructure/scripts/deploy-stack.sh diff --git a/tests/test-infrastructure/.gitignore b/tests/test-infrastructure/.gitignore index e433f6cb7..990529fba 100644 --- a/tests/test-infrastructure/.gitignore +++ b/tests/test-infrastructure/.gitignore @@ -1,5 +1,4 @@ secrets/ configs/ -docker-compose-rendered.yml -docker-compose-swarm-rendered.yml -docker-compose-services-rendered.yml +/*-rendered.yml + diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh new file mode 100755 index 000000000..4f6796166 --- /dev/null +++ b/tests/test-infrastructure/build-images.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +export BASE_IMAGE_NAME="govtool" +# build the base image +docker build -t "$BASE_IMAGE_NAME"/backend-base -f ../../govtool/backend/Dockerfile.base ../../govtool/backend +docker compose -f ./docker-compose-govtool.yml build +docker compose -f ./docker-compose.yml build diff --git a/tests/test-infrastructure/configs_template/backend_config.json b/tests/test-infrastructure/configs_template/backend_config.json new file mode 100644 index 000000000..dbb489e80 --- /dev/null +++ b/tests/test-infrastructure/configs_template/backend_config.json @@ -0,0 +1,13 @@ +{ + "dbsyncconfig" : { + "host" : "postgres", + "dbname" : "${DBSYNC_DATABASE}", + "user" : "postgres", + "password" : "${POSTGRES_PASSWORD}", + "port" : 5432 + }, + "port" : 8080, + "host" : "0.0.0.0", + "cachedurationseconds": 20, + "sentrydsn": "https://username:password@senty.host/id" +} diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh index 90c7fc269..d9d475971 100755 --- a/tests/test-infrastructure/deploy-swarm.sh +++ b/tests/test-infrastructure/deploy-swarm.sh @@ -5,9 +5,8 @@ ## ./deploy-swarm prepare ## set -eo pipefail -set -a -. ./.env -set +a +. ./scripts/deploy-stack.sh +load_env if [ "$1" == "destroy" ] then @@ -33,15 +32,14 @@ elif [ "$1" == "prepare" ] then ## apply the enviroment to services compose file ## and deploy the stack - envsubst < ./docker-compose-services.yml > ./docker-compose-services-rendered.yml - docker stack deploy -c './docker-compose-services-rendered.yml' ${STACK_NAME}-services + deploy-stack ${STACK_NAME}-services './docker-compose-services-rendered.yml' elif [ "$1" == "finalize" ] then ## apply the environment to compose file ## deploy the govtool test infrastructure stack - envsubst < ./docker-compose.yml > ./docker-compose-rendered.yml - docker stack deploy -c './docker-compose-rendered.yml' ${STACK_NAME} + deploy-stack ${STACK_NAME} './docker-compose-rendered.yml' + else echo "Something is wrong with the command" echo diff --git a/tests/test-infrastructure/docker-compose-govtool.yml b/tests/test-infrastructure/docker-compose-govtool.yml new file mode 100644 index 000000000..2d1e9ce25 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-govtool.yml @@ -0,0 +1,51 @@ +version: "3.9" +networks: + frontend: + external: true + postgres: + external: true +configs: + config.json: + name: govtool_backend_config.json + external: true +services: + backend: + image: govtool/backend + build: + context: ../../govtool/backend + args: + BASE_IMAGE_TAG: govtool/backend-base + entrypoint: + - sh + - -c + - vva-be -c /config.json start-app + environment: + VIRTUAL_HOST: https://${BASE_DOMAIN} -> :8080 + VIRTUAL_HOST_2: https://${BASE_DOMAIN}/swagger -> :8080/swagger + VIRTUAL_HOST_3: https://${BASE_DOMAIN}/api/ -> :8080/ + + networks: + - frontend + - postgres + configs: + - config.json + deploy: + restart_policy: + delay: "30s" + placement: + constraints: + - node.labels.govtool==true + frontend: + image: govtool/frontend + build: + context: ../../govtool/frontend + environment: + VIRTUAL_HOST: https://${BASE_DOMAIN} + networks: + - frontend + deploy: + restart_policy: + delay: "30s" + placement: + constraints: + - node.labels.govtool==true \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index 75281d5ef..73b26faa8 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -16,7 +16,8 @@ secrets: external: true name: ${STACK_NAME}_dbsync_database -## secrets syntax for docker compose stack +# secrets syntax for docker compose stack +## # secrets: # postgres_user: # file: "./secrets/${STACK_NAME}_postgres_user" diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index 38497990e..33b925726 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -15,10 +15,17 @@ set +a # Function to generate a random secret in base64 format without padding and '+' function generate_secret() { - openssl rand -base64 16 | tr -d '=+/' + local filename=$2 + local var_name=$1 + if [ -s "$filename" ]; then + export "$var_name"=$(<"$filename") + else + local secret=$(openssl rand -base64 16 | tr -d '=+/') + echo -n "$secret" > "$filename" + export "$var_name"="$secret" + fi } - if [ "$1" == "clean" ]; then # Create secrets from files @@ -45,35 +52,22 @@ if [ "$1" == "clean" ]; then exit 0 fi -## Check if one fo the secrets already exists -if [[ -f ./secrets/postgres_user ]] -then - echo "File ./secrets/postgres_user already exists." - echo "Assuming that the secrets were already generated" - echo " Use:" - echo " > ./gen-configs.sh clean" - echo " To clean up the configs and secrets" - exit 0 -fi - ## create dir if not present. mkdir -p ./configs; mkdir -p ./secrets; + # Generate random secrets export POSTGRES_USER=postgres -export POSTGRES_PASSWORD=$(generate_secret) -metrics_api_secret=$(generate_secret) -DBSYNC_DATABASE="${STACK_NAME}_dbsync" - - +export DBSYNC_DATABASE="${STACK_NAME}_dbsync" # Save secrets to files echo -n $POSTGRES_USER > ./secrets/postgres_user -echo -n $POSTGRES_PASSWORD > ./secrets/postgres_password -echo -n $metrics_api_secret > ./secrets/metrics_api_secret echo -n "$DBSYNC_DATABASE" > ./secrets/dbsync_database +# generate or load the secret +generate_secret "POSTGRES_PASSWORD" "./secrets/postgres_password" + ## loop over templates and update them. for CONFIG_FILE in $(ls ./configs_template) do @@ -96,7 +90,7 @@ docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 # Create secrets from files ls ./secrets | while IFS= read -r SECRET_FILE; do SECRET_NAME=$(basename "$SECRET_FILE") - echo -n "Creating Secret: ${STACK_NAME}_${SECRET_NAME}: " + echo -n "Secret: ${STACK_NAME}_${SECRET_NAME}: " cat "./secrets/$SECRET_NAME" | (docker secret create "${STACK_NAME}_${SECRET_NAME}" -) || true done @@ -105,6 +99,6 @@ done for CONFIG_FILE in $(ls ./configs) do CONFIG_NAME=$(basename $CONFIG_FILE) - echo -n "Creating Config: ${STACK_NAME}_${CONFIG_NAME}: " + echo -n "Config: ${STACK_NAME}_${CONFIG_NAME}: " cat "./configs/$CONFIG_NAME" | (docker config create "${STACK_NAME}_${CONFIG_NAME}" -) || true done \ No newline at end of file diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh new file mode 100755 index 000000000..c1b942e34 --- /dev/null +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -0,0 +1,47 @@ +#!/bin/bash +## Docker swarm doesn't read .env file. +## This script reads env file and variables +## and apply them to compose file and +## then execute `docker stack deploy` + +set -eo pipefail + +function load_env(){ + set -a + . ./.env + set +a +} + +function help_deploy(){ + echo "Something is wrong with the command" + echo + echo " Usage:" + echo " $0 [stack-name] [filename]" + echo +} + +function deploy-stack(){ + ## apply the environment to compose file + ## deploy the govtool test infrastructure stack + ## first argument is stack name and 2nd argument is the file name + STACK_NAME=$1 + COMPOSE_FILE=$2 + FILENAME=$(basename -- "$COMPOSE_FILE") + EXTENSION="${FILENAME##*.}" + FILENAME_WITHOUT_EXT="${FILENAME%.*}" + RENDERED_FILENAME="${FILENAME_WITHOUT_EXT}-rendered.${EXTENSION}" + envsubst < "$COMPOSE_FILE" > "$RENDERED_FILENAME" + echo docker stack deploy -c "$RENDERED_FILENAME" ${STACK_NAME} +} + + +if [ "$#" -eq 0 ]; then + exit 0 +elif [ "$#" -ne 2 ]; +then + help_deploy + exit 1 +else + load_env + deploy-stack "$1" "$2" +fi From 1152f709ae62b51a379001e3d1621392b8d08cf5 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 7 May 2024 13:04:14 +0545 Subject: [PATCH 138/157] Update deploy command --- tests/test-infrastructure/deploy-swarm.sh | 30 ++++++++++++++++--- .../scripts/deploy-stack.sh | 25 ++-------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh index d9d475971..5a700622a 100755 --- a/tests/test-infrastructure/deploy-swarm.sh +++ b/tests/test-infrastructure/deploy-swarm.sh @@ -5,6 +5,7 @@ ## ./deploy-swarm prepare ## set -eo pipefail +set -vx . ./scripts/deploy-stack.sh load_env @@ -32,22 +33,43 @@ elif [ "$1" == "prepare" ] then ## apply the enviroment to services compose file ## and deploy the stack - deploy-stack ${STACK_NAME}-services './docker-compose-services-rendered.yml' + deploy-stack ${STACK_NAME}-services './docker-compose-services.yml' elif [ "$1" == "finalize" ] then ## apply the environment to compose file ## deploy the govtool test infrastructure stack - deploy-stack ${STACK_NAME} './docker-compose-rendered.yml' - + deploy-stack ${STACK_NAME}-base './docker-compose.yml' +elif [ "$1" == 'stack' ] +then + if [ "$#" -ne 2 ] + then + echo 'stack requires the stack name "govtool" | "services" | "test"' + else + case "$2" in + govtool) + deploy-stack ${STACK_NAME} './docker-compose.yml' + ;; + services) + deploy-stack ${STACK_NAME}-services './docker-compose.yml' + ;; + base) + deploy-stack ${STACK_NAME}-base './docker-compose.yml' + ;; + *) + echo 'Invalid stack name. Valid options are "base", "services", or "govtool"' + ;; + esac + fi else echo "Something is wrong with the command" echo echo " Usage:" - echo " $0 (prepare | destroy | finalize)" + echo " $0 (prepare | destroy | finalize | deploy)" echo '' echo " Options:" echo " prepare -> deploys the services required by the test stack. i.e 'postgres' and 'reverse-proxy'" echo " finalize -> deploys the test infrastructure services" echo " destroy -> teardown everything except the volumes" + echo " deploy [stack_name] -> Deploy the stack." fi diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh index c1b942e34..577eb5445 100755 --- a/tests/test-infrastructure/scripts/deploy-stack.sh +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -12,15 +12,8 @@ function load_env(){ set +a } -function help_deploy(){ - echo "Something is wrong with the command" - echo - echo " Usage:" - echo " $0 [stack-name] [filename]" - echo -} - function deploy-stack(){ + echo "++ deploy-stack" "$@" ## apply the environment to compose file ## deploy the govtool test infrastructure stack ## first argument is stack name and 2nd argument is the file name @@ -31,17 +24,5 @@ function deploy-stack(){ FILENAME_WITHOUT_EXT="${FILENAME%.*}" RENDERED_FILENAME="${FILENAME_WITHOUT_EXT}-rendered.${EXTENSION}" envsubst < "$COMPOSE_FILE" > "$RENDERED_FILENAME" - echo docker stack deploy -c "$RENDERED_FILENAME" ${STACK_NAME} -} - - -if [ "$#" -eq 0 ]; then - exit 0 -elif [ "$#" -ne 2 ]; -then - help_deploy - exit 1 -else - load_env - deploy-stack "$1" "$2" -fi + docker stack deploy -c "$RENDERED_FILENAME" ${STACK_NAME} +} \ No newline at end of file From db8bcefb9492d7b8d9e5f6d5fcc32a9bb4757e12 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 7 May 2024 16:12:51 +0545 Subject: [PATCH 139/157] Separate out individual stacks --- tests/test-infrastructure/deploy-swarm.sh | 23 +- ....yml => docker-compose-basic-services.yml} | 9 - .../docker-compose-cardano.yml | 102 ++++++++ .../docker-compose-govaction-loader.yml | 56 +++++ .../docker-compose-test.yml | 81 +++++++ tests/test-infrastructure/docker-compose.yml | 221 ------------------ 6 files changed, 251 insertions(+), 241 deletions(-) rename tests/test-infrastructure/{docker-compose-services.yml => docker-compose-basic-services.yml} (85%) create mode 100644 tests/test-infrastructure/docker-compose-cardano.yml create mode 100644 tests/test-infrastructure/docker-compose-govaction-loader.yml create mode 100644 tests/test-infrastructure/docker-compose-test.yml delete mode 100644 tests/test-infrastructure/docker-compose.yml diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh index 5a700622a..71bb38d9e 100755 --- a/tests/test-infrastructure/deploy-swarm.sh +++ b/tests/test-infrastructure/deploy-swarm.sh @@ -33,13 +33,13 @@ elif [ "$1" == "prepare" ] then ## apply the enviroment to services compose file ## and deploy the stack - deploy-stack ${STACK_NAME}-services './docker-compose-services.yml' + deploy-stack ${STACK_NAME}-services './docker-compose-basic-services.yml' elif [ "$1" == "finalize" ] then ## apply the environment to compose file ## deploy the govtool test infrastructure stack - deploy-stack ${STACK_NAME}-base './docker-compose.yml' + deploy-stack ${STACK_NAME}-base './docker-compose-cardano.yml' elif [ "$1" == 'stack' ] then if [ "$#" -ne 2 ] @@ -47,17 +47,18 @@ then echo 'stack requires the stack name "govtool" | "services" | "test"' else case "$2" in - govtool) - deploy-stack ${STACK_NAME} './docker-compose.yml' - ;; - services) - deploy-stack ${STACK_NAME}-services './docker-compose.yml' - ;; - base) - deploy-stack ${STACK_NAME}-base './docker-compose.yml' + all) + for DEPLOY_STACK in "basic-services" "cardano" "govaction-loader" "govtool" "test"; do + deploy-stack $DEPLOY_STACK "docker-compose-$DEPLOY_STACK.yml" + done ;; *) - echo 'Invalid stack name. Valid options are "base", "services", or "govtool"' + if [[ ! -f ./"docker-compose-$2.yml" ]] + then + echo "Invalid stack name. $2" + else + deploy-stack $2 "docker-compose-$2.yml" + fi ;; esac fi diff --git a/tests/test-infrastructure/docker-compose-services.yml b/tests/test-infrastructure/docker-compose-basic-services.yml similarity index 85% rename from tests/test-infrastructure/docker-compose-services.yml rename to tests/test-infrastructure/docker-compose-basic-services.yml index d7563a2ad..96d9deaf6 100644 --- a/tests/test-infrastructure/docker-compose-services.yml +++ b/tests/test-infrastructure/docker-compose-basic-services.yml @@ -11,15 +11,6 @@ configs: external: true name: ${STACK_NAME}_postgres_db_setup.sql -### secrets and configs in docker compose -# secrets: -# postgres_user: -# file: "./secrets/${STACK_NAME}_postgres_user" -# postgres_password: -# file: "./secrets/${STACK_NAME}_postgres_password" -# configs: -# postgres_db_setup.sql: -# file: "./configs/${STACK_NAME}_postgres_db_setup.sql" volumes: postgres: nginx_dhparam: diff --git a/tests/test-infrastructure/docker-compose-cardano.yml b/tests/test-infrastructure/docker-compose-cardano.yml new file mode 100644 index 000000000..c9e3b69d6 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-cardano.yml @@ -0,0 +1,102 @@ +version: "3.9" +secrets: + postgres_user: + external: true + name: ${STACK_NAME}_postgres_user + postgres_password: + external: true + name: ${STACK_NAME}_postgres_password + dbsync_database: + external: true + name: ${STACK_NAME}_dbsync_database + +volumes: + node_data: + node_ipc: + dbsync_data: + +networks: + postgres: + external: true + frontend: + external: true + cardano: + attachable: true + name: cardano + +services: + cardano-node: + image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre + environment: + NETWORK: sanchonet + volumes: + - node_data:/data + - node_ipc:/ipc + stop_grace_period: 1m + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + ports: + - target: 3001 + published: 30004 + protocol: tcp + mode: host + deploy: + placement: + constraints: + - node.labels.blockchain== true + restart_policy: + condition: on-failure + delay: 15s + dbsync: + image: ghcr.io/intersectmbo/cardano-db-sync:sancho-4-2-1 + networks: + - postgres + environment: + NETWORK: sanchonet + POSTGRES_HOST: postgres + POSTGRES_PORT: 5432 + DISABLE_CACHE: "" + DISABLE_LEDGER: "" + DISABLE_EPOCH: "" + secrets: + - postgres_user + - source: dbsync_database + target: postgres_db + - postgres_password + volumes: + - dbsync_data:/var/lib/cexplorer + - node_ipc:/node-ipc + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + deploy: + labels: + "co_elastic_logs/enable": "false" + placement: + constraints: + - node.labels.blockchain== true + restart_policy: + condition: on-failure + delay: 15s + kuber: + image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 + environment: + CARDANO_NODE_SOCKET_PATH: /ipc/node.socket + VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} + NETWORK: 4 + START_ERA: CONWAY + volumes: + - node_ipc:/ipc/ + networks: + - cardano + deploy: + placement: + constraints: + - node.labels.blockchain== true + restart_policy: + delay: "30s" diff --git a/tests/test-infrastructure/docker-compose-govaction-loader.yml b/tests/test-infrastructure/docker-compose-govaction-loader.yml new file mode 100644 index 000000000..96e10f556 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-govaction-loader.yml @@ -0,0 +1,56 @@ +version: "3.9" + +networks: + frontend: + external: true + cardano: + external: true + +services: + + governance-action-loader-ui: + image: govtool/gov-action-loader-frontend + build: + context: ../../gov-action-loader/frontend + dockerfile: Dockerfile + environment: + VIRTUAL_HOST: https://governance-${BASE_DOMAIN} + networks: + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 500M + reservations: + memory: 100M + + governance-action-loader-api: + image: govtool/gov-action-loader-backend + build: + context: ../../gov-action-loader/backend + dockerfile: Dockerfile + environment: + KUBER_API_URL: "http://kuber:8081" + KUBER_API_KEY: "" + BLOCKFROST_API_URL: "${BLOCKFROST_API_URL}" + BLOCKFROST_PROJECT_ID: "${BLOCKFROST_PROJECT_ID}" + VIRTUAL_HOST: https://governance-${BASE_DOMAIN}/api/ -> /api/ + networks: + - default + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 1G + reservations: + memory: 500M \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose-test.yml b/tests/test-infrastructure/docker-compose-test.yml new file mode 100644 index 000000000..891e88253 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-test.yml @@ -0,0 +1,81 @@ +version: "3.9" +secrets: + postgres_user: + external: true + name: ${STACK_NAME}_postgres_user + postgres_password: + external: true + name: ${STACK_NAME}_postgres_password + lighthouserc.json: + external: true + name: ${STACK_NAME}_lighthouserc.json + metrics_api_secret_token: + external: true + name: ${STACK_NAME}_metrics_api_secret + +volumes: + lhci_data: + node_data: + node_ipc: + dbsync_data: + +networks: + postgres: + external: true + frontend: + external: true + +services: + metrics_api: + image: voltaire-era/govtool-metrics-api + build: + context: ../test-metrics-api + environment: + VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ + PGHOST: postgres + PGDATABASE: ${STACK_NAME}_metrics + secrets: + - source: postgres_password + target: /run/secrets/pgpassword + - source: postgres_user + target: /run/secrets/pguser + - source: metrics_api_secret_token + target: /run/secrets/api_secret_token + networks: + - postgres + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 600M + reservations: + memory: 100M + + lhci-server: + image: patrickhulce/lhci-server:0.12.0 + environment: + VIRTUAL_HOST: https://lighthouse-${BASE_DOMAIN} -> :9001 + volumes: + - lhci_data:/data + secrets: + - source: lighthouserc.json + target: /usr/src/lhci/lighthouserc.json + networks: + - postgres + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 1G + reservations: + memory: 300M \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml deleted file mode 100644 index 73b26faa8..000000000 --- a/tests/test-infrastructure/docker-compose.yml +++ /dev/null @@ -1,221 +0,0 @@ -version: "3.9" -secrets: - postgres_user: - external: true - name: ${STACK_NAME}_postgres_user - postgres_password: - external: true - name: ${STACK_NAME}_postgres_password - lighthouserc.json: - external: true - name: ${STACK_NAME}_lighthouserc.json - metrics_api_secret_token: - external: true - name: ${STACK_NAME}_metrics_api_secret - dbsync_database: - external: true - name: ${STACK_NAME}_dbsync_database - -# secrets syntax for docker compose stack -## -# secrets: -# postgres_user: -# file: "./secrets/${STACK_NAME}_postgres_user" -# postgres_password: -# file: "./secrets/${STACK_NAME}_postgres_password" -# postgres_db: -# file: "./secrets/${STACK_NAME}_postgres_user" -# lighthouserc.json: -# file: "./secrets/${STACK_NAME}_lighthouserc.json" -# metrics_api_secret_token: -# file: "./secrets/${STACK_NAME}_metrics_api_secret" -volumes: - lhci_data: - sonar_data: - sonar_logs: - node_data: - node_ipc: - dbsync_data: - -networks: - postgres: - external: true - frontend: - external: true - -services: - metrics_api: - image: voltaire-era/govtool-metrics-api - build: - context: ../test-metrics-api - - environment: - VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ - PGHOST: postgres - PGDATABASE: ${STACK_NAME}_metrics - secrets: - - source: postgres_password - target: /run/secrets/pgpassword - - source: postgres_user - target: /run/secrets/pguser - - source: metrics_api_secret_token - target: /run/secrets/api_secret_token - networks: - - postgres - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 600M - reservations: - memory: 100M - - lhci-server: - image: patrickhulce/lhci-server:0.12.0 - environment: - VIRTUAL_HOST: https://lighthouse-${BASE_DOMAIN} -> :9001 - volumes: - - lhci_data:/data - secrets: - - source: lighthouserc.json - target: /usr/src/lhci/lighthouserc.json - networks: - - postgres - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 1G - reservations: - memory: 300M - - governance-action-loader-ui: - image: voltaire-era/govtool-governance-action-loader - build: - context: ../../gov-action-loader/frontend - dockerfile: Dockerfile - environment: - VIRTUAL_HOST: https://governance-${BASE_DOMAIN} - networks: - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 500M - reservations: - memory: 100M - - governance-action-loader-api: - image: voltaire-era/govtool-kuber-proposal-loader-proxy - build: - context: ../../gov-action-loader/backend - dockerfile: Dockerfile - environment: - KUBER_API_URL: "http://kuber:8081" - KUBER_API_KEY: "" - BLOCKFROST_API_URL: "${BLOCKFROST_API_URL}" - BLOCKFROST_PROJECT_ID: "${BLOCKFROST_PROJECT_ID}" - VIRTUAL_HOST: https://governance-${BASE_DOMAIN}/api/ -> /api/ - networks: - - default - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 1G - reservations: - memory: 500M - - cardano-node: - image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre - environment: - NETWORK: sanchonet - volumes: - - node_data:/data - - node_ipc:/ipc - stop_grace_period: 1m - logging: - driver: "json-file" - options: - max-size: "200k" - max-file: "10" - ports: - - target: 3001 - published: 30004 - protocol: tcp - mode: host - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - condition: on-failure - delay: 15s - dbsync: - image: ghcr.io/intersectmbo/cardano-db-sync:sancho-4-2-1 - networks: - - postgres - environment: - NETWORK: sanchonet - POSTGRES_HOST: postgres - POSTGRES_PORT: 5432 - DISABLE_CACHE: "" - DISABLE_LEDGER: "" - DISABLE_EPOCH: "" - secrets: - - postgres_user - - source: dbsync_database - target: postgres_db - - postgres_password - volumes: - - dbsync_data:/var/lib/cexplorer - - node_ipc:/node-ipc - logging: - driver: "json-file" - options: - max-size: "200k" - max-file: "10" - deploy: - labels: - "co_elastic_logs/enable": "false" - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - condition: on-failure - delay: 15s - kuber: - image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 - environment: - CARDANO_NODE_SOCKET_PATH: /ipc/node.socket - VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} - NETWORK: 4 - START_ERA: CONWAY - volumes: - - node_ipc:/ipc/ - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" From 52d9e0d1d012693a45b6b29fc1ec9f039f4bfb90 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:19:59 +0545 Subject: [PATCH 140/157] Refactor build scripts and gh-action --- .github/workflows/build-and-deploy-test.yml | 35 +--- gov-action-loader/backend/.env.example | 4 - gov-action-loader/backend/app/settings.py | 11 +- govtool/backend/Dockerfile | 5 +- tests/test-infrastructure/.env.example | 6 +- tests/test-infrastructure/README.md | 155 ++++-------------- tests/test-infrastructure/build-and-deploy.sh | 30 ++++ tests/test-infrastructure/build-images.sh | 15 +- .../configs_template/postgres_db_setup.sql | 8 +- tests/test-infrastructure/deploy-swarm.sh | 76 --------- tests/test-infrastructure/deploy.sh | 112 +++++++++++++ .../docker-compose-basic-services.yml | 12 +- .../docker-compose-cardano.yml | 20 +-- .../docker-compose-govaction-loader.yml | 12 +- .../docker-compose-govtool.yml | 28 +++- .../docker-compose-test.yml | 41 +---- tests/test-infrastructure/gen-configs.sh | 22 +-- .../scripts/deploy-stack.sh | 44 ++++- .../secrets_template/lighthouserc.json | 2 +- tests/test-infrastructure/sync.sh | 2 + 20 files changed, 305 insertions(+), 335 deletions(-) create mode 100755 tests/test-infrastructure/build-and-deploy.sh delete mode 100755 tests/test-infrastructure/deploy-swarm.sh create mode 100755 tests/test-infrastructure/deploy.sh create mode 100755 tests/test-infrastructure/sync.sh diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index 44c064aa3..755e615c1 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -4,12 +4,11 @@ run-name: Deploy by @${{ github.actor }} on: push: branches: - - test + - test-deployment env: ENVIRONMENT: "test" CARDANO_NETWORK: "sanchonet" - DOMAIN: "test-sanchonet.govtool.byron.network" jobs: deploy: @@ -17,22 +16,16 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: ./scripts/govtool + working-directory: ./tests/test-infrastructure env: - DBSYNC_POSTGRES_DB: "cexplorer" - DBSYNC_POSTGRES_USER: "postgres" - DBSYNC_POSTGRES_PASSWORD: "pSa8JCpQOACMUdGb" + DOCKER_HOST: ssh://ec2-user@${{secrets.TEST_STACK_SERVER_IP }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} - NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} - TRAEFIK_LE_EMAIL: "admin+govtool@binarapps.com" GTM_ID: ${{ secrets.GTM_ID }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} - IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} USERSNAP_SPACE_API_KEY: ${{ secrets.USERSNAP_SPACE_API_KEY }} steps: - name: Checkout code @@ -40,28 +33,12 @@ jobs: with: fetch-depth: 0 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v3 - with: - aws-access-key-id: ${{ secrets.GHA_AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.GHA_AWS_SECRET_ACCESS_KEY }} - aws-region: eu-west-1 - - - name: Login to AWS ECR - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-region: eu-west-1 - name: Setup SSH agent uses: webfactory/ssh-agent@v0.8.0 with: - ssh-private-key: ${{ secrets.GHA_SSH_PRIVATE_KEY }} - - - name: Deploy app - run: | - make --debug=b all + ssh-private-key: ${{ secrets.TEST_STACK_SSH_KEY }} - - name: Reprovision Grafana + - name: Update images run: | - sleep 30 # give grafana time to start up - make --debug=b reload-grafana + ./build-and-deploy.sh update-images diff --git a/gov-action-loader/backend/.env.example b/gov-action-loader/backend/.env.example index 654ec757e..8997b5adf 100644 --- a/gov-action-loader/backend/.env.example +++ b/gov-action-loader/backend/.env.example @@ -1,6 +1,2 @@ KUBER_API_URL=https://sanchonet.kuber.cardanoapi.io KUBER_API_KEY=xxxxxxxxxxxxx - -## Not required anymore -BLOCKFROST_API_URL= -BLOCKFROST_PROJECT_ID= diff --git a/gov-action-loader/backend/app/settings.py b/gov-action-loader/backend/app/settings.py index ce543cf33..4175277df 100644 --- a/gov-action-loader/backend/app/settings.py +++ b/gov-action-loader/backend/app/settings.py @@ -1,12 +1,9 @@ -from pydantic_settings import BaseSettings +from pydantic import BaseModel -class Settings(BaseSettings): +class Settings(BaseModel): kuber_api_url: str - kuber_api_key: str + kuber_api_key: str = "" # Default value is an empty string - blockfrost_api_url: str - blockfrost_project_id: str - -settings = Settings() +settings = Settings(kuber_api_url="your_api_url_here") \ No newline at end of file diff --git a/govtool/backend/Dockerfile b/govtool/backend/Dockerfile index b8882627d..7da291284 100644 --- a/govtool/backend/Dockerfile +++ b/govtool/backend/Dockerfile @@ -1,5 +1,6 @@ -ARG BASE_IMAGE_TAG -FROM 733019650473.dkr.ecr.eu-west-1.amazonaws.com/backend-base:$BASE_IMAGE_TAG +ARG BASE_IMAGE_TAG=latest +ARG BASE_IMAGE_REPO=733019650473.dkr.ecr.eu-west-1.amazonaws.com/backend-base +FROM $BASE_IMAGE_REPO:$BASE_IMAGE_TAG WORKDIR /src COPY . . RUN cabal build diff --git a/tests/test-infrastructure/.env.example b/tests/test-infrastructure/.env.example index 92570776c..81ff08a2b 100644 --- a/tests/test-infrastructure/.env.example +++ b/tests/test-infrastructure/.env.example @@ -1,4 +1,4 @@ -STACK_NAME=govtool +PROJECT_NAME=govtool +CARDANO_NETWORK=sanchonet BASE_DOMAIN=govtool.cardanoapi.io -BLOCKFROST_API_URL="" -BLOCKFROST_PROJECT_ID="" +GOVTOOL_TAG=test \ No newline at end of file diff --git a/tests/test-infrastructure/README.md b/tests/test-infrastructure/README.md index c0775d8eb..054cda6f5 100644 --- a/tests/test-infrastructure/README.md +++ b/tests/test-infrastructure/README.md @@ -1,134 +1,41 @@ GovTool Test Infrastructure ==================== -Services required for testing GovTool +Compose files and scripts to deploy and test environment of govtool. +Additionally, it deploys services required to perform integration test on the environment -## 1. Setting up the services +## Compose files and services +1. [basic-services](./docker-compose-basic-services.yml) : postgres and gateway +2. [cardano](./docker-compose-cardano.yml) : node, dbsync and kuber +3. [govtool](./docker-compose-govtool.yml) : govtool-frontend and govtool-backend +4. [govaction-loader](./docker-compose-govaction-loader.yml) : govaction-loader frontend and badkcne +5. [test](./docker-compose-test.yml) : lighthouse-server and metadata-api +## Setting up the services -#### a. Deploy with docker on swarm mode. + +#### a. Update .env file and DNS records - Create `.env` file by copying `.env.example` and update it. - Make sure that DNS is pointed to the right server. Following are the domains used. - - lighthouse.BASE_DOMAIN - - metabase.BASE_DOMAIN - - sonarqube.BASE_DOMAIN - - metrics.BASE_DOMAIN - - kuber.BASE_DOMAIN - - -`docker stack deploy` command doesn't support `.env` file secret/config files. -There's a helper script `deploy-swarm.sh` to load the environment variables from `.env` file and generate rendered docker compose file. -```bash -cd ./test/test-infrastructure # cd into the test-infrastructure folder -docker swarm init # if swarm mode is not enabled yet. -docker compose build # build the images -docker node update xxxx --label-add govtool-test-stack=true ## set the node to be used for deploying the services -./gen-configs.sh # generate configs and secrets. -./deploy-swarm.sh prepare # start postgres and nginx -sleep 30 # wait for 30 secs for postgres to be healthy -./deploy-swarm.sh finalize # deploy all the required services. -``` - -#### b. Setup -When the stack is ready, further configuration is required it the services and github repo secrets and workflow files. - -# 2. Services List - -## SonarQube Server -#### Requires -- postgres database - -#### Used by -- Github Action to submit sonar-sacanner result - -`sonar-scanner` is used for static analysis of code. -The analysis generated by sonar-scanner is saved to SonarQube server for better visibility and to see progress over time. - - -**Docker Image:** [mc1arke/sonarqube-with-community-branch-plugin:9.9-community](https://hub.docker.com/layers/mc1arke/sonarqube-with-community-branch-plugin/9.9-community/images/sha256-b91ac551bea0fc3b394eaf7f82ea79115e03db9ab47d26610b9e1566723a07a5?context=explore) - -**See :** [sonar-scanner](https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/), [actions/sonar-scanner](https://github.com/marketplace/actions/sonar-scanner) - -### Initial configuration. - -- Login and change the initial password. -``` -username: admin -password: admin -``` -- Create new project and set the projectKey in file [govtool/frontend/sonar-project.properties](../../govtool/frontend/sonar-project.properties) -- Update the github action secrets - - SONAR_HOST_URL - - SONAR_TOKEN - - -## Metabase Server -#### Requires -- postgres database - -Metabase provides UI to show graphs and visualization from different datasource. -It is used for visualizing the test metrics and the api response times over time. - -**Docker Image:** [metabase/metabase:v0.46.6.4](https://hub.docker.com/layers/metabase/metabase/v0.46.6.4/images/sha256-95c60db0c87c5da9cb81f6aefd0cd548fe2c14ff8c8dcba2ea58a338865cdbd9?context=explore) - -### Initial Configuration - - Setup initial account for login via the webapp. - - Under database section in admin settings, add the `govtool_lithghouse` and `govtool_metrics` databases - - Select the database and add visualizations, queries for the data. - -## LightHouse Report Server -#### Requires -- postgres database - -#### Used by -- GitHub Action to submit lighthouse report. - -Lighthouse has audits for performance, accessibility, progressive web apps, SEO, and more. -Lighthouse-Server is used to host and display the audits generated by lighthouse. - -**Docker Image:** [patrickhulce/lhci-server:0.12.0](https://hub.docker.com/r/patrickhulce/lhci-server) - -### Initial Configuration -- install lhci locally and run `lhci wizard` to setup project -- update `--serverBaseUrl={{...}}` parameter in [.github/workflows/lighthouse.yml](../../.github/workflows/lighthouse.yml) -- update `LHCI_SERVER_TOKEN` in github secrets. -- install lighthouse github app on the repo -- obtain app token from lighthouse app and update `LHCI_GITHUB_APP_TOKEN` secret - -See: **[lighthouse-server-docs](https://googlechrome.github.io/lighthouse-ci/docs/server.html)** - - -## Metrics API Server -#### Requires -- postgres database -- metabase *(for result visualization) - - -#### Used by -- Github Action - backend test to submit test metrics. - -Metrics API Server receives metrics collected during backend test and saves them to database. -The results are visualized in metabase. - -### Initial Configuration -- update `RECORD_METRICS_API` variable in file [.github/workflows/test_backend.yml](../../.github/workflows/test_backend.yml) - - -**Source Code:** [tests/test-metrics-api](../test-metrics-api) - -## Kuber Server -#### Requires -- cardano-node's socket connection - -#### Used by -- Cypress integration test -- Governance Data Loader - -Opensource API server for transaction building and querying the ledger . -Kuber makes it easy to construct and submit transaction from the frontend. - -**Docker Image:** [dquadrant/kuber:70be9b0166177eab5cf33e603fd3dc579e14cf31](https://hub.docker.com/layers/dquadrant/kuber/70be9b0166177eab5cf33e603fd3dc579e14cf31/images/sha256-d3b3f7c2304da8c4777155b26220238b682c81a3ff2b14753a5dc41c4f151364?context=explore) + - lighthouse-{BASE_DOMAIN} + - kuber-{BASE_DOMAIN} + - metadata-{BASE_DOMAIN} + - governance-{BASE_DOMAIN} + +### b. Prepare the machine. + - Buy a virtual server + - Install `docker` and enable `docker compose` plugin. + - execute `docker swarm init` command. + +### c. One time setup on the machine. + - Generate secrets and configurations required by the services + `./gen-configs.sh` + - Mark the nodes with labels to specify where the services should be run. In case of single node + docker swarm, all labels can be set to single node. + `./deploy.sh prepare` + +### d. Build images and deploy the stacks. + - `./build-images.sh` + - `./deploy.sh stack all` -### Initial Configuration -- update `CYPRESS_kuberApiUrl` variable in [.github/workflows/test_integration_cypress.yml](../../.github/workflows/test_integration_cypress.yml) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh new file mode 100755 index 000000000..8c5c1568f --- /dev/null +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +BASE_IMAGE_NAME=govtool +export GOVTOOL_TAG="$(git rev-parse HEAD)" +export PROJECT_NAME=govtool +export CARDANO_NETWORK=sanchonet +export BASE_DOMAIN=govtool.cardanoapi.io + +. ./scripts/deploy-stack.sh + +check_env + +# Build images +./build-images.sh +function update-service(){ + docker service update --image "$2" "$1" +} + +if [[ "$1" == "update-images" ]] + + update-service govtool_backend "$BASE_IMAGE_NAME"/backend:${GOVTOOL_TAG} + update-service govtool_frontend "$BASE_IMAGE_NAME"/frontend:${GOVTOOL_TAG} + update-service govtool_metadata-validation "$BASE_IMAGE_NAME"/metadata-validation:${GOVTOOL_TAG} + + update-service govaction-loader_backend "$BASE_IMAGE_NAME"/gov-action-loader-frontend:${GOVTOOL_TAG} + update-service govaction-loader_frontend "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} + +elif [[ $1 == "full" ]] + ./deploy stack all +fi diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index 4f6796166..b74a8721d 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -1,7 +1,14 @@ #!/bin/bash - +set -e export BASE_IMAGE_NAME="govtool" -# build the base image -docker build -t "$BASE_IMAGE_NAME"/backend-base -f ../../govtool/backend/Dockerfile.base ../../govtool/backend +BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) + +if [ -z "$BASE_IMAGE_EXISTS" ]; then + echo "Building the base image..." + docker build -t "$BASE_IMAGE_NAME"/backend-base -f ../../govtool/backend/Dockerfile.base ../../govtool/backend +else + echo "Base image already exists. Skipping build." +fi + docker compose -f ./docker-compose-govtool.yml build -docker compose -f ./docker-compose.yml build +docker compose -f ./docker-compose-govaction-loader.yml build \ No newline at end of file diff --git a/tests/test-infrastructure/configs_template/postgres_db_setup.sql b/tests/test-infrastructure/configs_template/postgres_db_setup.sql index 7a40fccd8..1c87ab3f1 100644 --- a/tests/test-infrastructure/configs_template/postgres_db_setup.sql +++ b/tests/test-infrastructure/configs_template/postgres_db_setup.sql @@ -1,4 +1,4 @@ -CREATE database ${STACK_NAME}_lighthouse; -CREATE database ${STACK_NAME}_metrics; -CREATE database ${STACK_NAME}_sonarqube; -CREATE database ${STACK_NAME}_dbsync; \ No newline at end of file +CREATE database ${PROJECT_NAME}_lighthouse; +CREATE database ${PROJECT_NAME}_metrics; +CREATE database ${PROJECT_NAME}_sonarqube; +CREATE database ${PROJECßT_NAME}_dbsync; \ No newline at end of file diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh deleted file mode 100755 index 71bb38d9e..000000000 --- a/tests/test-infrastructure/deploy-swarm.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -## Load environment variables and deploy to the docker swarm. -## -## Usages: -## ./deploy-swarm prepare -## -set -eo pipefail -set -vx -. ./scripts/deploy-stack.sh -load_env - -if [ "$1" == "destroy" ] -then - echo "This will remove everything in your stack including volumes" - echo "Are you Sure? (Y/N)" - read user_input - if ! ( [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]) - then - exit 1 - fi - echo "Proceeding..." # Delete the Docker stack if "destroy" argument is provided - docker stack rm "${STACK_NAME}-services" || echo "${STACK_NAME}-services doesn't exist" - docker stack rm ${STACK_NAME} || echo "${STACK_NAME} doesn't exist" - ./gen-configs.sh clean - - for VOLUME in $(docker volume ls --filter "label=com.docker.stack.namespace=${STACK_NAME}" -q) "${STACK_NAME}-services_postgres" - do - echo -n "Removing Volume : " - docker volume rm "$VOLUME" - done - -elif [ "$1" == "prepare" ] -then - ## apply the enviroment to services compose file - ## and deploy the stack - deploy-stack ${STACK_NAME}-services './docker-compose-basic-services.yml' - -elif [ "$1" == "finalize" ] -then - ## apply the environment to compose file - ## deploy the govtool test infrastructure stack - deploy-stack ${STACK_NAME}-base './docker-compose-cardano.yml' -elif [ "$1" == 'stack' ] -then - if [ "$#" -ne 2 ] - then - echo 'stack requires the stack name "govtool" | "services" | "test"' - else - case "$2" in - all) - for DEPLOY_STACK in "basic-services" "cardano" "govaction-loader" "govtool" "test"; do - deploy-stack $DEPLOY_STACK "docker-compose-$DEPLOY_STACK.yml" - done - ;; - *) - if [[ ! -f ./"docker-compose-$2.yml" ]] - then - echo "Invalid stack name. $2" - else - deploy-stack $2 "docker-compose-$2.yml" - fi - ;; - esac - fi -else - echo "Something is wrong with the command" - echo - echo " Usage:" - echo " $0 (prepare | destroy | finalize | deploy)" - echo '' - echo " Options:" - echo " prepare -> deploys the services required by the test stack. i.e 'postgres' and 'reverse-proxy'" - echo " finalize -> deploys the test infrastructure services" - echo " destroy -> teardown everything except the volumes" - echo " deploy [stack_name] -> Deploy the stack." -fi diff --git a/tests/test-infrastructure/deploy.sh b/tests/test-infrastructure/deploy.sh new file mode 100755 index 000000000..c14d575b9 --- /dev/null +++ b/tests/test-infrastructure/deploy.sh @@ -0,0 +1,112 @@ +#!/bin/bash +## Load environment variables and deploy to the docker swarm. +## +## Usages: +## ./deploy-swarm prepare +## +set -eo pipefail +. ./scripts/deploy-stack.sh +load_env + +DOCKER_STACKS=("basic-services" "cardano" "govaction-loader" "govtool" "test") + +if [ "$1" == "destroy" ] +then + echo "This will remove everything in your stack except volumes, configs and secrets" + echo "Are you Sure? (Y/N)" + read user_input + if ! ( [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]) + then + exit 1 + fi + echo "Proceeding..." # Delete the Docker stack if "destroy" argument is provided + + REVERSE_STACKS=() + for ((i=${#STACKS[@]}-1; i>=0; i--)); do + REVERSE_STACKS+=("${STACKS[i]}") + done + + for CUR_STACK in "${REVERSE_STACKS[@]}"; do + docker stack rm "$CUR_STACK" + sleep 6 # wait 6 seconds for each stack cleanup. + done + +# ./gen-configs.sh clean + +# for VOLUME in $(docker volume ls --filter "label=com.docker.stack.namespace=${STACK_NAME}" -q) "${STACK_NAME}-services_postgres" +# do +# echo -n "Removing Volume : " +# docker volume rm "$VOLUME" +# done +elif [ "$1" == 'prepare' ] +then + + # Get the number of nodes in the swarm + NODES=$(docker node ls --format "{{.ID}}" | wc -l) + + # If there is only one node, set the labels + if [ "$NODES" -eq 1 ]; then + NODE_ID=$(docker node ls --format "{{.ID}}") + + docker node update --label-add govtool-test-stack=true \ + --label-add blockchain=true \ + --label-add gateway=true \ + --label-add govtool=true \ + --label-add gov-action-loader=true \ + "$NODE_ID" + + echo "Labels set on node: $NODE_ID" + else + echo "There are multiple nodes in the docker swarm." + echo "Please set the following labels to correct nodes manually." + echo " - govtool-test-stack " + echo " - blockchain" + echo " - gateway" + echo " - govtool" + echo " - gov-action-loader" + echo "" + echo " e.g. $ docker node update xxxx --label-add gateway=true" + + exit 1 + fi + +elif [ "$1" == 'stack' ] +then + if [ "$#" -ne 2 ] + then + echo "stack requires the stack name". + echo "Usage :" + echo " > $0 stack [stack-name]". + echo "" + echo " stack-name : One of the following"ß + echo " $DOCKER_STACKS" + else + case "$2" in + all) + + for DEPLOY_STACK in "${DOCKER_STACKS[@]}"; do + deploy-stack "$DEPLOY_STACK" "docker-compose-$DEPLOY_STACK.yml" + done + + ;; + *) + if [[ ! -f ./"docker-compose-$2.yml" ]] + then + echo "Invalid stack name. $2" + else + deploy-stack $2 "docker-compose-$2.yml" + fi + ;; + esac + fi +else + echo "Something is wrong with the command" + echo + echo " Usage:" + echo " $0 (prepare | destroy | deploy)" + echo '' + echo " Options:" + echo " prepare -> set required labels to docker swarm node." + echo " destroy -> teardown everything except the volumes" + echo " deploy [stack_name] -> Deploy the stack." +fi diff --git a/tests/test-infrastructure/docker-compose-basic-services.yml b/tests/test-infrastructure/docker-compose-basic-services.yml index 96d9deaf6..e0b417494 100644 --- a/tests/test-infrastructure/docker-compose-basic-services.yml +++ b/tests/test-infrastructure/docker-compose-basic-services.yml @@ -2,14 +2,14 @@ version: "3.9" secrets: postgres_user: external: true - name: ${STACK_NAME}_postgres_user + name: ${PROJECT_NAME}_postgres_user postgres_password: external: true - name: ${STACK_NAME}_postgres_password + name: ${PROJECT_NAME}_postgres_password configs: postgres_db_setup.sql: external: true - name: ${STACK_NAME}_postgres_db_setup.sql + name: ${PROJECT_NAME}_postgres_db_setup.sql volumes: postgres: @@ -45,7 +45,7 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.gateway == true restart_policy: delay: "10s" postgres: @@ -64,6 +64,8 @@ services: - postgres volumes: - postgres:/var/lib/postgresql/data + ports: + - 5432:5432 restart: always healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] @@ -74,6 +76,6 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.blockchain == true restart_policy: delay: "30s" diff --git a/tests/test-infrastructure/docker-compose-cardano.yml b/tests/test-infrastructure/docker-compose-cardano.yml index c9e3b69d6..c2d262628 100644 --- a/tests/test-infrastructure/docker-compose-cardano.yml +++ b/tests/test-infrastructure/docker-compose-cardano.yml @@ -2,13 +2,13 @@ version: "3.9" secrets: postgres_user: external: true - name: ${STACK_NAME}_postgres_user + name: ${PROJECT_NAME}_postgres_user postgres_password: external: true - name: ${STACK_NAME}_postgres_password + name: ${PROJECT_NAME}_postgres_password dbsync_database: external: true - name: ${STACK_NAME}_dbsync_database + name: ${PROJECT_NAME}_dbsync_database volumes: node_data: @@ -25,10 +25,10 @@ networks: name: cardano services: - cardano-node: + node: image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre environment: - NETWORK: sanchonet + NETWORK: ${CARDANO_NETWORK} volumes: - node_data:/data - node_ipc:/ipc @@ -36,17 +36,17 @@ services: logging: driver: "json-file" options: - max-size: "200k" + max-size: "10M" max-file: "10" ports: - target: 3001 - published: 30004 + published: 3001 protocol: tcp mode: host deploy: placement: constraints: - - node.labels.blockchain== true + - node.labels.blockchain==true restart_policy: condition: on-failure delay: 15s @@ -55,7 +55,7 @@ services: networks: - postgres environment: - NETWORK: sanchonet + NETWORK: ${CARDANO_NETWORK} POSTGRES_HOST: postgres POSTGRES_PORT: 5432 DISABLE_CACHE: "" @@ -72,7 +72,7 @@ services: logging: driver: "json-file" options: - max-size: "200k" + max-size: "10M" max-file: "10" deploy: labels: diff --git a/tests/test-infrastructure/docker-compose-govaction-loader.yml b/tests/test-infrastructure/docker-compose-govaction-loader.yml index 96e10f556..97cddc345 100644 --- a/tests/test-infrastructure/docker-compose-govaction-loader.yml +++ b/tests/test-infrastructure/docker-compose-govaction-loader.yml @@ -8,8 +8,8 @@ networks: services: - governance-action-loader-ui: - image: govtool/gov-action-loader-frontend + frontend: + image: govtool/gov-action-loader-frontend:${GOVTOOL_TAG} build: context: ../../gov-action-loader/frontend dockerfile: Dockerfile @@ -20,7 +20,7 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.gov-action-loader == true restart_policy: delay: "30s" resources: @@ -29,8 +29,8 @@ services: reservations: memory: 100M - governance-action-loader-api: - image: govtool/gov-action-loader-backend + backend: + image: govtool/gov-action-loader-backend:${GOVTOOL_TAG} build: context: ../../gov-action-loader/backend dockerfile: Dockerfile @@ -46,7 +46,7 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.gov-action-loader == true restart_policy: delay: "30s" resources: diff --git a/tests/test-infrastructure/docker-compose-govtool.yml b/tests/test-infrastructure/docker-compose-govtool.yml index 2d1e9ce25..68f96b8d7 100644 --- a/tests/test-infrastructure/docker-compose-govtool.yml +++ b/tests/test-infrastructure/docker-compose-govtool.yml @@ -10,19 +10,18 @@ configs: external: true services: backend: - image: govtool/backend + image: govtool/backend:${GOVTOOL_TAG} build: context: ../../govtool/backend args: - BASE_IMAGE_TAG: govtool/backend-base + BASE_IMAGE_REPO: govtool/backend-base entrypoint: - sh - -c - vva-be -c /config.json start-app environment: - VIRTUAL_HOST: https://${BASE_DOMAIN} -> :8080 + VIRTUAL_HOST: https://${BASE_DOMAIN}/api/ -> :8080/ VIRTUAL_HOST_2: https://${BASE_DOMAIN}/swagger -> :8080/swagger - VIRTUAL_HOST_3: https://${BASE_DOMAIN}/api/ -> :8080/ networks: - frontend @@ -36,9 +35,11 @@ services: constraints: - node.labels.govtool==true frontend: - image: govtool/frontend + image: govtool/frontend:${GOVTOOL_TAG} build: context: ../../govtool/frontend + args: + VITE_BASE_URL: "" environment: VIRTUAL_HOST: https://${BASE_DOMAIN} networks: @@ -48,4 +49,19 @@ services: delay: "30s" placement: constraints: - - node.labels.govtool==true \ No newline at end of file + - node.labels.govtool==true + metadata-validation: + image: govtool/metadata-validation:${GOVTOOL_TAG} + build: + context: ../../govtool/metadata-validation + environment: + VIRTUAL_HOST: https://${BASE_DOMAIN}/metadata-validation/ -> :3000 + PORT: '3000' + networks: + - frontend + deploy: + restart_policy: + delay: "30s" + placement: + constraints: + - node.labels.govtool==true diff --git a/tests/test-infrastructure/docker-compose-test.yml b/tests/test-infrastructure/docker-compose-test.yml index 891e88253..ef350c4ee 100644 --- a/tests/test-infrastructure/docker-compose-test.yml +++ b/tests/test-infrastructure/docker-compose-test.yml @@ -1,17 +1,8 @@ version: "3.9" secrets: - postgres_user: - external: true - name: ${STACK_NAME}_postgres_user - postgres_password: - external: true - name: ${STACK_NAME}_postgres_password lighthouserc.json: external: true - name: ${STACK_NAME}_lighthouserc.json - metrics_api_secret_token: - external: true - name: ${STACK_NAME}_metrics_api_secret + name: ${PROJECT_NAME}_lighthouserc.json volumes: lhci_data: @@ -26,36 +17,6 @@ networks: external: true services: - metrics_api: - image: voltaire-era/govtool-metrics-api - build: - context: ../test-metrics-api - environment: - VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ - PGHOST: postgres - PGDATABASE: ${STACK_NAME}_metrics - secrets: - - source: postgres_password - target: /run/secrets/pgpassword - - source: postgres_user - target: /run/secrets/pguser - - source: metrics_api_secret_token - target: /run/secrets/api_secret_token - networks: - - postgres - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 600M - reservations: - memory: 100M - lhci-server: image: patrickhulce/lhci-server:0.12.0 environment: diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index 33b925726..7d8d83e65 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -32,16 +32,16 @@ if [ "$1" == "clean" ]; then for SECRET_FILE in $(ls ./secrets) do SECRET_NAME="$(basename $SECRET_FILE)" - echo -n "Removing secret: ${STACK_NAME}_${SECRET_NAME}" - docker secret rm "${STACK_NAME}_${SECRET_NAME}" || true + echo -n "Removing secret: ${PROJECT_NAME}_${SECRET_NAME}" + docker secret rm "${PROJECT_NAME}_${SECRET_NAME}" || true done # Create configs from files for CONFIG_FILE in $(ls ./configs) do CONFIG_NAME=$(basename $CONFIG_FILE) - echo -n "Removing config: ${STACK_NAME}_${CONFIG_NAME}" - docker config rm "${STACK_NAME}_${CONFIG_NAME}" || true + echo -n "Removing config: ${PROJECT_NAME}_${CONFIG_NAME}" + docker config rm "${PROJECT_NAME}_${CONFIG_NAME}" || true done set -x @@ -59,7 +59,7 @@ mkdir -p ./secrets; # Generate random secrets export POSTGRES_USER=postgres -export DBSYNC_DATABASE="${STACK_NAME}_dbsync" +export DBSYNC_DATABASE="${PROJECT_NAME}_dbsync" # Save secrets to files echo -n $POSTGRES_USER > ./secrets/postgres_user @@ -71,13 +71,13 @@ generate_secret "POSTGRES_PASSWORD" "./secrets/postgres_password" ## loop over templates and update them. for CONFIG_FILE in $(ls ./configs_template) do - echo -n "Config ${STACK_NAME}_${CONFIG_FILE}: " + echo -n "Config ${PROJECT_NAME}_${CONFIG_FILE}: " envsubst < "./configs_template/$CONFIG_FILE" > "./configs/${CONFIG_FILE}" done for SECRET_FILE in $(ls ./secrets_template) do - echo -n "Secret ${STACK_NAME}_${SECRET_FILE}: " + echo -n "Secret ${PROJECT_NAME}_${SECRET_FILE}: " envsubst < "./secrets_template/$SECRET_FILE" > "./secrets/${SECRET_FILE}" done @@ -90,8 +90,8 @@ docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 # Create secrets from files ls ./secrets | while IFS= read -r SECRET_FILE; do SECRET_NAME=$(basename "$SECRET_FILE") - echo -n "Secret: ${STACK_NAME}_${SECRET_NAME}: " - cat "./secrets/$SECRET_NAME" | (docker secret create "${STACK_NAME}_${SECRET_NAME}" -) || true + echo -n "Secret: ${PROJECT_NAME}_${SECRET_NAME}: " + cat "./secrets/$SECRET_NAME" | (docker secret create "${PROJECT_NAME}_${SECRET_NAME}" -) || true done @@ -99,6 +99,6 @@ done for CONFIG_FILE in $(ls ./configs) do CONFIG_NAME=$(basename $CONFIG_FILE) - echo -n "Config: ${STACK_NAME}_${CONFIG_NAME}: " - cat "./configs/$CONFIG_NAME" | (docker config create "${STACK_NAME}_${CONFIG_NAME}" -) || true + echo -n "Config: ${PROJECT_NAME}_${CONFIG_NAME}: " + cat "./configs/$CONFIG_NAME" | (docker config create "${PROJECT_NAME}_${CONFIG_NAME}" -) || true done \ No newline at end of file diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh index 577eb5445..0e53de421 100755 --- a/tests/test-infrastructure/scripts/deploy-stack.sh +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -7,11 +7,49 @@ set -eo pipefail function load_env(){ - set -a - . ./.env - set +a + if [[ -f ./.env ]] + then + set -a + . ./.env + set +a + fi + check_env } + +function check_env(){ + + # Path to the .env.example file + EXAMPLE_FILE=".env.example" + + unset_keys=() + + # Read each line of the .env.example file + while IFS= read -r line || [ -n "$line" ]; do + # Skip empty lines + if [ -z "$line" ]; then + continue + fi + + line=$(echo "$line" | sed -e 's/^[[:space:]]*//') + + # Extract the key from each line + key=$(echo "$line" | cut -d'=' -f1) + + if [ -z "${!key}" ]; then + unset_keys+=("$key") + fi + done < "$EXAMPLE_FILE" + + # Print error message for unset keys + if [ ${#unset_keys[@]} -gt 0 ]; then + echo "The following keys are not set in the environment:" + for key in "${unset_keys[@]}"; do + echo "- $key" + done + exit 1 + fi +} function deploy-stack(){ echo "++ deploy-stack" "$@" ## apply the environment to compose file diff --git a/tests/test-infrastructure/secrets_template/lighthouserc.json b/tests/test-infrastructure/secrets_template/lighthouserc.json index 65930f8fa..ee7be38d2 100644 --- a/tests/test-infrastructure/secrets_template/lighthouserc.json +++ b/tests/test-infrastructure/secrets_template/lighthouserc.json @@ -3,7 +3,7 @@ "server": { "storage": { "sqlDialect": "postgres", - "sqlConnectionUrl": "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres/${STACK_NAME}_lighthouse?application_name=lighthouse-ci-server" + "sqlConnectionUrl": "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres/${PROJECT_NAME}_lighthouse?application_name=lighthouse-ci-server" } } } diff --git a/tests/test-infrastructure/sync.sh b/tests/test-infrastructure/sync.sh new file mode 100755 index 000000000..d2a7058ad --- /dev/null +++ b/tests/test-infrastructure/sync.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +rsync --rsync-path="sudo rsync" -ravz ./ intersect:/root/govtool/tests/test-infrastructure From 0277fa1cceb9397d1398685e5226cdf940270297 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:30:06 +0545 Subject: [PATCH 141/157] Add debug log --- .github/workflows/build-and-deploy-test.yml | 7 ++++--- tests/test-infrastructure/build-and-deploy.sh | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index 755e615c1..c1b99afe3 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -14,9 +14,6 @@ jobs: deploy: name: Deploy app runs-on: ubuntu-latest - defaults: - run: - working-directory: ./tests/test-infrastructure env: DOCKER_HOST: ssh://ec2-user@${{secrets.TEST_STACK_SERVER_IP }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} @@ -40,5 +37,9 @@ jobs: ssh-private-key: ${{ secrets.TEST_STACK_SSH_KEY }} - name: Update images + working-directory: "./tests/test-infrastructure" run: | + pwd + ls + set +x ./build-and-deploy.sh update-images diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 8c5c1568f..30e6cd66a 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash BASE_IMAGE_NAME=govtool export GOVTOOL_TAG="$(git rev-parse HEAD)" From 0fb6971a3fe9be479d496f1ac6be0353b5025088 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:33:56 +0545 Subject: [PATCH 142/157] Add set -x command --- .github/workflows/build-and-deploy-test.yml | 2 +- tests/test-infrastructure/build-and-deploy.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index c1b99afe3..a2c7f6e55 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -41,5 +41,5 @@ jobs: run: | pwd ls - set +x + set -x; ./build-and-deploy.sh update-images diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 30e6cd66a..f9fe96b88 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash - +set -vx; BASE_IMAGE_NAME=govtool export GOVTOOL_TAG="$(git rev-parse HEAD)" export PROJECT_NAME=govtool From d05fb439616d8e4bbb21c2b8fdf8ba57529a8994 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:47:33 +0545 Subject: [PATCH 143/157] Add exit code --- tests/test-infrastructure/build-and-deploy.sh | 2 +- tests/test-infrastructure/build-images.sh | 2 +- tests/test-infrastructure/scripts/deploy-stack.sh | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index f9fe96b88..43a0faf1f 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -vx; -BASE_IMAGE_NAME=govtool +export BASE_IMAGE_NAME=govtool export GOVTOOL_TAG="$(git rev-parse HEAD)" export PROJECT_NAME=govtool export CARDANO_NETWORK=sanchonet diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index b74a8721d..b471ba6fe 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e export BASE_IMAGE_NAME="govtool" BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh index 0e53de421..38920f07e 100755 --- a/tests/test-infrastructure/scripts/deploy-stack.sh +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## Docker swarm doesn't read .env file. ## This script reads env file and variables ## and apply them to compose file and @@ -47,7 +47,8 @@ function check_env(){ for key in "${unset_keys[@]}"; do echo "- $key" done - exit 1 + echo " Exiting due to missing env variables" + exit 2 fi } function deploy-stack(){ From ca66de011ff6b5743f6b9923f2a5eda86ab67b8f Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:49:43 +0545 Subject: [PATCH 144/157] Add debug log on build-images --- tests/test-infrastructure/build-images.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index b471ba6fe..3621fddcc 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -e +set -vx; export BASE_IMAGE_NAME="govtool" BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) From b5fd880b172af9ea053aaf4d5e0958d106e70a58 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:51:57 +0545 Subject: [PATCH 145/157] Remove pipe to /dev/null --- tests/test-infrastructure/build-images.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index 3621fddcc..4a8b19e17 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -2,7 +2,7 @@ set -e set -vx; export BASE_IMAGE_NAME="govtool" -BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) +BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base) if [ -z "$BASE_IMAGE_EXISTS" ]; then echo "Building the base image..." From 5ad580a1fbb8786b2c0610bb8a5836c59283a5c0 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 09:38:36 +0545 Subject: [PATCH 146/157] Add ansible Use dawidd6/action-ansible-playbook@v2 Remove verbose commands Set GOVTOOL_TAG env-variable --- .github/workflows/build-and-deploy-test.yml | 22 ++++++----- tests/test-infrastructure/build-and-deploy.sh | 7 +++- tests/test-infrastructure/build-images.sh | 1 - tests/test-infrastructure/playbook.yml | 39 +++++++++++++++++++ 4 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 tests/test-infrastructure/playbook.yml diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index a2c7f6e55..643a6e858 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -15,7 +15,6 @@ jobs: name: Deploy app runs-on: ubuntu-latest env: - DOCKER_HOST: ssh://ec2-user@${{secrets.TEST_STACK_SERVER_IP }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} @@ -30,16 +29,21 @@ jobs: with: fetch-depth: 0 - - name: Setup SSH agent uses: webfactory/ssh-agent@v0.8.0 with: ssh-private-key: ${{ secrets.TEST_STACK_SSH_KEY }} - - name: Update images - working-directory: "./tests/test-infrastructure" - run: | - pwd - ls - set -x; - ./build-and-deploy.sh update-images + - name: Run Ansible playbook + uses: dawidd6/action-ansible-playbook@v2 + with: + playbook: playbook.yml + directory: ./tests/test-infrastructure + key: ${{ secrets.TEST_STACK_SSH_KEY }} + inventory: | + [test_server] + ${{ secrets.TEST_STACK_SERVER_IP }} ansible_user=ec2-user + options: | + --verbose + env: + GOVTOOL_TAG: ${{ github.sha }} \ No newline at end of file diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 43a0faf1f..ec886732c 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -1,11 +1,14 @@ #!/usr/bin/env bash -set -vx; export BASE_IMAGE_NAME=govtool -export GOVTOOL_TAG="$(git rev-parse HEAD)" export PROJECT_NAME=govtool export CARDANO_NETWORK=sanchonet export BASE_DOMAIN=govtool.cardanoapi.io +if [ -z "$GOVTOOL_TAG" ]; then + GOVTOOL_TAG="$(git rev-parse HEAD)" +fi +export GOVTOOL_TAG + . ./scripts/deploy-stack.sh check_env diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index 4a8b19e17..4c1b7b442 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash set -e -set -vx; export BASE_IMAGE_NAME="govtool" BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base) diff --git a/tests/test-infrastructure/playbook.yml b/tests/test-infrastructure/playbook.yml new file mode 100644 index 000000000..3effdf44d --- /dev/null +++ b/tests/test-infrastructure/playbook.yml @@ -0,0 +1,39 @@ +--- +- name: Update deployed images. + hosts: test_server + gather_facts: no + tasks: + - name: Create /opt/govtool directory if it does not exist + ansible.builtin.file: + path: /opt/govtool + state: directory + become: yes + + - name: Copy files to the server + ansible.builtin.copy: + src: "{{ item }}" + dest: "/opt/govtool/{{ item }}" + mode: '0755' + with_items: + - build-and-deploy.sh + - build-images.sh + - configs_template/ + - deploy.sh + - docker-compose-basic-services.yml + - docker-compose-cardano.yml + - docker-compose-govaction-loader.yml + - docker-compose-govtool.yml + - docker-compose-test.yml + - gen-configs.sh + - scripts/ + - secrets_template/ + - .env.example + become: yes + + - name: Execute build-and-deploy.sh + ansible.builtin.shell: "/opt/govtool/build-and-deploy.sh update-images" + args: + chdir: "/opt/govtool" + environment: + GOVTOOL_TAG: "{{ lookup('env', 'GOVTOOL_TAG') }}" + become: yes From 427bb984ada2c9a5731b3418e52611219c05d8ac Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 11:15:52 +0545 Subject: [PATCH 147/157] Fix build script --- tests/test-infrastructure/build-and-deploy.sh | 3 +- .../docker-compose-govaction-loader.yml | 2 - tests/test-infrastructure/playbook.yml | 41 ++++++------------- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index ec886732c..84a5a2eac 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -20,7 +20,7 @@ function update-service(){ } if [[ "$1" == "update-images" ]] - +then update-service govtool_backend "$BASE_IMAGE_NAME"/backend:${GOVTOOL_TAG} update-service govtool_frontend "$BASE_IMAGE_NAME"/frontend:${GOVTOOL_TAG} update-service govtool_metadata-validation "$BASE_IMAGE_NAME"/metadata-validation:${GOVTOOL_TAG} @@ -29,5 +29,6 @@ if [[ "$1" == "update-images" ]] update-service govaction-loader_frontend "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} elif [[ $1 == "full" ]] +then ./deploy stack all fi diff --git a/tests/test-infrastructure/docker-compose-govaction-loader.yml b/tests/test-infrastructure/docker-compose-govaction-loader.yml index 97cddc345..93da99808 100644 --- a/tests/test-infrastructure/docker-compose-govaction-loader.yml +++ b/tests/test-infrastructure/docker-compose-govaction-loader.yml @@ -37,8 +37,6 @@ services: environment: KUBER_API_URL: "http://kuber:8081" KUBER_API_KEY: "" - BLOCKFROST_API_URL: "${BLOCKFROST_API_URL}" - BLOCKFROST_PROJECT_ID: "${BLOCKFROST_PROJECT_ID}" VIRTUAL_HOST: https://governance-${BASE_DOMAIN}/api/ -> /api/ networks: - default diff --git a/tests/test-infrastructure/playbook.yml b/tests/test-infrastructure/playbook.yml index 3effdf44d..37656787a 100644 --- a/tests/test-infrastructure/playbook.yml +++ b/tests/test-infrastructure/playbook.yml @@ -1,39 +1,22 @@ --- -- name: Update deployed images. +- name: Update deployed images hosts: test_server gather_facts: no tasks: - - name: Create /opt/govtool directory if it does not exist - ansible.builtin.file: - path: /opt/govtool - state: directory - become: yes - - - name: Copy files to the server - ansible.builtin.copy: - src: "{{ item }}" - dest: "/opt/govtool/{{ item }}" - mode: '0755' - with_items: - - build-and-deploy.sh - - build-images.sh - - configs_template/ - - deploy.sh - - docker-compose-basic-services.yml - - docker-compose-cardano.yml - - docker-compose-govaction-loader.yml - - docker-compose-govtool.yml - - docker-compose-test.yml - - gen-configs.sh - - scripts/ - - secrets_template/ - - .env.example + - name: Checkout to GOVTOOL_TAG commit + ansible.builtin.git: + repo: https://github.com/intersectmbo/govtool + dest: /opt/govtool + version: "{{ lookup('env', 'GOVTOOL_TAG') }}" + force: yes + update: yes + clone: yes become: yes - name: Execute build-and-deploy.sh - ansible.builtin.shell: "/opt/govtool/build-and-deploy.sh update-images" + ansible.builtin.shell: "/opt/govtool/tests/test-infrastructure/build-and-deploy.sh update-images" args: - chdir: "/opt/govtool" + chdir: "/opt/govtool/tests/test-infrastructure" environment: GOVTOOL_TAG: "{{ lookup('env', 'GOVTOOL_TAG') }}" - become: yes + become: yes \ No newline at end of file From 2c2bd56bccc43c2ba854218c140e4ba10c73d46e Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 12:44:18 +0545 Subject: [PATCH 148/157] Add metadata-api deployment on test-stack --- tests/test-infrastructure/build-and-deploy.sh | 5 +++- tests/test-infrastructure/build-images.sh | 3 ++- .../docker-compose-test.yml | 24 +++++++++++++++---- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 84a5a2eac..6ea9f2107 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -28,7 +28,10 @@ then update-service govaction-loader_backend "$BASE_IMAGE_NAME"/gov-action-loader-frontend:${GOVTOOL_TAG} update-service govaction-loader_frontend "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} + # test metadata API + update-service test_metadata-api "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} + elif [[ $1 == "full" ]] then - ./deploy stack all + ./deploy.sh stack all fi diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index 4c1b7b442..e86103e7a 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -11,4 +11,5 @@ else fi docker compose -f ./docker-compose-govtool.yml build -docker compose -f ./docker-compose-govaction-loader.yml build \ No newline at end of file +docker compose -f ./docker-compose-govaction-loader.yml build +docker compose -f ./docker-compose-test.yml build \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose-test.yml b/tests/test-infrastructure/docker-compose-test.yml index ef350c4ee..21b634b18 100644 --- a/tests/test-infrastructure/docker-compose-test.yml +++ b/tests/test-infrastructure/docker-compose-test.yml @@ -6,10 +6,7 @@ secrets: volumes: lhci_data: - node_data: - node_ipc: - dbsync_data: - + metadata_data: networks: postgres: external: true @@ -39,4 +36,21 @@ services: limits: memory: 1G reservations: - memory: 300M \ No newline at end of file + memory: 300M + + metadata: + image: govtool/metadata-api:${GOVTOOL_TAG} + build: + context: ../test-metadata-api + environment: + VIRTUAL_HOST: https://metadata-${BASE_DOMAIN} -> :3000 + networks: + - frontend + volumes: + - metadata_data:/data + deploy: + restart_policy: + delay: "30s" + placement: + constraints: + - node.labels.govtool-test-stack==true \ No newline at end of file From d78f853df5a6d9ca0058f147a28a40a884be28d7 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 13:36:52 +0545 Subject: [PATCH 149/157] Fix gov-action-loader backend config --- gov-action-loader/backend/app/settings.py | 9 ++++----- .../docker-compose-govaction-loader.yml | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gov-action-loader/backend/app/settings.py b/gov-action-loader/backend/app/settings.py index 4175277df..02095e720 100644 --- a/gov-action-loader/backend/app/settings.py +++ b/gov-action-loader/backend/app/settings.py @@ -1,9 +1,8 @@ -from pydantic import BaseModel +from pydantic_settings import BaseSettings -class Settings(BaseModel): +class Settings(BaseSettings): kuber_api_url: str - kuber_api_key: str = "" # Default value is an empty string + kuber_api_key: str = '' - -settings = Settings(kuber_api_url="your_api_url_here") \ No newline at end of file +settings = Settings() diff --git a/tests/test-infrastructure/docker-compose-govaction-loader.yml b/tests/test-infrastructure/docker-compose-govaction-loader.yml index 93da99808..269bc4202 100644 --- a/tests/test-infrastructure/docker-compose-govaction-loader.yml +++ b/tests/test-infrastructure/docker-compose-govaction-loader.yml @@ -41,6 +41,7 @@ services: networks: - default - frontend + - cardano deploy: placement: constraints: From c82370885ec362cae8e726071770f890e25e5e44 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 15:07:17 +0545 Subject: [PATCH 150/157] BugFix: Fix image name of metadata service --- tests/test-infrastructure/build-and-deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 6ea9f2107..0b04468f3 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -29,7 +29,7 @@ then update-service govaction-loader_frontend "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} # test metadata API - update-service test_metadata-api "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} + update-service test_metadata-api "$BASE_IMAGE_NAME"/metadata-api:${GOVTOOL_TAG} elif [[ $1 == "full" ]] then From 4e2446e6c52cea7539ce9e575240a7549616cdc7 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 15:44:28 +0545 Subject: [PATCH 151/157] BugFix: Fix images for gov-action-loader --- tests/test-infrastructure/build-and-deploy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 0b04468f3..919f64a15 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -25,8 +25,8 @@ then update-service govtool_frontend "$BASE_IMAGE_NAME"/frontend:${GOVTOOL_TAG} update-service govtool_metadata-validation "$BASE_IMAGE_NAME"/metadata-validation:${GOVTOOL_TAG} - update-service govaction-loader_backend "$BASE_IMAGE_NAME"/gov-action-loader-frontend:${GOVTOOL_TAG} - update-service govaction-loader_frontend "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} + update-service govaction-loader_backend "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} + update-service govaction-loader_frontend "$BASE_IMAGE_NAME"/gov-action-loader-frontend:${GOVTOOL_TAG} # test metadata API update-service test_metadata-api "$BASE_IMAGE_NAME"/metadata-api:${GOVTOOL_TAG} From 902d64242534d58fbea7665c74411321198d0371 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 16:19:29 +0545 Subject: [PATCH 152/157] BugFix: Rename metadata api service name to metadata-api --- tests/test-infrastructure/docker-compose-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-infrastructure/docker-compose-test.yml b/tests/test-infrastructure/docker-compose-test.yml index 21b634b18..6b03e358d 100644 --- a/tests/test-infrastructure/docker-compose-test.yml +++ b/tests/test-infrastructure/docker-compose-test.yml @@ -38,7 +38,7 @@ services: reservations: memory: 300M - metadata: + metadata-api: image: govtool/metadata-api:${GOVTOOL_TAG} build: context: ../test-metadata-api From 91a753a3738cafe787fc32631fdddb9659b94a34 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Fri, 10 May 2024 11:52:44 +0545 Subject: [PATCH 153/157] Set VITE_BASE_URL=/api on test deployment --- tests/test-infrastructure/docker-compose-govtool.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-infrastructure/docker-compose-govtool.yml b/tests/test-infrastructure/docker-compose-govtool.yml index 68f96b8d7..b31f5b9ae 100644 --- a/tests/test-infrastructure/docker-compose-govtool.yml +++ b/tests/test-infrastructure/docker-compose-govtool.yml @@ -39,7 +39,7 @@ services: build: context: ../../govtool/frontend args: - VITE_BASE_URL: "" + VITE_BASE_URL: "/api" environment: VIRTUAL_HOST: https://${BASE_DOMAIN} networks: From 4d4670a311fa411b2d78083ff60745aad0ecc137 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Fri, 10 May 2024 15:49:45 +0545 Subject: [PATCH 154/157] Update lighthouse action --- .github/workflows/lighthouse.yml | 36 +++++++++--------------------- govtool/frontend/.lighthouserc.yml | 5 +++-- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index 2bf75ada6..1b9f8c40c 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -2,9 +2,13 @@ name: Lighthouse on: push: - paths: - - govtool/frontend/** - - .github/workflows/lighthouse.yml + branches: + - tests/lighthouse + workflow_run: + workflows: + - Build and deploy GovTool to TEST server + types: + - completed jobs: lighthouse: @@ -17,31 +21,16 @@ jobs: with: node-version: 16 - - name: Install dependencies - run: npm install - working-directory: ./govtool/frontend - - - name: Cache npm dependencies - id: npm-cache - uses: actions/cache@v3 - with: - path: | - ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('govtool/frontend/package-lock.json', 'tests/govtool-frontend/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - run: npm install -g @lhci/cli@0.12.x - - name: Run build and lighthouse task + - name: Run lighthouse task working-directory: ./govtool/frontend run: | - npm install - VITE_BASE_URL=https://staging.govtool.byron.network/ npm run build lhci collect - name: Evaluate reports if: github.repository_owner != 'IntersectMBO' + working-directory: ./govtool/frontend run: | lhci assert --preset "lighthouse:recommended" @@ -50,9 +39,4 @@ jobs: if: github.repository_owner == 'IntersectMBO' run: | lhci assert --preset lighthouse:recommended || echo "LightHouse Assertion error ignored ..." - lhci upload --githubAppToken="${{ secrets.LHCI_GITHUB_APP_TOKEN }}" --token="${{ secrets.LHCI_SERVER_TOKEN }}" --serverBaseUrl=https://lighthouse.cardanoapi.io --ignoreDuplicateBuildFailure - curl -X POST https://ligththouse.cardanoapi.io/api/metrics/build-reports \ - -d "@./lighthouseci/$(ls ./.lighthouseci |grep 'lhr.*\.json' | head -n 1)" \ - -H "commit-hash: $(git rev-parse HEAD)" \ - -H "secret-token: ${{ secrets.METRICS_SERVER_SECRET_TOKEN }}" \ - -H 'Content-Type: application/json' || echo "Metric Upload error ignored ..." + lhci upload --githubAppToken="${{ secrets.LHCI_GITHUB_APP_TOKEN }}" --token="${{ secrets.LHCI_SERVER_TOKEN }}" --serverBaseUrl=https://lighthouse-govtool.cardanoapi.io --ignoreDuplicateBuildFailure diff --git a/govtool/frontend/.lighthouserc.yml b/govtool/frontend/.lighthouserc.yml index 5e963f7ae..fe06450bb 100644 --- a/govtool/frontend/.lighthouserc.yml +++ b/govtool/frontend/.lighthouserc.yml @@ -1,5 +1,6 @@ ci: collect: - staticDistDir: "./dist" url: - - "http://localhost" + - https://govtool.cardanoapi.io + - https://govtool.cardanoapi.io/drep_directory + - https://govtool.cardanoapi.io/governance_actions \ No newline at end of file From 38ce897381c70e7b81f8740d5f5ac7ee2a33e29f Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Fri, 10 May 2024 15:55:16 +0545 Subject: [PATCH 155/157] Remove unused node options --- .github/workflows/lighthouse.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index 1b9f8c40c..a7263ebd6 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -1,9 +1,6 @@ name: Lighthouse on: - push: - branches: - - tests/lighthouse workflow_run: workflows: - Build and deploy GovTool to TEST server @@ -13,8 +10,6 @@ on: jobs: lighthouse: runs-on: ubuntu-latest - env: - NODE_OPTIONS: --max_old_space_size=4096 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v3 From 4f32371b6fa3e64191ac34a86abcc18d5035ea0a Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 14 May 2024 11:55:37 +0545 Subject: [PATCH 156/157] Expose kuber-api for tests --- tests/test-infrastructure/docker-compose-cardano.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-infrastructure/docker-compose-cardano.yml b/tests/test-infrastructure/docker-compose-cardano.yml index c2d262628..6805696bd 100644 --- a/tests/test-infrastructure/docker-compose-cardano.yml +++ b/tests/test-infrastructure/docker-compose-cardano.yml @@ -94,6 +94,7 @@ services: - node_ipc:/ipc/ networks: - cardano + - frontend deploy: placement: constraints: From 7aff6e43f81f964dce318e7b2aa49bcd0e8aebfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Tue, 14 May 2024 15:14:24 +0200 Subject: [PATCH 157/157] fix: fix test deployment workflow file --- .github/workflows/build-and-deploy-dev.yml | 2 +- .github/workflows/build-and-deploy-test.yml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-deploy-dev.yml b/.github/workflows/build-and-deploy-dev.yml index bf11bbb39..32edb1af4 100644 --- a/.github/workflows/build-and-deploy-dev.yml +++ b/.github/workflows/build-and-deploy-dev.yml @@ -23,8 +23,8 @@ jobs: GA_CLIENT_EMAIL: ${{ secrets.GA_CLIENT_EMAIL }} GA_PRIVATE_KEY: ${{ secrets.GA_PRIVATE_KEY }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} - GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} + GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index 55ade7aea..388b40dd0 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -23,7 +23,6 @@ jobs: GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} - SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} @@ -32,7 +31,9 @@ jobs: TEST_NGINX_BASIC_AUTH: ${{ secrets.TEST_NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} - PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} + SENTRY_IGNORE_API_RESOLUTION_ERROR: "1" + TRAEFIK_LE_EMAIL: "admin+govtool@binarapps.com" USERSNAP_SPACE_API_KEY: ${{ secrets.USERSNAP_SPACE_API_KEY }} steps: - name: Checkout code @@ -57,4 +58,4 @@ jobs: options: | --verbose env: - GOVTOOL_TAG: ${{ github.sha }} \ No newline at end of file + GOVTOOL_TAG: ${{ github.sha }}