Skip to content
Merged

v2.0.25 #3747

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
937adda
fix: use content attributes created at for newest and oldest sorting
kneerose Jun 5, 2025
4b0a348
fix: ignore space on name compare
kneerose Jun 5, 2025
cc3e767
fix: show validation failing messages for proposal sorting
kneerose Jun 5, 2025
cefdd7f
fix: increase timeout for transaction confirmation checks
kneerose Jun 5, 2025
8aa3e5e
chore: update @intersect.mbo/pdf-ui to 1.0.0-alfa
github-actions[bot] Jun 5, 2025
450afb1
Merge pull request #3736 from IntersectMBO/chore/@intersect.mbo/pdf-u…
bosko-m Jun 5, 2025
44f29dc
fix(#3733): blank page when dRep have @value in uri or label references
Ciabas Jun 5, 2025
2d3a82c
Merge pull request #3737 from IntersectMBO/3733-bug-drep-details-page…
bosko-m Jun 5, 2025
ab68af6
fix(#3733): missing group_by updates in list-dreps.sql
Ciabas Jun 6, 2025
6f1c515
Merge pull request #3738 from IntersectMBO/3733-bug-drep-details-page…
Ciabas Jun 6, 2025
5f6bf60
Merge pull request #3732 from IntersectMBO/fix/proposal-sorting-test
kneerose Jun 9, 2025
e988d13
fix: make proposal title search case-insensitive
kneerose Jun 9, 2025
6828985
fix: ensure proposal cards are visible in governance actions test
kneerose Jun 9, 2025
8bea9a1
fix: add keyboard tab for focus after input
kneerose Jun 9, 2025
b1abd4a
Revert "chore: update @intersect.mbo/pdf-ui to 1.0.0-alfa"
Ciabas Jun 9, 2025
f27027f
Merge pull request #3743 from IntersectMBO/revert-pdf-ui-alfa-1-0-0
bosko-m Jun 9, 2025
90d4403
Merge pull request #3740 from IntersectMBO/fix/proposal-search-case
kneerose Jun 10, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ changes.

### Fixed

- Fix blank page on dRep details when link or identity references contain objects: { @value: ... } not strings [Issue 3733](https://github.com/IntersectMBO/govtool/issues/3733)
- Fix missing off chain references in DRep details [Issue 3490](https://github.com/IntersectMBO/govtool/issues/3490)
- Fix blank screen and type error on linkReferences when navigating to edit dRep page that has no links [Issue 3714](https://github.com/IntersectMBO/govtool/issues/3714)
- Fix adding two link input fields when editing the dRep form when no links are present initially [Issue 3709](https://github.com/IntersectMBO/govtool/issues/3709)
Expand Down
94 changes: 71 additions & 23 deletions govtool/backend/sql/list-dreps.sql
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ HasNonDeregisterVotingAnchor AS (
EXISTS (
SELECT 1
FROM drep_registration dr_sub
WHERE
WHERE
dr_sub.drep_hash_id = dr.drep_hash_id
AND dr_sub.voting_anchor_id IS NULL
AND COALESCE(dr_sub.deposit, 0) >= 0
Expand Down Expand Up @@ -129,12 +129,24 @@ DRepData AS (
off_chain_vote_drep_data.image_hash,
COALESCE(
(
SELECT jsonb_agg(ref)
SELECT jsonb_agg(
jsonb_build_object(
'uri', COALESCE(
CASE WHEN jsonb_typeof(ref->'uri') = 'string' THEN ref->>'uri' END,
ref->'uri'->>'@value'
),
'@type', ref->>'@type',
'label', COALESCE(
CASE WHEN jsonb_typeof(ref->'label') = 'string' THEN ref->>'label' END,
ref->'label'->>'@value'
)
)
)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Identity'
Expand All @@ -143,12 +155,24 @@ DRepData AS (
) AS identity_references,
COALESCE(
(
SELECT jsonb_agg(ref)
SELECT jsonb_agg(
jsonb_build_object(
'uri', COALESCE(
CASE WHEN jsonb_typeof(ref->'uri') = 'string' THEN ref->>'uri' END,
ref->'uri'->>'@value'
),
'@type', ref->>'@type',
'label', COALESCE(
CASE WHEN jsonb_typeof(ref->'label') = 'string' THEN ref->>'label' END,
ref->'label'->>'@value'
)
)
)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Link'
Expand Down Expand Up @@ -185,7 +209,7 @@ DRepData AS (
LEFT JOIN FetchError fetch_error ON fetch_error.voting_anchor_id = leva.voting_anchor_id
LEFT JOIN HasNonDeregisterVotingAnchor hndva ON hndva.drep_hash_id = dh.id
LEFT JOIN off_chain_vote_data ocvd ON ocvd.voting_anchor_id = leva.voting_anchor_id
LEFT JOIN off_chain_vote_drep_data ON off_chain_vote_drep_data.off_chain_vote_data_id = ocvd.id
LEFT JOIN off_chain_vote_drep_data ON off_chain_vote_drep_data.off_chain_vote_data_id = ocvd.id
LEFT JOIN voting_procedure ON voting_procedure.drep_voter = dh.id
LEFT JOIN tx voting_procedure_transaction ON voting_procedure_transaction.id = voting_procedure.tx_id
LEFT JOIN block voting_procedure_block ON voting_procedure_block.id = voting_procedure_transaction.block_id
Expand Down Expand Up @@ -242,23 +266,47 @@ DRepData AS (
off_chain_vote_drep_data.image_url,
off_chain_vote_drep_data.image_hash,
(
SELECT jsonb_agg(ref)
SELECT jsonb_agg(
jsonb_build_object(
'uri', COALESCE(
CASE WHEN jsonb_typeof(ref->'uri') = 'string' THEN ref->>'uri' END,
ref->'uri'->>'@value'
),
'@type', ref->>'@type',
'label', COALESCE(
CASE WHEN jsonb_typeof(ref->'label') = 'string' THEN ref->>'label' END,
ref->'label'->>'@value'
)
)
)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Identity'
),
(
SELECT jsonb_agg(ref)
SELECT jsonb_agg(
jsonb_build_object(
'uri', COALESCE(
CASE WHEN jsonb_typeof(ref->'uri') = 'string' THEN ref->>'uri' END,
ref->'uri'->>'@value'
),
'@type', ref->>'@type',
'label', COALESCE(
CASE WHEN jsonb_typeof(ref->'label') = 'string' THEN ref->>'label' END,
ref->'label'->>'@value'
)
)
)
FROM jsonb_array_elements(
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
CASE
WHEN (ocvd.json::jsonb)->'body'->'references' IS NOT NULL
THEN (ocvd.json::jsonb)->'body'->'references'
ELSE '[]'::jsonb
END
) AS ref
WHERE ref->>'@type' = 'Link'
Expand All @@ -275,4 +323,4 @@ WHERE
objectives ILIKE ? OR
motivations ILIKE ? OR
qualifications ILIKE ?
)
)
2 changes: 2 additions & 0 deletions tests/govtool-frontend/playwright/lib/forms/dRepForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ export default class DRepForm {
await this.identityReferenceFirstDescriptionInput.fill(
dRepInfo.identityReferenceLinks[0].description
);

await this.form.keyboard.press("Tab");
}

async validateForm(dRepInfo: IDRepInfo) {
Expand Down
4 changes: 2 additions & 2 deletions tests/govtool-frontend/playwright/lib/helpers/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export async function waitForTxConfirmation(
.getByTestId("alert-warning")
.getByText("Transaction in progress", { exact: false })
).toBeVisible({
timeout: 60_000,
timeout: 90_000,
});
const url = (await transactionStatusPromise).url();
const regex = /\/transaction\/status\/([^\/]+)$/;
Expand All @@ -90,7 +90,7 @@ export async function waitForTxConfirmation(
await pollTransaction(transactionHash);
await expect(
page.getByText("In Progress", { exact: true }).first() //FIXME: Only one element needs to be displayed
).not.toBeVisible({ timeout: 60_000 });
).not.toBeVisible({ timeout: 90_000 });
}
} catch (error) {
Logger.fail(error.message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,11 @@ export default class BudgetDiscussionPage {
// API validation
for (let i = 0; i <= proposals.length - 2; i++) {
const isValid = validationFn(proposals[i], proposals[i + 1]);
expect(isValid).toBe(true);
expect(isValid, {
message:
!isValid &&
`Failed on sorting ${type} with proposals: ${proposals[i].id} and ${proposals[i + 1].id}`,
}).toBe(true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,11 @@ export default class ProposalDiscussionPage {
// API validation
for (let i = 0; i <= proposals.length - 2; i++) {
const isValid = validationFn(proposals[i], proposals[i + 1]);
expect(isValid).toBe(true);
expect(isValid, {
message:
!isValid &&
`Failed on sorting ${type} with proposals: ${proposals[i].id} and ${proposals[i + 1].id}`,
}).toBe(true);
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/govtool-frontend/playwright/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export type ProposedGovAction = {
attributes: {
proposal_id: string;
prop_name: string;
createdAt: string;
};
};
creator: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ test.describe("Budget proposal list manipulation", () => {
});

test("11B_3. Should sort budget proposals", async () => {
test.slow();
const sortOptions = {
Oldest: (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.createdAt <= p2.attributes.createdAt,
Expand All @@ -120,21 +121,35 @@ test.describe("Budget proposal list manipulation", () => {
p1.attributes.prop_comments_number <=
p2.attributes.prop_comments_number,
"Name A-Z": (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.bd_proposal_detail.data.attributes.proposal_name.localeCompare(
p2.attributes.bd_proposal_detail.data.attributes.proposal_name
) <= 0,
p1.attributes.bd_proposal_detail.data.attributes.proposal_name
.replace(/ /g, "")
.localeCompare(
p2.attributes.bd_proposal_detail.data.attributes.proposal_name.replace(
/ /g,
""
)
) <= 0,
"Name Z-A": (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.bd_proposal_detail.data.attributes.proposal_name.localeCompare(
p2.attributes.bd_proposal_detail.data.attributes.proposal_name
) >= 0,
p1.attributes.bd_proposal_detail.data.attributes.proposal_name
.replace(/ /g, "")
.localeCompare(
p2.attributes.bd_proposal_detail.data.attributes.proposal_name.replace(
/ /g,
""
)
) >= 0,
"Proposer A-Z": (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.creator.data.attributes.govtool_username.localeCompare(
p2.attributes.creator.data.attributes.govtool_username
) <= 0,
p1.attributes.creator.data.attributes.govtool_username
.replace(/ /g, "")
.localeCompare(
p2.attributes.creator.data.attributes.govtool_username
) <= 0,
"Proposer Z-A": (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.creator.data.attributes.govtool_username.localeCompare(
p2.attributes.creator.data.attributes.govtool_username
) >= 0,
p1.attributes.creator.data.attributes.govtool_username
.replace(/ /g, "")
.localeCompare(
p2.attributes.creator.data.attributes.govtool_username
) >= 0,
};

for (const [option, validationFn] of Object.entries(sortOptions)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ test("4H. Should verify none of the displayed governance actions have expired",
async () => {
const proposalCards = await govActionsPage.getAllProposals();
for (const proposalCard of proposalCards) {
await expect(proposalCard).toBeVisible();
const expiryDateEl = proposalCard.getByTestId("expiry-date");
const expiryDateTxt = await expiryDateEl.innerText();
const expiryDate = extractExpiryDateFromText(expiryDateTxt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,14 @@ test.describe("Filter and sort proposals", () => {
});

test("8B_2. Should sort the list of proposed governance actions.", async () => {
test.slow();
const sortOptions = {
Oldest: (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.createdAt <= p2.attributes.createdAt,
p1.attributes.content.attributes.createdAt <=
p2.attributes.content.attributes.createdAt,
Newest: (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.createdAt >= p2.attributes.createdAt,
p1.attributes.content.attributes.createdAt >=
p2.attributes.content.attributes.createdAt,
"Most likes": (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.prop_likes >= p2.attributes.prop_likes,
"Least likes": (p1: ProposedGovAction, p2: ProposedGovAction) =>
Expand All @@ -89,13 +92,17 @@ test.describe("Filter and sort proposals", () => {
p1.attributes.prop_comments_number <=
p2.attributes.prop_comments_number,
"Name A-Z": (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.content.attributes.prop_name.localeCompare(
p2.attributes.content.attributes.prop_name
) <= 0,
p1.attributes.content.attributes.prop_name
.replace(/ /g, "")
.localeCompare(
p2.attributes.content.attributes.prop_name.replace(/ /g, "")
) <= 0,
"Name Z-A": (p1: ProposedGovAction, p2: ProposedGovAction) =>
p1.attributes.content.attributes.prop_name.localeCompare(
p2.attributes.content.attributes.prop_name
) >= 0,
p1.attributes.content.attributes.prop_name
.replace(/ /g, "")
.localeCompare(
p2.attributes.content.attributes.prop_name.replace(/ /g, "")
) >= 0,
};

for (const [sortOption, sortFunction] of Object.entries(sortOptions)) {
Expand Down Expand Up @@ -149,7 +156,9 @@ test("8C. Should search the list of proposed governance actions.", async ({
const proposalTitle = await proposalCard
.locator('[data-testid^="proposal-"][data-testid$="-title"]')
.innerText();
expect(proposalTitle.trim()).toContain(proposalName.trim());
expect(proposalTitle.toLowerCase().trim()).toContain(
proposalName.toLowerCase().trim()
);
}
},
{
Expand Down
Loading