Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

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

### Added

- Add a switch to show provisioners with no stake [#63]

### Changed

### Removed
Expand Down Expand Up @@ -442,6 +444,7 @@ dusk-network/rusk#3985: https://github.com/dusk-network/rusk/issues/3985
[#18]: https://github.com/dusk-network/explorer/issues/18
[#19]: https://github.com/dusk-network/explorer/issues/19
[#30]: https://github.com/dusk-network/explorer/issues/30
[#63]: https://github.com/dusk-network/explorer/issues/63
[#71]: https://github.com/dusk-network/explorer/issues/71
[#278]: https://github.com/dusk-network/explorer/pull/278
[#279]: https://github.com/dusk-network/explorer/issues/279
Expand Down
71 changes: 71 additions & 0 deletions src/lib/components/__tests__/ProvisionersCard.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,75 @@ describe("Provisioners Card", () => {
await findByText("This name is not registered.")
).toBeInTheDocument();
});

it.each([[false], [true]])(
"should show those with no stake only when asked, after the others and unranked (phone: %s)",
async (isSmallScreen) => {
const noStake = hostProvisioners.find(
(p) => !p.amount && !p.locked_amt && !p.eligibility
);
const { container, getByLabelText, getByRole, queryByRole } = render(
ProvisionersCard,
{
...baseOptions,
props: {
...baseProps,
isSmallScreen,
provisioners: hostProvisioners,
},
}
);
const count = () =>
container.querySelector(".data-card__count")?.textContent;
const rows = () =>
container.querySelectorAll(
isSmallScreen ? ".provisioners-list" : "tbody tr"
);
const toggle = getByRole("switch", {
name: "Show provisioners with no stake",
});

expect(container).toHaveTextContent("Show 2 with no stake");
expect(count()).toBe("15 of 214");

// Off, searching for one finds nothing.
await fireEvent.input(getByLabelText(/^Search provisioners/), {
target: { value: noStake?.key },
});
expect(rows()).toHaveLength(0);

await fireEvent.click(toggle);

expect(rows()).toHaveLength(1);

if (isSmallScreen) {
expect(container.querySelector(".provisioners-list__rank")).toBeNull();
} else {
expect(
container.querySelector(".provisioners-table__rank")
).toHaveTextContent(/^—$/);
}

await fireEvent.input(getByLabelText(/^Search provisioners/), {
target: { value: "" },
});

expect(count()).toBe("15 of 216");
expect(queryByRole("button", { name: "Show more" })).toBeInTheDocument();
}
);

it("should offer no switch when every provisioner has a stake", () => {
const { queryByRole } = render(ProvisionersCard, {
...baseOptions,
props: {
...baseProps,
provisioners: hostProvisioners.filter(
(p) => p.amount || p.locked_amt || p.eligibility
),
},
});

expect(queryByRole("switch")).toBeNull();
});
});
14 changes: 14 additions & 0 deletions src/lib/components/provisioners-card/ProvisionersCard.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
/* A filter field, as the web wallet's: filled, rounded, quiet. */
.provisioners-card__search {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.75rem 1.5rem;
margin-bottom: 1rem;
}

/* Those with no stake, only rewards left: off by default. */
.provisioners-card__no-stake {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--calm-muted);
font-size: 0.875rem;
}

.provisioners-card__search .dusk-textbox {
width: 100%;
max-width: 26rem;
Expand Down
40 changes: 32 additions & 8 deletions src/lib/components/provisioners-card/ProvisionersCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
ProvisionersList,
ProvisionersTable,
} from "$lib/components";
import { Button, Textbox } from "$lib/dusk/components";
import { Button, Switch, Textbox } from "$lib/dusk/components";
import { isDuskName, resolveDuskName } from "$lib/dusk-domains";
import { appStore } from "$lib/stores";

Expand All @@ -32,6 +32,9 @@
/** @type {string} */
let query = "";

/** Whether the list also shows those with no stake, only rewards left. */
let showNoStake = false;

/** @param {HostProvisioner} p */
const hasActiveStake = (p) =>
p.amount !== 0 || p.locked_amt !== 0 || p.eligibility !== 0;
Expand Down Expand Up @@ -67,14 +70,26 @@
p.key.toLowerCase().includes(search) ||
p.ownerAddress.toLowerCase().includes(search);

$: all = Array.isArray(provisioners) ? provisioners : [];

/** @type {EnrichedProvisioner[]} */
$: withStake = all
.filter(hasActiveStake)
.map(withOwner)
.toSorted((a, b) => Number(b.amount ?? 0) - Number(a.amount ?? 0))
.map((p, index) => ({ ...p, rank: index + 1 }));

// After those with a stake and unranked, the most rewards first.
/** @type {EnrichedProvisioner[]} */
$: enrichedProvisioners = Array.isArray(provisioners)
? provisioners
.filter(hasActiveStake)
.map(withOwner)
.toSorted((a, b) => Number(b.amount ?? 0) - Number(a.amount ?? 0))
.map((p, index) => ({ ...p, rank: index + 1 }))
: [];
$: withNoStake = all
.filter((p) => !hasActiveStake(p))
.map(withOwner)
.toSorted((a, b) => Number(b.reward ?? 0) - Number(a.reward ?? 0));

/** @type {EnrichedProvisioner[]} */
$: enrichedProvisioners = showNoStake
? [...withStake, ...withNoStake]
: withStake;

/**
* What each `.dusk` name searched for resolved to: the account, or why
Expand Down Expand Up @@ -146,6 +161,15 @@
placeholder="Staking or owner address, or .dusk name"
type="search"
/>
{#if withNoStake.length}
<span class="provisioners-card__no-stake">
<Switch
aria-label="Show provisioners with no stake"
bind:value={showNoStake}
/>
Show {withNoStake.length} with no stake
</span>
{/if}
</div>
{#if !displayedProvisioners.length}
<p class="provisioners-card__empty">
Expand Down
4 changes: 3 additions & 1 deletion src/lib/components/provisioners-list/ProvisionersList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
<ListItem>
<svelte:fragment slot="term">Provisioner</svelte:fragment>
<svelte:fragment slot="definition">
<span class="provisioners-list__rank">#{data.rank}</span>
{#if data.rank}
<span class="provisioners-list__rank">#{data.rank}</span>
{/if}
<AppAnchor
className="provisioners-list__staking-address chain-link"
href="/accounts/?key={data.key}">{shortId(data.key)}</AppAnchor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@

<TableRow>
<TableCell
><span class="provisioners-table__rank">{provisioner.rank}</span
><span class="provisioners-table__rank"
>{provisioner.rank || "—"}</span
></TableCell
>

Expand Down
Loading