Too expensive? can upgrade to Gold package to get discount up to 60% when you fund your
wallet with {{ sharedUpgradePrice }} TFT
diff --git a/packages/playground/src/components/algorand_capacity.vue b/packages/playground/src/components/algorand_capacity.vue
index 078104d4c7..ad5b69a76b 100644
--- a/packages/playground/src/components/algorand_capacity.vue
+++ b/packages/playground/src/components/algorand_capacity.vue
@@ -66,6 +66,14 @@
/>
+
+
+ Please check the required
+
+ hardware requirements
+
+ before deciding to deploy a new Algorand instance.
+
@@ -88,8 +96,8 @@ const storageInput = ref();
const custom = ref(false);
-const cpu = ref(2);
-const memory = ref(4096);
+const cpu = ref(8);
+const memory = ref(16384);
const storage = ref(100);
watch(cpu, cpu => emits("update:cpu", cpu), { immediate: true });
diff --git a/packages/playground/src/components/contracts_list/contracts_table.vue b/packages/playground/src/components/contracts_list/contracts_table.vue
index d1f341bd56..322f301645 100644
--- a/packages/playground/src/components/contracts_list/contracts_table.vue
+++ b/packages/playground/src/components/contracts_list/contracts_table.vue
@@ -25,6 +25,7 @@
show-select
@update:page="updatePage"
@update:items-per-page="updateSize"
+ @update:sort-by="updateSortBy"
>
{{ item.details.nodeId }}
@@ -41,7 +42,7 @@
No Data Available
-
+
{{ item.details.farm_id ? item.details.farm_id : "-" }}
@@ -352,7 +353,13 @@ const isNodeInRentContracts = computed(() => {
return false;
});
-const emits = defineEmits(["update:deleted-contracts", "update:unlock-contracts", "update:page", "update:size"]);
+const emits = defineEmits([
+ "update:deleted-contracts",
+ "update:unlock-contracts",
+ "update:page",
+ "update:size",
+ "update:sort",
+]);
function updatePage(page: number) {
emits("update:page", page);
@@ -362,6 +369,10 @@ function updateSize(size: number) {
emits("update:size", size);
}
+function updateSortBy(sort: { key: string; order: "asc" | "desc" }[]) {
+ emits("update:sort", sort);
+}
+
const layout = ref();
const contractLocked = ref();
const deleting = ref(false);
diff --git a/packages/playground/src/components/filters/TfFiltersContainer.vue b/packages/playground/src/components/filters/TfFiltersContainer.vue
index 2cfaa426ab..1f1e512849 100644
--- a/packages/playground/src/components/filters/TfFiltersContainer.vue
+++ b/packages/playground/src/components/filters/TfFiltersContainer.vue
@@ -179,8 +179,15 @@ export default {
collapsible.value = breakpoint > window.innerWidth;
}
+ function onEnterApply(e: KeyboardEvent) {
+ if (e.keyCode == 13 && valid.value && changed.value) apply();
+ }
+
onMounted(() => typeof breakpoint === "number" && window.addEventListener("resize", onResize));
+ onMounted(() => window.addEventListener("keyup", onEnterApply));
onUnmounted(() => typeof breakpoint === "number" && window.removeEventListener("resize", onResize));
+ onUnmounted(() => window.removeEventListener("keyup", onEnterApply));
+
typeof breakpoint === "number" && onResize();
return { empty, changed, clear, apply, valid, collapsible, filterOpened };
diff --git a/packages/playground/src/components/node_selector/TfNodeDetailsCard.vue b/packages/playground/src/components/node_selector/TfNodeDetailsCard.vue
index ac4843653c..16be9cd3e8 100644
--- a/packages/playground/src/components/node_selector/TfNodeDetailsCard.vue
+++ b/packages/playground/src/components/node_selector/TfNodeDetailsCard.vue
@@ -52,7 +52,7 @@
-
+
@@ -455,7 +455,7 @@ export default {
}
async function getLastDeploymentTime() {
- if (props.node?.id) {
+ if (props.node?.id && props.node?.status == "up") {
try {
const obj = await gridProxyClient.nodes.statsById(props.node.nodeId);
lastDeploymentTime.value = obj.users.last_deployment_timestamp;
diff --git a/packages/playground/src/components/node_selector/TfSelectGpu.vue b/packages/playground/src/components/node_selector/TfSelectGpu.vue
index 7a7964ac12..136d4d39a1 100644
--- a/packages/playground/src/components/node_selector/TfSelectGpu.vue
+++ b/packages/playground/src/components/node_selector/TfSelectGpu.vue
@@ -1,4 +1,5 @@
+ Choose a GPU card to deploy your VM.
- SSH keys management page
and add more as needed.
-
-
-
-
-
- Manage SSH keys
-
-
-
-
-
-
-
-
- mdi-cog-sync
- Manage SSH keys
-
-
-
-
+
To change the key that you want to use over the deployment, simply click on it.
-
+
+
-
-
-
-
-
+
-
-
-
-
+
diff --git a/packages/playground/src/views/solutions_view.vue b/packages/playground/src/views/solutions_view.vue
index fa6b72ddcd..0bab5d14d8 100644
--- a/packages/playground/src/views/solutions_view.vue
+++ b/packages/playground/src/views/solutions_view.vue
@@ -55,6 +55,13 @@ export default {
name: "SolutionsView",
setup() {
let cards: Card[] = [
+ {
+ title: "Nostr",
+ excerpt:
+ "Nostr is a simple, open protocol that enables global, decentralized, and censorship-resistant social media.",
+ icon: "nostr.png",
+ route: DashboardRoutes.Applications.Nostr,
+ },
{
title: "TFRobot",
excerpt:
diff --git a/packages/playground/src/weblets/profile_manager.vue b/packages/playground/src/weblets/profile_manager.vue
index 5acece2b69..2c36454672 100644
--- a/packages/playground/src/weblets/profile_manager.vue
+++ b/packages/playground/src/weblets/profile_manager.vue
@@ -153,6 +153,7 @@
}"
:disabled="creatingAccount || activatingAccount || activating"
@click:append="reloadValidation"
+ autocomplete="off"
>
@@ -257,6 +258,7 @@
v-model="email"
v-bind="props"
:disabled="creatingAccount || activatingAccount || activating"
+ autocomplete="off"
/>
@@ -283,6 +285,7 @@
v-model="password"
v-bind="{ ...passwordInputProps, ...validationProps }"
:disabled="creatingAccount || activatingAccount || activating"
+ autocomplete="off"
/>
@@ -305,6 +308,7 @@
...validationProps,
}"
:disabled="creatingAccount || activatingAccount || activating"
+ autocomplete="off"
/>
diff --git a/packages/playground/src/weblets/tf_algorand.vue b/packages/playground/src/weblets/tf_algorand.vue
index 3f0cf97b2f..50440698b0 100644
--- a/packages/playground/src/weblets/tf_algorand.vue
+++ b/packages/playground/src/weblets/tf_algorand.vue
@@ -28,9 +28,7 @@
-
-
-
+
;
const memory = ref() as Ref;
@@ -173,7 +172,7 @@ async function deploy() {
rootFilesystemSize: rootFilesystemSize.value,
publicIpv4: ipv4.value,
mycelium: mycelium.value,
- planetary: true,
+ planetary: planetary.value,
nodeId: selectionDetails.value!.node!.nodeId,
rentedBy: dedicated.value ? grid!.twinId : undefined,
certified: certified.value,
diff --git a/packages/playground/src/weblets/tf_casperlabs.vue b/packages/playground/src/weblets/tf_casperlabs.vue
index ad4d996449..bedba6134c 100644
--- a/packages/playground/src/weblets/tf_casperlabs.vue
+++ b/packages/playground/src/weblets/tf_casperlabs.vue
@@ -37,7 +37,7 @@
:large="{ cpu: 8, memory: 32, disk: 1000 }"
/>
-
+
@@ -98,6 +98,7 @@ const dedicated = ref(false);
const certified = ref(false);
const ipv4 = ref(false);
const mycelium = ref(true);
+const planetary = ref(false);
const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0));
const selectionDetails = ref();
const selectedSSHKeys = ref("");
@@ -149,6 +150,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
mycelium: mycelium.value,
+ planetary: planetary.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
{ key: "CASPERLABS_HOSTNAME", value: domain },
diff --git a/packages/playground/src/weblets/tf_contracts_list.vue b/packages/playground/src/weblets/tf_contracts_list.vue
index 5f5ba69110..71755c58b5 100644
--- a/packages/playground/src/weblets/tf_contracts_list.vue
+++ b/packages/playground/src/weblets/tf_contracts_list.vue
@@ -170,6 +170,11 @@
loadContracts(table.type);
}
"
+ @update:sort="
+ sort => {
+ loadContracts(table.type, { sort });
+ }
+ "
/>
@@ -256,6 +261,7 @@ async function _normalizeContracts(
async function loadContractsByType(
contractType: ContractType.Node | ContractType.Name | ContractType.Rent,
contractsRef: Ref,
+ options?: { sort: { key: string; order: "asc" | "desc" }[] },
) {
const table = contractsTables.find(table => table.type === contractType);
if (!table) {
@@ -276,6 +282,11 @@ async function loadContractsByType(
table.count.value = response.count ?? 0;
const normalizedContracts = await _normalizeContracts(response.data, contractType);
+
+ if (options && options.sort.length) {
+ contractsRef.value = sortContracts(normalizedContracts, options.sort);
+ }
+
contractsRef.value = normalizedContracts;
} catch (error: any) {
loadingErrorMessage.value = `Error while listing ${contractType} contracts: ${error.message}`;
@@ -285,7 +296,22 @@ async function loadContractsByType(
}
}
-async function loadContracts(type?: ContractType) {
+function sortContracts(
+ contracts: NormalizedContract[],
+ sort: { key: string; order: "asc" | "desc" }[],
+): NormalizedContract[] {
+ const sortKey = sort[0].key;
+ const sortOrder = sort[0].order;
+
+ contracts = contracts.sort((a, b) => {
+ const aValue = Reflect.get(a, sortKey) ?? Reflect.get(a.details, sortKey);
+ const bValue = Reflect.get(b, sortKey) ?? Reflect.get(b.details, sortKey);
+ return sortOrder === "desc" ? bValue - aValue : aValue - bValue;
+ });
+ return contracts;
+}
+
+async function loadContracts(type?: ContractType, options?: { sort: { key: string; order: "asc" | "desc" }[] }) {
totalCost.value = undefined;
totalCostUSD.value = undefined;
loadingErrorMessage.value = undefined;
@@ -298,20 +324,20 @@ async function loadContracts(type?: ContractType) {
if (type) {
switch (type) {
case ContractType.Name:
- await loadContractsByType(ContractType.Name, nameContracts);
+ await loadContractsByType(ContractType.Name, nameContracts, options);
break;
case ContractType.Node:
- await loadContractsByType(ContractType.Node, nodeContracts);
+ await loadContractsByType(ContractType.Node, nodeContracts, options);
break;
case ContractType.Rent:
- await loadContractsByType(ContractType.Rent, rentContracts);
+ await loadContractsByType(ContractType.Rent, rentContracts, options);
break;
}
} else {
await Promise.all([
- loadContractsByType(ContractType.Name, nameContracts),
- loadContractsByType(ContractType.Node, nodeContracts),
- loadContractsByType(ContractType.Rent, rentContracts),
+ loadContractsByType(ContractType.Name, nameContracts, options),
+ loadContractsByType(ContractType.Node, nodeContracts, options),
+ loadContractsByType(ContractType.Rent, rentContracts, options),
]);
}
await getContractsLockDetails();
@@ -437,7 +463,7 @@ const nodeTableHeaders: VDataTableHeader = [
},
{ title: "Type", key: "deploymentType", sortable: false },
{ title: "Expiration", key: "expiration" },
- { title: "Farm ID", key: "farmId" },
+ { title: "Farm ID", key: "farm_id" },
{
title: "Node",
key: "node",
@@ -452,14 +478,14 @@ const nodeTableHeaders: VDataTableHeader = [
const nameTableHeaders: VDataTableHeader = [
...baseTableHeaders,
- { title: "Solution Name", key: "solutionName" },
+ { title: "Solution Name", key: "solutionName", sortable: false },
{ title: "Expiration", key: "expiration" },
{ title: "Details", key: "actions", sortable: false },
];
const RentTableHeaders: VDataTableHeader = [
...baseTableHeaders,
- { title: "Farm ID", key: "farmId" },
+ { title: "Farm ID", key: "farm_id" },
{
title: "Node",
key: "node",
diff --git a/packages/playground/src/weblets/tf_deployment_list.vue b/packages/playground/src/weblets/tf_deployment_list.vue
index b570629844..8b98883e0d 100644
--- a/packages/playground/src/weblets/tf_deployment_list.vue
+++ b/packages/playground/src/weblets/tf_deployment_list.vue
@@ -282,6 +282,14 @@
/>
+
+
+
+
-
+
@@ -124,6 +124,7 @@ const email = ref(profileManager.profile?.email || "");
const solution = ref() as Ref;
const ipv4 = ref(false);
const mycelium = ref(true);
+const planetary = ref(true);
const smtp = ref(createSMTPServer());
const dedicated = ref(false);
const certified = ref(false);
@@ -181,7 +182,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
rootFilesystemSize: rootFilesystemSize.value,
publicIpv4: ipv4.value,
- planetary: true,
+ planetary: planetary.value,
mycelium: mycelium.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
diff --git a/packages/playground/src/weblets/tf_funkwhale.vue b/packages/playground/src/weblets/tf_funkwhale.vue
index 8d6d62120d..f27fbd36bf 100644
--- a/packages/playground/src/weblets/tf_funkwhale.vue
+++ b/packages/playground/src/weblets/tf_funkwhale.vue
@@ -89,7 +89,7 @@
:small="{ cpu: 1, memory: 2, disk: 50 }"
:medium="{ cpu: 2, memory: 4, disk: 100 }"
/>
-
+
@@ -153,6 +153,7 @@ const dedicated = ref(false);
const certified = ref(false);
const ipv4 = ref(false);
const mycelium = ref(true);
+const planetary = ref(false);
const selectionDetails = ref();
const gridStore = useGrid();
const grid = gridStore.client as GridClient;
@@ -207,6 +208,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
mycelium: mycelium.value,
+ planetary: planetary.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
{ key: "FUNKWHALE_HOSTNAME", value: domain },
diff --git a/packages/playground/src/weblets/tf_mattermost.vue b/packages/playground/src/weblets/tf_mattermost.vue
index 0a8a805d7d..0fb205e970 100644
--- a/packages/playground/src/weblets/tf_mattermost.vue
+++ b/packages/playground/src/weblets/tf_mattermost.vue
@@ -42,7 +42,7 @@
:medium="{ cpu: 2, memory: 4, disk: 50 }"
:large="{ cpu: 4, memory: 16, disk: 100 }"
/>
-
+
@@ -106,6 +106,7 @@ const flist: Flist = {
const dedicated = ref(false);
const certified = ref(false);
const ipv4 = ref(false);
+const planetary = ref(true);
const smtp = ref(createSMTPServer());
const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0));
const selectionDetails = ref();
@@ -164,7 +165,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
rootFilesystemSize: rootFilesystemSize.value,
publicIpv4: ipv4.value,
- planetary: true,
+ planetary: planetary.value,
mycelium: mycelium.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
diff --git a/packages/playground/src/weblets/tf_nextcloud.vue b/packages/playground/src/weblets/tf_nextcloud.vue
index ac56cd57c1..fe1d29f655 100644
--- a/packages/playground/src/weblets/tf_nextcloud.vue
+++ b/packages/playground/src/weblets/tf_nextcloud.vue
@@ -36,7 +36,7 @@
:large="{ cpu: 4, memory: 16, disk: 1000 }"
v-model="solution"
/>
-
+
@@ -97,6 +97,7 @@ const dedicated = ref(false);
const certified = ref(false);
const ipv4 = ref(false);
const mycelium = ref(true);
+const planetary = ref(false);
const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0));
const selectionDetails = ref();
const selectedSSHKeys = ref("");
@@ -158,6 +159,7 @@ async function deploy() {
flist: flist.value,
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
+ planetary: planetary.value,
mycelium: mycelium.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
diff --git a/packages/playground/src/weblets/tf_node_pilot.vue b/packages/playground/src/weblets/tf_node_pilot.vue
index bdc26b639a..1f9e927c31 100644
--- a/packages/playground/src/weblets/tf_node_pilot.vue
+++ b/packages/playground/src/weblets/tf_node_pilot.vue
@@ -35,6 +35,13 @@
:large="{ cpu: 8, memory: 32, disk: 2000 }"
v-model="solution"
/>
+
@@ -71,6 +78,7 @@ import { type Ref, ref } from "vue";
import { manual } from "@/utils/manual";
+import Network from "../components/networks.vue";
import { useLayout } from "../components/weblet_layout.vue";
import { useGrid } from "../stores";
import { type Flist, ProjectName } from "../types";
@@ -83,6 +91,10 @@ const flist: Flist = {
value: "https://hub.grid.tf/tf-official-vms/node-pilot-zdbfs.flist",
entryPoint: "/",
};
+const ipv4 = ref(false);
+const ipv6 = ref(false);
+const planetary = ref(true);
+const mycelium = ref(true);
const dedicated = ref(false);
const certified = ref(false);
const rootFilesystemSize = 2;
@@ -111,9 +123,10 @@ async function deploy() {
memory: solution.value.memory,
flist: flist.value,
entryPoint: flist.entryPoint,
- publicIpv4: true,
- publicIpv6: true,
- planetary: false,
+ publicIpv4: ipv4.value,
+ publicIpv6: ipv6.value,
+ planetary: planetary.value,
+ mycelium: mycelium.value,
envs: [{ key: "SSH_KEY", value: selectedSSHKeys.value }],
rootFilesystemSize,
disks: [
diff --git a/packages/playground/src/weblets/tf_nostr.vue b/packages/playground/src/weblets/tf_nostr.vue
new file mode 100644
index 0000000000..5bf6e16c99
--- /dev/null
+++ b/packages/playground/src/weblets/tf_nostr.vue
@@ -0,0 +1,204 @@
+
+
+ Deploy a Nostr Machine
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/playground/src/weblets/tf_peertube.vue b/packages/playground/src/weblets/tf_peertube.vue
index d891978123..755c91abcc 100644
--- a/packages/playground/src/weblets/tf_peertube.vue
+++ b/packages/playground/src/weblets/tf_peertube.vue
@@ -63,7 +63,7 @@
-
+
@@ -126,6 +126,7 @@ const ipv4 = ref(false);
const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0));
const selectionDetails = ref();
const mycelium = ref(true);
+const planetary = ref(true);
const selectedSSHKeys = ref("");
const gridStore = useGrid();
const grid = gridStore.client as GridClient;
@@ -177,7 +178,7 @@ async function deploy() {
flist: flist.value,
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
- planetary: true,
+ planetary: planetary.value,
mycelium: mycelium.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
diff --git a/packages/playground/src/weblets/tf_staticwebsite.vue b/packages/playground/src/weblets/tf_staticwebsite.vue
index 2430344b85..5e9afa0b9d 100644
--- a/packages/playground/src/weblets/tf_staticwebsite.vue
+++ b/packages/playground/src/weblets/tf_staticwebsite.vue
@@ -62,7 +62,7 @@
:medium="{ cpu: 2, memory: 4, disk: 100 }"
/>
-
+
;
const flist: Flist = {
// Should be upgraded to an oficial Flist
@@ -193,6 +194,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
mycelium: mycelium.value,
+ planetary: planetary.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
{ key: "GITHUB_URL", value: gitUrl.value },
diff --git a/packages/playground/src/weblets/tf_subsquid.vue b/packages/playground/src/weblets/tf_subsquid.vue
index 5fc458e08a..d332b63104 100644
--- a/packages/playground/src/weblets/tf_subsquid.vue
+++ b/packages/playground/src/weblets/tf_subsquid.vue
@@ -51,7 +51,7 @@
:medium="{ cpu: 2, memory: 4, disk: 100 }"
/>
-
+
@@ -104,6 +104,7 @@ const profileManager = useProfileManager();
const name = ref(generateName({ prefix: "ss" }));
const endpoint = ref("");
const ipv4 = ref(false);
+const planetary = ref(false);
const mycelium = ref(true);
const solution = ref() as Ref;
const flist: Flist = {
@@ -168,6 +169,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
mycelium: mycelium.value,
+ planetary: planetary.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
{ key: "CHAIN_ENDPOINT", value: endpoint.value },
diff --git a/packages/playground/src/weblets/tf_taiga.vue b/packages/playground/src/weblets/tf_taiga.vue
index e85d812a75..f3821870e5 100644
--- a/packages/playground/src/weblets/tf_taiga.vue
+++ b/packages/playground/src/weblets/tf_taiga.vue
@@ -90,7 +90,7 @@
:small="{ cpu: 2, memory: 4, disk: 100 }"
:medium="{ cpu: 4, memory: 8, disk: 150 }"
/>
-
+
@@ -161,6 +161,7 @@ const dedicated = ref(false);
const certified = ref(false);
const ipv4 = ref(false);
const mycelium = ref(true);
+const planetary = ref(true);
const smtp = ref(createSMTPServer());
const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0));
const selectionDetails = ref();
@@ -218,7 +219,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
rootFilesystemSize: rootFilesystemSize.value,
publicIpv4: ipv4.value,
- planetary: true,
+ planetary: planetary.value,
mycelium: mycelium.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
diff --git a/packages/playground/src/weblets/tf_wordpress.vue b/packages/playground/src/weblets/tf_wordpress.vue
index 8d2ea73c51..6d6e46626f 100644
--- a/packages/playground/src/weblets/tf_wordpress.vue
+++ b/packages/playground/src/weblets/tf_wordpress.vue
@@ -90,7 +90,7 @@
:large="{ cpu: 4, memory: 16, disk: 100 }"
/>
-
+
@@ -154,6 +154,7 @@ const dedicated = ref(false);
const certified = ref(false);
const ipv4 = ref(false);
const mycelium = ref(true);
+const planetary = ref(false);
const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0));
const selectionDetails = ref();
const selectedSSHKeys = ref("");
@@ -206,6 +207,7 @@ async function deploy() {
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
mycelium: mycelium.value,
+ planetary: planetary.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
{ key: "MYSQL_USER", value: username.value },