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
6 changes: 5 additions & 1 deletion packages/playground/src/components/TfNavigationLoader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</template>

<script lang="ts">
import { computed, ref, type StyleValue, watch } from "vue";
import { computed, onUnmounted, ref, type StyleValue, watch } from "vue";

import { useNavigationStatus, useOnline } from "../hooks";

Expand Down Expand Up @@ -72,6 +72,10 @@ export default {
};
});

onUnmounted(() => {
clear();
});

return { loadingValue, style };
},
};
Expand Down
13 changes: 9 additions & 4 deletions packages/playground/src/components/TfOfflineNotifier.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@
</VCardText>

<VCardActions v-if="failed" class="d-flex justify-center mb-4">
<VBtn prepend-icon="mdi-reload" variant="outlined" color="secondary" @click="reload">
Reload Now
</VBtn>
<VBtn prepend-icon="mdi-reload" variant="outlined" color="secondary" @click="reload"> Reload Now </VBtn>
</VCardActions>
</VCard>
</VDialog>
</template>

<script lang="ts">
import { computed, ref, watch } from "vue";
import { computed, onUnmounted, ref, watch } from "vue";

import { useOffline } from "../hooks";

Expand Down Expand Up @@ -81,6 +79,13 @@ export default {
can reload instantly.`;
});

onUnmounted(() => {
if (interval) {
clearInterval(interval);
interval = null;
}
});

return { offline, failed, reload, dotCount, title, description };
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ import { ContractStates, type GridClient, type OverdueDetails } from "@threefold
import { type Contract, ContractState, type NodeStatus } from "@threefold/gridproxy_client";
import { TFChainError } from "@threefold/tfchain_client";
import { DeploymentKeyDeletionError } from "@threefold/types";
import { capitalize, computed, defineComponent, type PropType, type Ref, ref, watch } from "vue";
import { capitalize, computed, defineComponent, onUnmounted, type PropType, type Ref, ref, watch } from "vue";

import { useProfileManagerController } from "@/components/profile_manager_controller.vue";
import type { VDataTableHeader } from "@/types";
Expand Down Expand Up @@ -423,6 +423,7 @@ const freeBalance = computed(() => balance.value?.free ?? 0);
const unlockContractLoading = ref(false);
const unlockDialog = ref(false);
const rentContracts = ref<{ [key: number]: number }>({}); // to store the node id with its rent contract
const timeouts: ReturnType<typeof setTimeout>[] = [];
const selectedLockedContracts = computed(() => {
if (selectedContracts.value.length == 0) return false;
for (const contract of selectedContracts.value) {
Expand Down Expand Up @@ -615,7 +616,8 @@ async function unlockContract(contractId: number[]) {
`Your request to unlock contract ${contractId} has been processed successfully. Changes may take a few minutes to reflect`,
ToastType.info,
);
setTimeout(() => emits("update:unlock-contracts"), 30000);
const timeoutId = setTimeout(() => emits("update:unlock-contracts"), 30000);
timeouts.push(timeoutId);
contractStateDialog.value = false;
unlockDialog.value = false;
selectedContracts.value = [];
Expand All @@ -629,6 +631,12 @@ async function unlockContract(contractId: number[]) {
watch(contractStateDialog, contractStateDialog => {
if (!contractStateDialog) selectedItem.value = undefined;
});

onUnmounted(() => {
timeouts.forEach(timeout => clearTimeout(timeout));
timeouts.length = 0;
});

defineExpose({
reset() {
rentContracts.value = {};
Expand Down
20 changes: 8 additions & 12 deletions packages/playground/src/components/deposit_dialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
@update:model-value="closeDialog"
>
<v-card>
<VCardTitle class="bg-primary">
Deposit TFT
</VCardTitle>
<VCardTitle class="bg-primary"> Deposit TFT </VCardTitle>
<v-card-text>
<v-container>
<v-row class="py-2">
Expand All @@ -20,9 +18,7 @@
{{ selectedName ? selectedName.charAt(0).toUpperCase() + selectedName.slice(1) : "" }}
transaction.
</p>
<p class="mt-1 mb-8 text-secondary text-sm-subtitle-2 font-weight-bold">
Deposit fee is 1 TFT
</p>
<p class="mt-1 mb-8 text-secondary text-sm-subtitle-2 font-weight-bold">Deposit fee is 1 TFT</p>
</div>
<input-tooltip
v-if="selectedName == 'stellar'"
Expand Down Expand Up @@ -53,19 +49,15 @@
<v-col>
<QRPlayStore :qr="qrCodeText">
<b> OR </b>
<p class="mb-3">
Use ThreeFold Connect to scan this QRcode:
</p>
<p class="mb-3">Use ThreeFold Connect to scan this QRcode:</p>
</QRPlayStore>
</v-col>
</v-row>
</v-container>
<v-divider />
</v-card-text>
<v-card-actions class="justify-end my-1 mr-2">
<v-btn color="anchor" @click="closeDialog">
Close
</v-btn>
<v-btn color="anchor" @click="closeDialog"> Close </v-btn>
<v-btn color="secondary" :href="manual.tft_bridges" target="_blank" text="Learn more?" />
</v-card-actions>
</v-card>
Expand Down Expand Up @@ -157,6 +149,10 @@ const closeDialog = () => {

onBeforeUnmount(() => {
destroyed = true;
if (interval.value !== null) {
window.clearInterval(interval.value);
interval.value = null;
}
});
</script>
<script lang="ts">
Expand Down
10 changes: 8 additions & 2 deletions packages/playground/src/dashboard/components/node_details.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@

<script setup lang="ts">
import type { GridNode } from "@threefold/gridproxy_client";
import { onMounted, type PropType, ref } from "vue";
import { onMounted, onUnmounted, type PropType, ref } from "vue";

import { gridProxyClient } from "@/clients";
import type { NodeDetailsCard } from "@/types";
Expand Down Expand Up @@ -202,14 +202,20 @@ function loadingDots() {
dots.value += ".";
}
}

onUnmounted(() => {
if (interval.value !== null) {
window.clearInterval(interval.value);
interval.value = null;
}
});
</script>

<script lang="ts">
import CardDetails from "@/components/node_details_cards/card_details.vue";
import GPUDetailsCard from "@/components/node_details_cards/gpu_details_card.vue";

export default {

name: "NodeDetails",
components: {
CardDetails,
Expand Down
36 changes: 32 additions & 4 deletions packages/playground/src/utils/load_deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,36 @@ export async function loadVms(grid: GridClient, options: LoadVMsOptions = {}) {
}
return res;
});
let timeoutId: ReturnType<typeof setTimeout> | null = null;
const timeoutPromise = new Promise((resolve, reject) => {
setTimeout(() => {
timeoutId = setTimeout(() => {
reject(new Error("Timeout"));
}, window.env.TIMEOUT);
});

try {
const result = await Promise.race([machinePromise, timeoutPromise]);
const result = await Promise.race([
machinePromise.finally(() => {
if (timeoutId !== null) {
clearTimeout(timeoutId);
timeoutId = null;
}
}),
timeoutPromise.finally(() => {
timeoutId = null;
}),
]);
if (result instanceof Error && result.message === "Timeout") {
console.error(`Timeout loading deployment with name ${name}`);
return null;
} else {
return result;
}
} catch (e) {
if (timeoutId !== null) {
clearTimeout(timeoutId);
timeoutId = null;
}
console.error(`Failed to load deployment with name ${name}:\n${normalizeError(e, "No errors were provided.")}`);
failedDeployments.push({ name, nodes: nodeIds, contracts: contracts });
}
Expand Down Expand Up @@ -188,13 +203,26 @@ export async function loadK8s(grid: GridClient) {

return res;
});
let timeoutId: ReturnType<typeof setTimeout> | null = null;
const timeoutPromise = new Promise((resolve, reject) => {
setTimeout(() => {
timeoutId = setTimeout(() => {
reject(new Error("Timeout"));
}, window.env.TIMEOUT);
});

const result = await Promise.race([clusterPromise, timeoutPromise]);
const result = await Promise.race([
clusterPromise.finally(() => {
// Clear timeout if main promise resolves/rejects first
if (timeoutId !== null) {
clearTimeout(timeoutId);
timeoutId = null;
}
}),
timeoutPromise.finally(() => {
// Clear timeout reference when timeout promise resolves/rejects
timeoutId = null;
}),
]);
if (result instanceof Error && result.message === "Timeout") {
console.error(`Timeout loading deployment with name ${name}`);
return null;
Expand Down
23 changes: 20 additions & 3 deletions packages/playground/src/weblets/profile_manager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@
</VDialog>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from "vue";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { nextTick } from "vue";
import { useTheme } from "vuetify";

Expand Down Expand Up @@ -247,7 +247,9 @@ const profileManagerController = useProfileManagerController();
const balance = profileManagerController.balance;
const freeBalance = computed(() => balance.value?.free ?? 0);
const kyc = useKYC();
let interval: any;
let interval: ReturnType<typeof setInterval> | null = null;
const timeouts: ReturnType<typeof setTimeout>[] = [];

watch(
() => profileManager.profile,
profile => {
Expand All @@ -259,6 +261,10 @@ watch(
} else {
kyc.clear();
if (interval) clearInterval(interval);
interval = null;
// Clear all pending timeouts
timeouts.forEach(timeout => clearTimeout(timeout));
timeouts.length = 0;
balance.value = undefined;
}
},
Expand All @@ -278,6 +284,16 @@ onMounted(async () => {
await mounted();
});

onUnmounted(() => {
if (interval) {
clearInterval(interval);
interval = null;
}
// Clear all pending timeouts
timeouts.forEach(timeout => clearTimeout(timeout));
timeouts.length = 0;
});

async function handleProfileDialog(value: boolean) {
emit("update:modelValue", value);
if (profileManager?.profile && value) __loadBalance(profileManager.profile);
Expand Down Expand Up @@ -306,7 +322,8 @@ async function __loadBalance(profile?: Profile, tries = 1) {
return;
}

setTimeout(() => __loadBalance(profile, tries + 1), Math.floor(Math.exp(tries) * 1_000));
const timeoutId = setTimeout(() => __loadBalance(profile, tries + 1), Math.floor(Math.exp(tries) * 1_000));
timeouts.push(timeoutId);
}
}
profileManagerController.set({ loadBalance: __loadBalance });
Expand Down
17 changes: 13 additions & 4 deletions packages/playground/src/weblets/tf_contracts_list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@
import type { ContractsOverdue, GridClient } from "@threefold/grid_client";
import { type Contract, ContractState, NodeStatus, SortByContracts, SortOrder } from "@threefold/gridproxy_client";
import { DeploymentKeyDeletionError } from "@threefold/types";
import { computed, defineComponent, onMounted, type Ref, ref } from "vue";
import { computed, defineComponent, onMounted, onUnmounted, type Ref, ref } from "vue";

import ContractsTable from "@/components/contracts_list/contracts_table.vue";
import { useProfileManagerController } from "@/components/profile_manager_controller.vue";
Expand Down Expand Up @@ -312,6 +312,7 @@ const nodeInfo: Ref<{ [nodeId: number]: { status: NodeStatus; farmId: number } }
const unlockContractLoading = ref<boolean>(false);
const contractsTable = ref<(typeof ContractsTable)[]>([]);
const loadingLockDetails = ref(false);
const timeouts: ReturnType<typeof setTimeout>[] = [];
// Computed property to get unique node IDs from contracts
const nodeIDs = computed(() => {
return [...new Set(contracts.value.map(contract => contract.details.nodeId) || [])];
Expand All @@ -322,6 +323,11 @@ onMounted(() => {
loadContracts();
});

onUnmounted(() => {
timeouts.forEach(timeout => clearTimeout(timeout));
timeouts.length = 0;
});

async function _normalizeContracts(
contracts: Contract[],
contractType: ContractType.Node | ContractType.Name | ContractType.Rent,
Expand Down Expand Up @@ -444,10 +450,11 @@ async function unlockAllContracts() {
loadingTablesMessage.value =
"Your request to unlock your contracts has been processed successfully. Changes may take a few minutes to reflect";
createCustomToast(loadingTablesMessage.value, ToastType.info);
setTimeout(() => {
const timeoutId = setTimeout(() => {
loadContracts();
loadingTablesMessage.value = undefined;
}, 30000);
timeouts.push(timeoutId);
unlockDialog.value = false;
} catch (e) {
loadingErrorMessage.value = `Failed to unlock contract your contracts`;
Expand All @@ -472,10 +479,11 @@ async function deleteAll() {
loadingTablesMessage.value =
"The contracts have been successfully deleted. Please note that all tables will be reloaded in 30 seconds.";
createCustomToast(loadingTablesMessage.value, ToastType.info);
setTimeout(() => {
const timeoutId = setTimeout(() => {
loadContracts();
loadingTablesMessage.value = undefined;
}, 30000);
timeouts.push(timeoutId);
} catch (e) {
if (e instanceof DeploymentKeyDeletionError) {
createCustomToast("Failed to delete some keys, You don't have enough tokens", ToastType.danger);
Expand Down Expand Up @@ -544,10 +552,11 @@ async function onDeletedContracts(_contracts: NormalizedContract[]) {
loadingTablesMessage.value =
"The contracts have been successfully deleted. Please note that all tables will be reloaded in 30 seconds.";
createCustomToast(loadingTablesMessage.value, ToastType.info);
setTimeout(() => {
const timeoutId = setTimeout(() => {
loadContracts();
loadingTablesMessage.value = undefined;
}, 30000);
timeouts.push(timeoutId);
contracts.value = [...rentContracts.value, ...nameContracts.value, ...nodeContracts.value];
}
async function getContractsLockDetails() {
Expand Down