Skip to content
Merged

2.0.31 #3945

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0a50bb5
Allow Opening Governance Actions in New Tab from Live Voting Page
Jul 22, 2025
7f2432f
fix(#3918): disappearing governance actions for the same tx hash
MSzalowski Jul 22, 2025
70055dd
Merge pull request #3938 from IntersectMBO/fix/3918-gas-in-the-to-vot…
bosko-m Jul 22, 2025
2b7a6c4
Update DashboardGovernanceActions.tsx
bosko-m Jul 23, 2025
84a8fef
Update DashboardGovernanceActions.tsx
bosko-m Jul 23, 2025
adc5d07
Update DashboardGovernanceActions.tsx
bosko-m Jul 23, 2025
b1049f9
Update DashboardGovernanceActions.tsx
bosko-m Jul 23, 2025
f0684d1
Merge pull request #3940 from IntersectMBO/3918-race-condition-fix
bosko-m Jul 23, 2025
d86def3
Fix Back button on GA category view and tests
Jul 23, 2025
b53dcfc
Update DashboardGovernanceActions.tsx - attempt 2
bosko-m Jul 23, 2025
7c380ca
Merge pull request #3941 from IntersectMBO/3918-additional-guarding-a…
bosko-m Jul 23, 2025
f23389d
Merge pull request #3937 from IntersectMBO/issue-3924
bosko-m Jul 23, 2025
9795d27
Update API.hs - preventing caching of empty result set
bosko-m Jul 23, 2025
97e8ec6
Update API.hs - setting cache to ()
bosko-m Jul 23, 2025
64fc605
Merge pull request #3942 from IntersectMBO/3918-API.hs-prevent-cachin…
bosko-m Jul 23, 2025
60afc9f
Issue 3918 temporary bypass
mirekzielinski Jul 23, 2025
0cc6dd2
Merge branch 'develop' into issue3918_bypass
Ojly Jul 23, 2025
9e5ce6e
Merge pull request #3943 from IntersectMBO/issue3918_bypass
bosko-m Jul 23, 2025
ec457a3
Merge pull request #3944 from IntersectMBO/develop
bosko-m Jul 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ changes.

### Fixed

- Fix disappearing proposals in the governance actions list for the same tx hashes [Issue 3918](https://github.com/IntersectMBO/govtool/issues/3918)

### Changed

### Removed
Expand Down
3 changes: 2 additions & 1 deletion govtool/backend/src/VVA/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,8 @@ listProposals selectedTypes sortMode mPage mPageSize mDrepRaw mSearchQuery = do

CacheEnv {proposalListCache} <- asks vvaCache

proposals <- cacheRequest proposalListCache () (Proposal.listProposals mSearchQuery)
let emptyMSearchQuery = Just "" :: Maybe Text -- issue 3918 temporary bypass
proposals <- cacheRequest proposalListCache () (Proposal.listProposals emptyMSearchQuery)

mappedSortedAndFilteredProposals <- mapSortAndFilterProposals selectedTypes sortMode proposals
let filteredProposals = filter
Expand Down
55 changes: 37 additions & 18 deletions govtool/frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,47 @@ export default () => {
}, []);

const checkTheWalletIsActive = useCallback(() => {
const hrefCondition =
window.location.pathname === PATHS.home ||
window.location.pathname === PATHS.governanceActions ||
window.location.pathname === PATHS.governanceActionsAction;
const isWalletAvailable = () =>
window.cardano && walletName && Object.keys(window.cardano).includes(walletName);

const walletName = getItemFromLocalStorage(`${WALLET_LS_KEY}_name`);
if (window.cardano) {
const walletExtensions = Object.keys(window.cardano);
if (walletName && walletExtensions.includes(walletName)) {
enable(walletName);
return;
const cleanUpWalletData = () => {
removeItemFromLocalStorage(`${WALLET_LS_KEY}_name`);
removeItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`);
};

const waitForWalletExtension = async () => {
const timeout = 5000;
const interval = 100;
const startTime = Date.now();

while (Date.now() - startTime < timeout) {
if (isWalletAvailable()) {
enable(walletName);
return;
}
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => {
setTimeout(resolve, interval);
});
}
}
if (
(!window.cardano && walletName) ||
(walletName && !Object.keys(window.cardano).includes(walletName))
) {
if (!hrefCondition) {

if (!isOnAllowedPage) {
navigate(PATHS.home);
}
removeItemFromLocalStorage(`${WALLET_LS_KEY}_name`);
removeItemFromLocalStorage(`${WALLET_LS_KEY}_stake_key`);
cleanUpWalletData();
};

const isOnAllowedPage = [PATHS.home, PATHS.governanceActions, PATHS.governanceActionsAction]
.includes(window.location.pathname);

const walletName = getItemFromLocalStorage(`${WALLET_LS_KEY}_name`);

if (!walletName) return;

if (isWalletAvailable()) {
enable(walletName);
} else {
waitForWalletExtension();
}
}, []);

Expand Down
5 changes: 5 additions & 0 deletions govtool/frontend/src/components/atoms/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ChangeEvent } from "react";
import { LinkProps } from "react-router-dom";
import {
ButtonProps as MUIButtonProps,
CheckboxProps as MUICheckboxProps,
Expand All @@ -13,6 +14,10 @@ export type ButtonProps = Omit<MUIButtonProps, "size"> & {
isLoading?: boolean;
size?: "small" | "medium" | "large" | "extraLarge";
dataTestId?: string;
to?: LinkProps["to"];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
state?: any;
component?: React.ElementType;
};

export type LoadingButtonProps = ButtonProps & {
Expand Down
20 changes: 20 additions & 0 deletions govtool/frontend/src/components/molecules/GovernanceActionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FC } from "react";
import { Box, Skeleton } from "@mui/material";
import { Link, useLocation } from "react-router-dom";

import { Button } from "@atoms";
import {
Expand Down Expand Up @@ -58,6 +59,9 @@ export const GovernanceActionCard: FC<ActionTypeProps> = ({
bech32Prefix: "gov_action",
});

const pathname = useLocation().pathname.replace(/governance_actions.*/g, "governance_actions");
const isCategoryView = useLocation().pathname.includes("category");

return (
<Box
sx={{
Expand Down Expand Up @@ -151,6 +155,22 @@ export const GovernanceActionCard: FC<ActionTypeProps> = ({
) : (
<Button
onClick={onClick}
component={Link}
to={`${pathname}/${govActionId}`}
state={{
proposal: {
abstract,
type,
expiryDate,
expiryEpochNo,
createdDate,
createdEpochNo,
txHash,
index,
title,
},
openedFromCategoryPage: isCategoryView
}}
variant={inProgress ? "outlined" : "contained"}
size="large"
sx={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from "react";
import { useState, useEffect, useCallback, useMemo } from "react";
import { Box, CircularProgress, Tab, Tabs, styled } from "@mui/material";
import { useLocation, useNavigate } from "react-router-dom";

Expand Down Expand Up @@ -88,8 +88,12 @@ export const DashboardGovernanceActions = () => {
const prevFilters = usePrevious(queryFilters);
const prevSorting = usePrevious(chosenSorting);

const stableFilters = isAdjusting ? prevFilters ?? queryFilters : queryFilters;
const stableSorting = isAdjusting ? prevSorting ?? chosenSorting : chosenSorting;
const stableFilters = isAdjusting
? prevFilters ?? queryFilters
: queryFilters;
const stableSorting = isAdjusting
? prevSorting ?? chosenSorting
: chosenSorting;

const { proposals, isProposalsLoading } = useGetProposalsQuery({
filters: stableFilters,
Expand All @@ -103,16 +107,23 @@ export const DashboardGovernanceActions = () => {
debouncedSearchText,
);

// TODO: Black magic - that filtering should be done on the backend
const filteredProposals = proposals
?.map((proposalCategory) => {
// White Magic :)
const shouldFilter =
voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter;

const filteredProposals = useMemo(() => {
if (!shouldFilter || !proposals || !votes) return proposals;

return proposals
.map((proposalCategory) => {
const filteredActions = proposalCategory.actions.filter((action) => {
const hasVote = votes?.some((voteCategory) =>
const hasVote = votes.some((voteCategory) =>
voteCategory.actions.some(
(voteAction) => voteAction.proposal.txHash === action.txHash,
(voteAction) =>
voteAction.proposal.txHash === action.txHash &&
voteAction.proposal.index === action.index,
),
);

return !hasVote;
});

Expand All @@ -122,6 +133,7 @@ export const DashboardGovernanceActions = () => {
};
})
.filter((category) => category.actions.length > 0);
}, [proposals, votes, shouldFilter]);

const { state } = useLocation();
const [content, setContent] = useState<number>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { useNavigate, generatePath } from "react-router-dom";
import { Box } from "@mui/material";

import { Typography } from "@atoms";
import { PATHS } from "@consts";
import { useCardano } from "@context";
import { useScreenDimension, useTranslation } from "@hooks";
import { ProposalData } from "@models";
import { getProposalTypeTitle, getFullGovActionId } from "@utils";
import { getProposalTypeTitle } from "@utils";
import { Slider, ValidatedGovernanceActionCard } from "@organisms";

type GovernanceActionsToVoteProps = {
Expand All @@ -25,7 +23,6 @@ export const GovernanceActionsToVote = ({
sorting,
}: GovernanceActionsToVoteProps) => {
const { pendingTransaction } = useCardano();
const navigate = useNavigate();
const { isMobile, pagePadding } = useScreenDimension();
const { t } = useTranslation();

Expand Down Expand Up @@ -64,29 +61,6 @@ export const GovernanceActionsToVote = ({
pendingTransaction.vote?.resourceId ===
`${action.txHash ?? ""}${action.index ?? ""}`
}
onClick={() => {
navigate(
onDashboard
? generatePath(
PATHS.dashboardGovernanceActionsAction,
{
proposalId: getFullGovActionId(
action.txHash,
action.index,
),
},
)
: PATHS.governanceActionsAction.replace(
":proposalId",
getFullGovActionId(action.txHash, action.index),
),
{
state: {
proposal: action,
},
},
);
}}
/>
</div>
))}
Expand Down
28 changes: 11 additions & 17 deletions govtool/frontend/src/components/organisms/Slider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { generatePath, useNavigate } from "react-router-dom";
import { useEffect, useMemo, useState } from "react";
import { generatePath, Link } from "react-router-dom";
import { Box } from "@mui/material";
import { KeenSliderOptions } from "keen-slider";
import "keen-slider/keen-slider.min.css";
Expand Down Expand Up @@ -39,7 +39,6 @@ export const Slider = ({
const [isSliderInitialized, setIsSliderInitialized] = useState(false);

const { isMobile, screenWidth } = useScreenDimension();
const navigate = useNavigate();
const { pendingTransaction } = useCardano();
const { t } = useTranslation();

Expand Down Expand Up @@ -77,19 +76,6 @@ export const Slider = ({
instanceRef.current?.moveToIdx(0);
};

const onClickShowAll = useCallback(() => {
navigate(
generatePath(
onDashboard
? PATHS.dashboardGovernanceActionsCategory
: PATHS.governanceActionsCategory,
{
category: navigateKey,
},
),
);
}, [navigate, onDashboard]);

useEffect(() => {
if (instanceRef.current) {
setIsSliderInitialized(true);
Expand Down Expand Up @@ -129,6 +115,15 @@ export const Slider = ({
<Typography variant="title2">{title}</Typography>
{(notSlicedDataLength > 6 || (isMobile && isShowAll)) && (
<Button
component={Link}
to={`${generatePath(
onDashboard
? PATHS.dashboardGovernanceActionsCategory
: PATHS.governanceActionsCategory,
{
category: navigateKey,
},
)}`}
variant="contained"
size="medium"
sx={{
Expand All @@ -139,7 +134,6 @@ export const Slider = ({
minWidth: 93,
"&:hover": { backgroundColor: arcticWhite },
}}
onClick={onClickShowAll}
>
{t("slider.showAll")}
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useState, useEffect } from "react";

import { GovernanceActionCard } from "@molecules";
import { useValidateMutation } from "@/hooks/mutations";
import { MetadataStandard, ProposalData } from "@/models";
import { GovernanceActionCard } from "../molecules";

type ActionTypeProps = Omit<
ProposalData,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMemo, useRef } from "react";
import { generatePath, useNavigate, useParams } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import { Box, CircularProgress, Link } from "@mui/material";

import { Background, Typography } from "@atoms";
Expand All @@ -18,7 +18,6 @@ import {
useTranslation,
} from "@hooks";
import {
getFullGovActionId,
getProposalTypeLabel,
removeDuplicatedProposals,
} from "@utils";
Expand Down Expand Up @@ -141,18 +140,6 @@ export const DashboardGovernanceActionsCategory = () => {
}
onClick={() => {
saveScrollPosition();

navigate(
generatePath(PATHS.dashboardGovernanceActionsAction, {
proposalId: getFullGovActionId(item.txHash, item.index),
}),
{
state: {
proposal: item,
openedFromCategoryPage: true,
},
},
);
}}
txHash={item.txHash}
/>
Expand Down
14 changes: 0 additions & 14 deletions govtool/frontend/src/pages/GovernanceActionsCategory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
} from "@hooks";
import {
WALLET_LS_KEY,
getFullGovActionId,
getItemFromLocalStorage,
getProposalTypeLabel,
removeDuplicatedProposals,
Expand Down Expand Up @@ -142,19 +141,6 @@ export const GovernanceActionsCategory = () => {
{...item}
onClick={() => {
saveScrollPosition();

navigate(
PATHS.governanceActionsAction.replace(
":proposalId",
getFullGovActionId(item.txHash, item.index),
),
{
state: {
proposal: item,
openedFromCategoryPage: true,
},
},
);
}}
/>
</Box>
Expand Down
2 changes: 1 addition & 1 deletion govtool/frontend/src/stories/Slider.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ export const SliderComponentOverflow: Story = {
await expect(canvas.getByText("Slider title")).toBeInTheDocument();
await expect(canvas.getAllByTestId("slider")).toHaveLength(6);

await expect(canvas.getByRole("button")).toBeEnabled();
await expect(canvas.getByRole("link")).toBeEnabled();
},
};