Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/snapshot-labs/sx-monorepo
Browse files Browse the repository at this point in the history
…into fix-voting-power-check
  • Loading branch information
ChaituVR committed Jan 8, 2025
2 parents c808a9d + dc4c0c4 commit 6e25fdc
Show file tree
Hide file tree
Showing 15 changed files with 395 additions and 208 deletions.
2 changes: 1 addition & 1 deletion apps/ui/src/components/EditorTimeline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function formatVotingDuration(
:data="
isOffchainSpace || !editable
? {
...space,
network: space.network,
created,
start,
min_end,
Expand Down
5 changes: 5 additions & 0 deletions apps/ui/src/components/Modal/SelectValidation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ function handleSelect(validationDetails: ValidationDetails) {
form.value.scoreThreshold ??= 0;
form.value.operator ??= 'NONE';
form.value.stamps ??= [];
// Remove unsupported options
form.value.stamps = definition.value.properties.stamps.options
.filter(option => form.value.stamps.includes(option.id))
.map(option => option.id);
}
}
Expand Down
29 changes: 29 additions & 0 deletions apps/ui/src/components/ProposalResults.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
quorumProgress
} from '@/helpers/quorum';
import { _n, _p, _vp } from '@/helpers/utils';
import { getNetwork, offchainNetworks } from '@/networks';
import { Proposal as ProposalType } from '@/types';
const DEFAULT_MAX_CHOICES = 6;
Expand All @@ -26,6 +27,8 @@ const props = withDefaults(
}
);
const proposalsStore = useProposalsStore();
const displayAllChoices = ref(false);
const totalProgress = computed(() => quorumProgress(props.proposal));
Expand Down Expand Up @@ -94,6 +97,32 @@ const isFinalizing = computed(() => {
['passed', 'executed', 'rejected'].includes(props.proposal.state)
);
});
async function refreshScores() {
try {
const network = getNetwork(props.proposal.network);
const hubUrl = network.api.apiUrl.replace('/graphql', '');
const response = await fetch(`${hubUrl}/api/scores/${props.proposal.id}`);
const result = await response.json();
if (result.result === true) {
proposalsStore.reset(props.proposal.space.id, props.proposal.network);
await proposalsStore.fetchProposal(
props.proposal.space.id,
props.proposal.id,
props.proposal.network
);
}
} catch (e) {
console.warn('Failed to refresh scores', e);
}
}
onMounted(() => {
if (offchainNetworks.includes(props.proposal.network) && isFinalizing.value) {
refreshScores();
}
});
</script>

<template>
Expand Down
10 changes: 8 additions & 2 deletions apps/ui/src/components/ProposalTimeline.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { _t } from '@/helpers/utils';
import { Proposal, Space } from '@/types';
import { NetworkID, Proposal, Space } from '@/types';
type ProposalTimelineValues = {
created?: number;
Expand All @@ -9,12 +9,18 @@ type ProposalTimelineValues = {
max_end: number;
};
type ProposalTimelineInput = {
network: NetworkID;
} & ProposalTimelineValues;
type State = {
id: keyof typeof LABELS;
value: number;
};
const props = defineProps<{ data: Proposal | Space }>();
const props = defineProps<{
data: Proposal | Space | ProposalTimelineInput;
}>();
const LABELS = {
created: 'Created',
Expand Down
110 changes: 110 additions & 0 deletions apps/ui/src/components/Ui/ResizableHorizontal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<script lang="ts" setup>
import { lsGet, lsSet } from '@/helpers/utils';
const CACHE_KEY_SUFFIX = 'width';
const props = defineProps<{
id: string;
default: number;
max?: number;
min?: number;
}>();
const containerEl = ref<HTMLElement | null>(null);
const sliderEl = ref<HTMLElement | null>(null);
const initialized = ref(false);
const dragging = ref(false);
const width = ref(lsGet(`${props.id}.${CACHE_KEY_SUFFIX}`, props.default));
const sliderOutOfBound = ref(false);
const skipNextDragTick = ref(false);
const { x, y } = useDraggable(sliderEl, {
axis: 'x',
onStart: () => {
dragging.value = true;
},
onEnd: () => {
dragging.value = false;
if (sliderOutOfBound) {
skipNextDragTick.value = true;
}
}
});
function getNewWidth(width: number, delta: number) {
const newWidth = Math.round(width - delta);
if (props.max && newWidth >= props.max) {
sliderOutOfBound.value = true;
return props.max;
}
if (props.min && newWidth <= props.min) {
sliderOutOfBound.value = true;
return props.min;
}
sliderOutOfBound.value = false;
return newWidth;
}
function initResizer() {
if (!sliderEl.value || !containerEl.value) return;
const position = sliderEl.value.getBoundingClientRect();
x.value = position.x;
y.value = position.y;
initialized.value = true;
}
watch(x, (newX, oldX) => {
if (!initialized.value || !dragging.value) return;
// useDraggable composable is not clamping x between min and max when given
// The following check will ignore the first x changes, when it's out of bound
if (skipNextDragTick.value) {
skipNextDragTick.value = false;
sliderOutOfBound.value = false;
return;
}
width.value = getNewWidth(width.value, newX - oldX);
lsSet(`${props.id}.${CACHE_KEY_SUFFIX}`, width.value);
});
onMounted(() => {
initResizer();
});
</script>

<template>
<div
ref="containerEl"
class="relative max-md:!w-full"
:style="{ width: `${width}px` }"
>
<div
ref="sliderEl"
:class="[
'slider',
{
dragging: dragging
}
]"
/>
<slot />
</div>
</template>

<style lang="scss" scoped>
.slider {
$sliderSize: 6px;
@apply hidden md:block absolute h-full z-10 select-none left-[-#{calc($sliderSize / 2)}] w-[#{$sliderSize}];
&:hover,
&.dragging {
@apply bg-skin-border cursor-col-resize;
}
}
</style>
35 changes: 29 additions & 6 deletions apps/ui/src/composables/useEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ const processedProposals = Object.fromEntries(
);

const proposals = reactive<Drafts>(processedProposals as Drafts);
const spaceVoteType = reactive(new Map<string, VoteType>());
const spaceVoteType = new Map<string, VoteType>();
const spaceTemplate = new Map<string, string>();

function generateId() {
return (Math.random() + 1).toString(36).substring(7);
Expand All @@ -38,6 +39,8 @@ function getSpaceId(draftId: string) {
}

export function useEditor() {
const spacesStore = useSpacesStore();

const drafts = computed(() => {
return Object.entries(removeEmpty(proposals))
.map(([k, value]) => {
Expand All @@ -56,11 +59,13 @@ export function useEditor() {

function removeEmpty(proposals: Drafts): Drafts {
return Object.entries(proposals).reduce((acc, [id, proposal]) => {
const { executions, type, choices, labels, ...rest } = omit(proposal, [
'updatedAt'
]);
const { executions, type, body, choices, labels, ...rest } = omit(
proposal,
['updatedAt']
);
const hasFormValues = Object.values(rest).some(val => !!val);
const hasChangedVotingType = type !== spaceVoteType.get(getSpaceId(id));
const hasChangedBody = body !== spaceTemplate.get(getSpaceId(id));
const hasFormChoices =
type !== 'basic' && (choices || []).some(val => !!val);

Expand All @@ -69,6 +74,7 @@ export function useEditor() {
labels.length === 0 &&
!hasFormValues &&
!hasChangedVotingType &&
!hasChangedBody &&
!hasFormChoices
) {
return acc;
Expand All @@ -85,8 +91,23 @@ export function useEditor() {
}, {});
}

async function getInitialProposalBody(spaceId: string) {
if (spaceTemplate.has(spaceId)) {
return spaceTemplate.get(spaceId) as string;
}

if (!spacesStore.spacesMap.has(spaceId)) {
await spacesStore.fetchSpaces([spaceId]);
}

const template = spacesStore.spacesMap.get(spaceId)?.template ?? '';

spaceTemplate.set(spaceId, template);

return template;
}

async function setSpacesVoteType(spaceIds: string[]) {
const spacesStore = useSpacesStore();
const newIds = spaceIds.filter(id => !spaceVoteType.has(id));

if (!newIds.length) return;
Expand Down Expand Up @@ -122,9 +143,11 @@ export function useEditor() {
const id = draftKey ?? generateId();
const key = `${spaceId}:${id}`;

const body = await getInitialProposalBody(spaceId);

proposals[key] = {
title: '',
body: '',
body,
discussion: '',
type,
choices,
Expand Down
10 changes: 4 additions & 6 deletions apps/ui/src/composables/useSpaceSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,8 +702,8 @@ export function useSpaceSettings(space: Ref<Space>) {

if (offchainNetworks.includes(space.value.network)) {
proposalValidation.value = getInitialProposalValidation(space.value);
guidelines.value = space.value.additionalRawData?.guidelines ?? '';
template.value = space.value.additionalRawData?.template ?? '';
guidelines.value = space.value.guidelines ?? '';
template.value = space.value.template ?? '';

const initialVotingProperties = getInitialVotingProperties(space.value);
quorumType.value = initialVotingProperties.quorumType;
Expand Down Expand Up @@ -816,14 +816,12 @@ export function useSpaceSettings(space: Ref<Space>) {
return;
}

if (
guidelinesValue !== (space.value.additionalRawData?.guidelines ?? '')
) {
if (guidelinesValue !== (space.value.guidelines ?? '')) {
isModified.value = true;
return;
}

if (templateValue !== (space.value.additionalRawData?.template ?? '')) {
if (templateValue !== (space.value.template ?? '')) {
isModified.value = true;
return;
}
Expand Down
12 changes: 3 additions & 9 deletions apps/ui/src/helpers/etherscan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,17 @@ import { call } from './call';
import { getProvider } from './provider';

export async function getABI(chainId: number, address: string) {
let apiHost: string;
if (chainId === 1) apiHost = 'https://api.etherscan.io';
else if (chainId === 10) apiHost = 'https://api-optimistic.etherscan.io';
else if (chainId === 137) apiHost = 'https://api.polygonscan.com';
else if (chainId === 8453) apiHost = 'https://api.basescan.org';
else if (chainId === 42161) apiHost = 'https://api.arbiscan.io';
else if (chainId === 11155111) apiHost = 'https://api-sepolia.etherscan.io';
else throw new Error('Unsupported chainId');
const apiHost = `https://api.etherscan.io/v2/api`;

const params = new URLSearchParams({
chainid: chainId.toString(),
module: 'contract',
action: 'getAbi',
address,
apikey: import.meta.env.VITE_ETHERSCAN_API_KEY || ''
});

const res = await fetch(`${apiHost}/api?${params}`);
const res = await fetch(`${apiHost}?${params}`);
const { result } = await res.json();
const abi = JSON.parse(result);

Expand Down
4 changes: 3 additions & 1 deletion apps/ui/src/networks/common/graphqlApi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ function formatSpace(
space.strategies_indices
),
children: [],
parent: null
parent: null,
template: null,
guidelines: null
};
}

Expand Down
4 changes: 2 additions & 2 deletions apps/ui/src/networks/offchain/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ function formatSpace(
private: space.private,
domain: space.domain,
skin: space.skin,
guidelines: space.guidelines,
template: space.template,
strategies: space.strategies,
categories: space.categories,
admins: space.admins,
Expand Down Expand Up @@ -212,6 +210,8 @@ function formatSpace(
children: space.children.map(formatRelatedSpace),
parent: space.parent ? formatRelatedSpace(space.parent) : null,
terms: space.terms,
guidelines: space.guidelines,
template: space.template,
additionalRawData
};
}
Expand Down
Loading

0 comments on commit 6e25fdc

Please sign in to comment.