Skip to content
Open
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
1 change: 1 addition & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Final test before demo
import React from "react"
import "App.css"
import { BrowserRouter as Router, Redirect, Route, Switch } from "react-router-dom"
Expand Down
18 changes: 18 additions & 0 deletions src/modules/etherlink/components/EvmProposalsShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react"
import { Button, Grid, Theme, styled, useMediaQuery, useTheme } from "@material-ui/core"
import { ContentContainer } from "components/ui/Table"
import FilterAltIcon from "@mui/icons-material/FilterAlt"
import HowToVoteIcon from "@mui/icons-material/HowToVote"
import { ReactComponent as LinkActive } from "assets/img/link_active.svg"
import { ReactComponent as LinkInactive } from "assets/img/link_inactive.svg"
import { ReactComponent as UnlinkActive } from "assets/img/unlink_active.svg"
Expand Down Expand Up @@ -149,6 +150,23 @@ export const EvmProposalsShell: React.FC<Props> = ({
Off-Chain
</StyledTab>
</Grid>

<Grid item>
<StyledTab
startIcon={
<HowToVoteIcon
style={{ color: selectedTab === 2 ? theme.palette.secondary.main : "#fff" }}
fontSize="small"
/>
}
disableElevation={true}
variant="contained"
onClick={() => onChangeTab(2)}
isSelected={selectedTab === 2}
>
Active
</StyledTab>
</Grid>
</TabsContainer>
</Grid>
) : null}
Expand Down
18 changes: 14 additions & 4 deletions src/modules/etherlink/explorer/EtherlinkDAO/EvmProposalsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const EvmProposalsPage = () => {
daoSelected as any
)
const offchainEnabled = isFeatureEnabled("etherlink-offchain-debate")
const selectedTab = offchainEnabled && qFilters.type === "offchain" ? 1 : 0
const selectedTab = qFilters.type === "active" ? 2 : offchainEnabled && qFilters.type === "offchain" ? 1 : 0
const [openFiltersDialog, setOpenFiltersDialog] = useState(false)
const [searchText, setSearchText] = useState("")
const [debouncedSearchText, setDebouncedSearchText] = useState("")
Expand All @@ -35,7 +35,8 @@ export const EvmProposalsPage = () => {
const onChangeTab = useCallback(
(idx: number) => {
if (!offchainEnabled && idx === 1) return
setQFilters({ type: idx === 1 ? "offchain" : "onchain" })
const type = idx === 2 ? "active" : idx === 1 ? "offchain" : "onchain"
setQFilters({ type: type as any })
},
[offchainEnabled, setQFilters]
)
Expand All @@ -61,11 +62,14 @@ export const EvmProposalsPage = () => {

const resolveDisplayStatus = (p: any) => toDisplayStatus(p.effectiveDisplayStatus || p.displayStatus || p.status)

const isOffchainActive = (p: any) => {
const isProposalActive = (p: any) => {
const disp = resolveDisplayStatus(p)
return disp === "Active" || disp === "Pending"
}

// Alias for backwards compatibility
const isOffchainActive = isProposalActive

const offchainStatusKeyForProposal = (p: any): "active" | "closed" | "no-quorum" => {
const disp = resolveDisplayStatus(p)
if (disp === "NoQuorum") return "no-quorum"
Expand Down Expand Up @@ -103,13 +107,16 @@ export const EvmProposalsPage = () => {
if (ptypes.length > 0) {
base = base.filter((p: any) => (ptypes as PTypeKey[]).some(k => matchesPtypeKey(p, k)))
}
} else if (offchainEnabled) {
} else if (selectedTab === 1 && offchainEnabled) {
// off-chain
base = base.filter(p => p.type === "offchain")
const offStatuses = ((qFilters.status || []) as string[]).filter(s => s !== "all")
if (offStatuses.length > 0) {
base = base.filter(p => offStatuses.includes(offchainStatusKeyForProposal(p)))
}
} else if (selectedTab === 2) {
// Active tab - show all active/pending proposals (both on-chain and off-chain)
base = base.filter(p => isProposalActive(p))
}

if (debouncedSearchText) {
Expand Down Expand Up @@ -163,6 +170,9 @@ export const EvmProposalsPage = () => {
<EvmDaoProposalList proposals={(filteredProposals || []).filter(p => p.type === "offchain")} />
</TabPanel>
) : null}
<TabPanel value={selectedTab} index={2}>
<EvmDaoProposalList proposals={filteredProposals || []} />
</TabPanel>
</Grid>
</EvmProposalsShell>
<EvmProposalsActionDialog open={isProposalDialogOpen} handleClose={() => setIsProposalDialogOpen(false)} />
Expand Down
14 changes: 9 additions & 5 deletions src/modules/etherlink/explorer/filters/queryFilters.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DisplayStatus } from "modules/etherlink/status"

export type TypeKey = "onchain" | "offchain"
export type TypeKey = "onchain" | "offchain" | "active"

// Canonical, hyphenated keys for URL usage
export type StatusKey =
Expand Down Expand Up @@ -104,7 +104,9 @@ const splitCsv = (v?: string | null) =>

export function canonicalType(value?: string | null): TypeKey {
const v = normalize(value)
return v === "offchain" ? "offchain" : "onchain"
if (v === "offchain") return "offchain"
if (v === "active") return "active"
return "onchain"
}

export function canonicalStatuses(
Expand Down Expand Up @@ -173,7 +175,7 @@ export function parseFiltersFromSearch(search: string): ParsedFilters {
const t = canonicalType(sp.get("type"))
const author = sp.get("author")
const status = canonicalStatuses(sp.get("status"), t)
const ptype = t === "offchain" ? [] : canonicalPtypes(sp.get("ptype"))
const ptype = t === "offchain" || t === "active" ? [] : canonicalPtypes(sp.get("ptype"))
return { type: t, status, ptype, author }
}

Expand All @@ -185,8 +187,9 @@ export function serializeFiltersToSearch(filters: ParsedFilters, prevSearch: str
sp.delete("status")
sp.delete("ptype")

// type: only emit when offchain (onchain is default)
// type: only emit when offchain or active (onchain is default)
if (filters.type === "offchain") sp.set("type", "offchain")
if (filters.type === "active") sp.set("type", "active")

// status
const statuses = (filters.status || []).filter(Boolean) as string[]
Expand All @@ -196,7 +199,8 @@ export function serializeFiltersToSearch(filters: ParsedFilters, prevSearch: str
const off = statusSet.filter(s => s === "active" || s === "closed" || s === "no-quorum")
if (off.length === 1) sp.set("status", off[0])
if (off.length > 1) sp.set("status", off.sort().join(","))
} else {
} else if (filters.type !== "active") {
// Active tab doesn't need status filters in URL
const withoutAll = statusSet.filter(s => s !== "all")
if (withoutAll.length > 0) sp.set("status", withoutAll.sort().join(","))
}
Expand Down
36 changes: 36 additions & 0 deletions src/modules/explorer/pages/Proposals/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ProposalStatus } from "services/services/dao/mappers/proposal/types"
import NewReleasesIcon from "@mui/icons-material/NewReleases"
import DeleteIcon from "@mui/icons-material/Delete"
import FilterAltIcon from "@mui/icons-material/FilterAlt"
import HowToVoteIcon from "@mui/icons-material/HowToVote"
import { FilterProposalsDialog } from "modules/explorer/components/FiltersDialog"
import { Filters } from "../User/components/UserMovements"
import { EvmProposalsPage } from "modules/etherlink/explorer/EtherlinkDAO/EvmProposalsPage"
Expand Down Expand Up @@ -112,6 +113,7 @@ const TezosProposals = () => {
const [selectedTab, setSelectedTab] = React.useState(0)

const { data: proposals } = useProposals(daoId)
const { data: activeProposals } = useProposals(daoId, ProposalStatus.ACTIVE)
const theme = useTheme()
const isMobileSmall = useMediaQuery(theme.breakpoints.down("xs"))
const proposalTypeQuery = new URLSearchParams(window.location.search).get("type")
Expand Down Expand Up @@ -260,6 +262,17 @@ const TezosProposals = () => {
Off-Chain
</StyledTab>
</Grid>
<Grid item>
<StyledTab
startIcon={<HowToVoteIcon style={{ fontSize: 20, color: selectedTab === 2 ? "#85C4FF" : "#fff" }} />}
disableElevation={true}
variant="contained"
onClick={() => handleChangeTab(2)}
isSelected={selectedTab === 2}
>
Active
</StyledTab>
</Grid>
</TabsContainer>
</Grid>

Expand Down Expand Up @@ -320,6 +333,29 @@ const TezosProposals = () => {
) : null}
</Grid>
</TabPanel>

<TabPanel value={selectedTab} index={2}>
<Grid item xs={12} style={{ marginTop: 38, gap: 16 }}>
{activeProposals && cycleInfo && (
<ProposalsList
proposalStyle={{ marginBottom: 32 }}
currentLevel={cycleInfo.currentLevel}
proposals={activeProposals}
liteProposals={undefined}
filters={filters}
/>
)}
{!(activeProposals && activeProposals.length > 0) ? (
<ProposalsFooter item container direction="column" justifyContent="center">
<Grid item>
<Typography color="textPrimary" align="center">
No active proposals
</Typography>
</Grid>
</ProposalsFooter>
) : null}
</Grid>
</TabPanel>
</TabsBox>

<ProposalActionsDialog open={openDialog} handleClose={handleCloseModal} queryType={proposalTypeQuery || ""} />
Expand Down
Loading