Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reserve/unreserve buttons in the actions of the nodes table #2223

Merged
merged 6 commits into from
Feb 27, 2024
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
18 changes: 15 additions & 3 deletions packages/playground/src/components/nodes_table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@
</v-chip>
</p>
</template>

<template v-slot:[`item.actions`]="{ item }">
<reserve-btn
v-if="item.columns.dedicated && item.columns.status !== 'down'"
:node="(item.raw as unknown as GridNode)"
@updateTable="$emit('reloadTable', item.raw.nodeId)"
/>
<span v-else>-</span>
</template>
</v-data-table-server>
</v-col>
</v-row>
Expand All @@ -64,12 +73,12 @@ import type { PropType } from "vue";
import { capitalize } from "vue";
import type { VDataTable } from "vuetify/labs/VDataTable";

import ReserveBtn from "@/dashboard/components/reserve_action_btn.vue";
import formatResourceSize from "@/utils/format_resource_size";
import { getNodeStatusColor, getNodeTypeColor } from "@/utils/get_nodes";
import toReadableDate from "@/utils/to_readable_data";

export default {
emits: ["update:page", "update:size", "open-dialog"],
emits: ["update:page", "update:size", "open-dialog", "reloadTable"],
props: {
size: {
required: true,
Expand All @@ -92,9 +101,11 @@ export default {
type: Boolean,
},
},
components: {
ReserveBtn,
},
setup(_, { emit }) {
const nodeStatusOptions = [NodeStatus.Up, NodeStatus.Down];

const headers: VDataTable["headers"] = [
{ title: "ID", key: "nodeId", sortable: false },
{ title: "Farm ID", key: "farmId", align: "start", sortable: false },
Expand Down Expand Up @@ -131,6 +142,7 @@ export default {
{ title: "Uptime", key: "uptime", align: "start", sortable: false, value: item => toReadableDate(item.uptime) },
{ title: "Status", key: "status", align: "start", sortable: false },
{ title: "Type", key: "dedicated", align: "start", sortable: false },
{ title: "Actions", key: "actions", align: "start", sortable: false },
];

const openSheet = (_e: any, { item }: any) => {
Expand Down
49 changes: 35 additions & 14 deletions packages/playground/src/dashboard/components/reserve_action_btn.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
:disabled="disableButton"
v-if="node.rentedByTwinId === 0"
color="primary"
@click="reserveNode"
@click.stop="reserveNode"
>
Reserve
</v-btn>
Expand All @@ -35,10 +35,19 @@
:loading="loadingUnreserveBtn"
:disabled="disableButton"
v-if="node.rentedByTwinId === profileManager.profile?.twinId"
@click="removeReserve"
@click.stop="removeReserve"
>
Unreserve
</v-btn>

<v-btn
size="small"
variant="text"
v-if="node.rentedByTwinId !== 0 && node.rentedByTwinId !== profileManager.profile?.twinId"
color="error"
>
Reserved
</v-btn>
</container>
</template>

Expand Down Expand Up @@ -112,19 +121,24 @@ export default {
}

async function reserveNode() {
loadingReserveNode.value = true;
const isLogged = profileManager.profile;
try {
const grid = await getGrid(profileManager.profile!);
createCustomToast("Transaction Submitted", ToastType.info);
await grid?.nodes.reserve({ nodeId: +props.node.nodeId });
createCustomToast(`Transaction succeeded node ${props.node.nodeId} Reserved`, ToastType.success);
notifyDelaying();
emit("updateTable");
disableButton.value = true;
setTimeout(() => {
disableButton.value = false;
loadingReserveNode.value = false;
}, 20000);
if (isLogged) {
loadingReserveNode.value = true;
const grid = await getGrid(profileManager.profile!);
createCustomToast("Transaction Submitted", ToastType.info);
await grid?.nodes.reserve({ nodeId: +props.node.nodeId });
createCustomToast(`Transaction succeeded node ${props.node.nodeId} Reserved`, ToastType.success);
notifyDelaying();
emit("updateTable");
disableButton.value = true;
setTimeout(() => {
disableButton.value = false;
loadingReserveNode.value = false;
}, 20000);
} else {
createCustomToast("Please Login first to continue.", ToastType.danger);
}
} catch (e) {
if (e instanceof InsufficientBalanceError) {
createCustomToast(`Can't create rent contract due to Insufficient balance`, ToastType.danger);
Expand All @@ -135,6 +149,7 @@ export default {
loadingReserveNode.value = false;
}
}

return {
openUnreserveDialog,
loadingUnreserveNode,
Expand All @@ -149,3 +164,9 @@ export default {
},
};
</script>

<style scoped>
.v-btn.text-error:hover > .v-btn__overlay {
opacity: 0;
}
</style>
52 changes: 45 additions & 7 deletions packages/playground/src/views/nodes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
<TfFilter
query-route="node-id"
:rules="[
validators.isNumeric('This field accepts numbers only.', { no_symbols: true }),
validators.isNumeric('This field accepts numbers only.', {
no_symbols: true,
}),
validators.min('The node id should be larger then zero.', 1),
validators.startsWith('The node id start with zero.', '0'),
validators.validateResourceMaxNumber('This is not a valid ID.'),
Expand All @@ -34,7 +36,9 @@
query-route="farm-id"
v-model="filters.farmId"
:rules="[
validators.isNumeric('This field accepts numbers only.', { no_symbols: true }),
validators.isNumeric('This field accepts numbers only.', {
no_symbols: true,
}),
validators.min('The ID should be larger than zero.', 1),
validators.isInt('should be an integer'),
validators.validateResourceMaxNumber('This is not a valid ID.'),
Expand Down Expand Up @@ -243,7 +247,9 @@
<TfFilter
query-route="free-public-ips"
:rules="[
validators.isNumeric('This field accepts numbers only.', { no_symbols: true }),
validators.isNumeric('This field accepts numbers only.', {
no_symbols: true,
}),
validators.min('The node id should be larger then zero.', 1),
validators.startsWith('The node id start with zero.', '0'),
validators.validateResourceMaxNumber('This value is out of range.'),
Expand Down Expand Up @@ -288,6 +294,10 @@
<TfFilter query-route="gpu" v-model="filters.gpu">
<v-switch color="primary" inset label="GPU Node (Only)" v-model="filters.gpu" hide-details />
</TfFilter>

<TfFilter query-route="dedicated" v-model="filters.dedicated">
<v-switch color="primary" inset label="Dedicated Nodes (Only)" v-model="filters.dedicated" hide-details />
</TfFilter>
</TfFiltersContainer>

<div class="nodes mt-5">
Expand All @@ -307,6 +317,7 @@
page = $event;
loadNodes();
"
@reload-table="reloadTable"
:count="nodesCount"
:loading="loading"
v-model:selectedNode="selectedNodeId"
Expand Down Expand Up @@ -357,14 +368,14 @@ import { useRoute } from "vue-router";
import NodeDetails from "@/components/node_details.vue";
import NodesTable from "@/components/nodes_table.vue";
import router from "@/router";
import { requestNodes } from "@/utils/get_nodes";
import type { GridProxyRequestConfig } from "@/types";
import { getNode, requestNodes } from "@/utils/get_nodes";
import { convertToBytes } from "@/utils/get_nodes";

import TfFilter from "../components/filters/TfFilter.vue";
import TfFiltersContainer from "../components/filters/TfFiltersContainer.vue";
import TfSelectFarm from "../components/node_selector/TfSelectFarm.vue";
import TfSelectLocation from "../components/node_selector/TfSelectLocation.vue";

export default {
components: {
NodesTable,
Expand All @@ -377,7 +388,7 @@ export default {
setup() {
const size = ref(window.env.PAGE_SIZE);
const page = ref(1);

const nodeId = ref<number>(0);
const filters = ref({
nodeId: "",
farmId: "",
Expand All @@ -395,6 +406,7 @@ export default {
gateway: false,
gpu: false,
publicIPs: "",
dedicated: false,
});

const loading = ref<boolean>(true);
Expand All @@ -406,6 +418,13 @@ export default {

const route = useRoute();

const nodeOptions: GridProxyRequestConfig = {
loadTwin: true,
loadFarm: true,
loadStats: true,
loadGpu: false,
};

async function loadNodes() {
loading.value = true;
try {
Expand All @@ -430,6 +449,7 @@ export default {
hasGpu: filters.value.gpu || undefined,
domain: filters.value.gateway || undefined,
freeIps: +filters.value.publicIPs || undefined,
dedicated: filters.value.dedicated || undefined,
},
{ loadFarm: true },
);
Expand All @@ -442,6 +462,19 @@ export default {
}
}

async function requestNode() {
loading.value = true;
try {
const node = await getNode(nodeId.value, nodeOptions);
const index = nodes.value.findIndex(node => node.nodeId === nodeId.value);
nodes.value[index] = node;
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
}

const checkSelectedNode = async () => {
if (route.query.nodeId) {
selectedNodeId.value = +route.query.nodeId;
Expand All @@ -466,6 +499,11 @@ export default {
isDialogOpened.value = true;
};

function reloadTable(id: number) {
nodeId.value = id;
setTimeout(requestNode, 20000);
}

return {
loading,
nodesCount,
Expand All @@ -475,7 +513,7 @@ export default {
closeDialog,
requestNodes,
isDialogOpened,

reloadTable,
filters,
NodeStatus,
size,
Expand Down
Loading