Skip to content

Commit

Permalink
feat: Polish UX for unrecoverable exceptions (#87)
Browse files Browse the repository at this point in the history
* feat: Add error popup

* chore: catch top-level exceptions
  • Loading branch information
clockworkgr authored May 2, 2024
1 parent 9e6d6e4 commit 676e664
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 76 deletions.
2 changes: 2 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { RouterView } from "vue-router";
import HeaderSection from "@/components/layout/HeaderSection.vue";
import ErrorBox from "@/components/popups/ErrorBox.vue";
import FooterSection from "@/components/layout/FooterSection.vue";
import { useGithubDiscussions } from "@/composables/useGithubDiscussions";
Expand All @@ -13,6 +14,7 @@ useGithubDiscussions().setup();
<div class="w-full max-w-[90rem] px-6 md:px-14 lg:px-20 mx-auto">
<HeaderSection />
<div class="flex flex-col w-full min-h-screen">
<ErrorBox />
<router-view v-slot="{ Component }">
<Transition name="page" mode="out-in">
<component :is="Component" />
Expand Down
21 changes: 13 additions & 8 deletions src/components/common/MarkdownParser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import MarkdownItMermaid from "@agoose77/markdown-it-mermaid";
import { alertPlugin } from "markdown-it-github-alert";
import DOMPurify from "dompurify";
import { bus } from "@/bus";
const md = markdownit({
html: true,
Expand All @@ -19,15 +20,19 @@ const content = defineModel<string>();
const trimmedContent = ref<string>("");
async function parseData() {
if (!content.value) {
return "";
try {
if (!content.value) {
return "";
}
const htmlContent = props.limit
? await md.render(content.value.slice(0, props.limit))
: await md.render(content.value);
trimmedContent.value = DOMPurify.sanitize(htmlContent);
} catch (_e) {
bus.emit("error");
}
const htmlContent = props.limit
? await md.render(content.value.slice(0, props.limit))
: await md.render(content.value);
trimmedContent.value = DOMPurify.sanitize(htmlContent);
}
const getClasses = computed(() => {
Expand Down
9 changes: 7 additions & 2 deletions src/components/home/CommentCount.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts" setup>
import { bus } from "@/bus";
import { useGithubDiscussions } from "@/composables/useGithubDiscussions";
import { onMounted, ref } from "vue";
Expand All @@ -7,8 +8,12 @@ const count = ref(0);
const { getDiscussionCommentCount } = useGithubDiscussions();
onMounted(async () => {
const response = await getDiscussionCommentCount({ term: `Proposal #${props.proposal}` });
count.value = response.count;
try {
const response = await getDiscussionCommentCount({ term: `Proposal #${props.proposal}` });
count.value = response.count;
} catch (_e) {
bus.emit("error");
}
});
</script>

Expand Down
50 changes: 50 additions & 0 deletions src/components/popups/ErrorBox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script setup lang="ts">
import { ref } from "vue";
import { bus } from "@/bus";
import ModalWrap from "@/components/common/ModalWrap.vue";
const isOpen = ref(false);
const refresh = () => {
window.location.reload();
};
bus.on("error", () => {
isOpen.value = true;
});
</script>

<template>
<div class="relative">
<ModalWrap :visible="isOpen" :is-empty="true" @back="isOpen = false">
<div class="bg-grey-400 w-full rounded-md max-h-screen overflow-auto">
<div class="px-10 py-12 bg-grey-400 rounded w-screen max-w-[25rem]">
<div class="flex flex-col gap-6 relative">
<span class="text-gradient font-termina text-700 text-center">{{ $t("components.ErrorBox.title") }}</span>
<div class="flex flex-col gap-10">
<div>
<div class="flex flex-col gap-10">
<p class="text-grey-100 text-center text-200">
{{ $t("components.ErrorBox.message") }}
</p>
</div>
</div>

<div class="flex flex-col gap-4">
<div class="flex flex-col gap-4">
<button
class="px-6 py-4 rounded text-light text-300 text-center bg-grey-200 w-full hover:opacity-50 duration-150 ease-in-out"
@click="refresh()"
>
{{ $t("components.ErrorBox.cta") }}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</ModalWrap>
</div>
</template>
39 changes: 22 additions & 17 deletions src/components/proposals/ProposalWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,30 @@ const validatorsWithStakeAndVotes = ref<
>([]);
watch(validators, async (valSet, _old) => {
validatorsWithStakeAndVotes.value = await Promise.all(
valSet.map(async (val) => {
if (val.validator.validator_info && val.validator.validator_info.self_delegate_address) {
const vp = await getVotingPower(val.validator.validator_info.self_delegate_address);
const votes = await getVotesAsync(val.validator.validator_info.self_delegate_address, props.proposalId);
if (votes && votes.proposal_vote.length > 0) {
return {
...val,
voting_power: vp,
votes: votes.proposal_vote.filter((x) => x.height == votes.proposal_vote[0].height),
};
try {
validatorsWithStakeAndVotes.value = await Promise.all(
valSet.map(async (val) => {
if (val.validator.validator_info && val.validator.validator_info.self_delegate_address) {
const vp = await getVotingPower(val.validator.validator_info.self_delegate_address);
const votes = await getVotesAsync(val.validator.validator_info.self_delegate_address, props.proposalId);
if (votes && votes.proposal_vote.length > 0) {
return {
...val,
voting_power: vp,
votes: votes.proposal_vote.filter((x) => x.height == votes.proposal_vote[0].height),
};
} else {
return { ...val, voting_power: vp, votes: [] };
}
} else {
return { ...val, voting_power: vp, votes: [] };
return { ...val, voting_power: 0, votes: [] };
}
} else {
return { ...val, voting_power: 0, votes: [] };
}
}),
);
}),
);
} catch (_e) {
bus.emit("error");
1;
}
});
const maxValidators = computed(() => {
Expand Down
5 changes: 5 additions & 0 deletions src/localization/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export const messages = {
},
},
components: {
ErrorBox: {
title: "Error",
message: "Something went wrong...",
cta: "Please refresh",
},
WalletConnect: {
button: "Connect Wallet",
cta: "Connect your wallet",
Expand Down
102 changes: 59 additions & 43 deletions src/views/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import apolloClient from "@/apolloClient";
import { useChainData } from "@/composables/useChainData";
import { useTelemetry } from "@/composables/useTelemetry";
import { bus } from "@/bus";
const typeFilterIndex = ref(0);
const activityFilterIndex = ref(0);
Expand Down Expand Up @@ -63,46 +64,57 @@ const filterToStatus = computed(() => {
watch(filterToStatus, async (newType, oldType) => {
if (newType !== oldType) {
provideApolloClient(apolloClient);
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
offset.value,
newType ?? undefined,
searchString.value,
);
if (res) {
proposals.value = res;
try {
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
offset.value,
newType ?? undefined,
searchString.value,
);
if (res) {
proposals.value = res;
}
} catch (_e) {
bus.emit("error");
}
}
});
watch(searchString, async (newSearch, oldSearch) => {
if (newSearch !== oldSearch) {
provideApolloClient(apolloClient);
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
offset.value,
filterToStatus.value ?? undefined,
searchString.value,
);
if (res) {
proposals.value = res;
try {
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
offset.value,
filterToStatus.value ?? undefined,
searchString.value,
);
if (res) {
proposals.value = res;
}
} catch (_e) {
bus.emit("error");
}
}
});
watch(sortToOrder, async (newOrder, oldOrder) => {
if (newOrder !== oldOrder) {
provideApolloClient(apolloClient);
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
offset.value,
filterToStatus.value ?? undefined,
searchString.value,
);
if (res) {
proposals.value = res;
try {
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
offset.value,
filterToStatus.value ?? undefined,
searchString.value,
);
if (res) {
proposals.value = res;
}
} catch (_e) {
bus.emit("error");
}
}
});
Expand All @@ -128,22 +140,26 @@ function prev() {
watch(offset, async (newOffset, oldOffset) => {
if (newOffset != oldOffset) {
provideApolloClient(apolloClient);
if (filterToStatus.value != null) {
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
newOffset,
filterToStatus.value,
searchString.value,
);
if (res) {
proposals.value = res;
}
} else {
const res = await getProposalsAsync(sortToOrder.value, limit.value, newOffset, undefined, searchString.value);
if (res) {
proposals.value = res;
try {
if (filterToStatus.value != null) {
const res = await getProposalsAsync(
sortToOrder.value,
limit.value,
newOffset,
filterToStatus.value,
searchString.value,
);
if (res) {
proposals.value = res;
}
} else {
const res = await getProposalsAsync(sortToOrder.value, limit.value, newOffset, undefined, searchString.value);
if (res) {
proposals.value = res;
}
}
} catch (_e) {
bus.emit("error");
}
}
});
Expand Down
16 changes: 10 additions & 6 deletions src/views/ProposalView.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import ProposalWrapper from "@/components/proposals/ProposalWrapper.vue";
import { bus } from "@/bus";
import { useRoute } from "vue-router";
import { useChainData } from "@/composables/useChainData";
import { ref, watch } from "vue";
Expand All @@ -24,12 +25,15 @@ watch(proposal, async (newProp, _oldProp) => {
proposal.value?.proposal[0].status == "PROPSOAL_STATUS_REJECTED"
) {
provideApolloClient(apolloClient);
const hq = await getBlockHeightAsync(proposal.value.proposal[0].voting_end_time);
console.log("here");
if (hq) {
height.value = hq.block[0].height;
} else {
height.value = 0;
try {
const hq = await getBlockHeightAsync(proposal.value.proposal[0].voting_end_time);
if (hq) {
height.value = hq.block[0].height;
} else {
height.value = 0;
}
} catch (e) {
bus.emit("error");
}
} else {
height.value = 0;
Expand Down

0 comments on commit 676e664

Please sign in to comment.