Skip to content

Commit

Permalink
merge development
Browse files Browse the repository at this point in the history
  • Loading branch information
0oM4R committed Oct 29, 2024
2 parents 6591896 + 0647659 commit a56342a
Show file tree
Hide file tree
Showing 20 changed files with 236 additions and 127 deletions.
12 changes: 6 additions & 6 deletions packages/grid_client/src/modules/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class MachinesModel {
}

class AddMachineModel extends MachineModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) deployment_name: string;
@Expose() @IsString() @IsNotEmpty() @IsAlphanumericExpectUnderscore() @MaxLength(NameLength) deployment_name: string;
@Expose() @IsString() @IsOptional() myceliumNetworkSeed?: string;
}

Expand All @@ -167,7 +167,7 @@ class MachinesGetModel extends BaseGetDeleteModel {}
class MachinesDeleteModel extends BaseGetDeleteModel {}

class KubernetesNodeModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) name: string;
@Expose() @IsString() @IsNotEmpty() @IsAlphanumericExpectUnderscore() @MaxLength(NameLength) name: string;
@Expose() @IsInt() @Min(1) node_id: number;
@Expose() @IsInt() @Min(1) cpu: number;
@Expose() @Min(1024) memory: number; // in MB
Expand All @@ -187,7 +187,7 @@ class KubernetesNodeModel {
}

class K8SModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) name: string;
@Expose() @IsString() @IsNotEmpty() @IsAlphanumericExpectUnderscore() @MaxLength(NameLength) name: string;
@Expose() @IsString() @IsNotEmpty() secret: string;
@Expose() @Type(() => NetworkModel) @ValidateNested() network: NetworkModel;
@Expose() @Type(() => KubernetesNodeModel) @ValidateNested({ each: true }) masters: KubernetesNodeModel[];
Expand All @@ -202,13 +202,13 @@ class K8SGetModel extends BaseGetDeleteModel {}
class K8SDeleteModel extends BaseGetDeleteModel {}

class AddWorkerModel extends KubernetesNodeModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) deployment_name: string;
@Expose() @IsString() @IsNotEmpty() @IsAlphanumericExpectUnderscore() @MaxLength(NameLength) deployment_name: string;
@Expose() @IsString() @IsOptional() myceliumNetworkSeed?: string;
}

class DeleteWorkerModel {
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) deployment_name: string;
@Expose() @IsString() @IsNotEmpty() @IsAlphanumeric() @MaxLength(NameLength) name: string;
@Expose() @IsString() @IsNotEmpty() @IsAlphanumericExpectUnderscore() @MaxLength(NameLength) deployment_name: string;
@Expose() @IsString() @IsNotEmpty() @IsAlphanumericExpectUnderscore() @MaxLength(NameLength) name: string;
}

class ZDBModel {
Expand Down
32 changes: 19 additions & 13 deletions packages/playground/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -294,22 +294,29 @@ function setSidebarOnResize() {
window.addEventListener("resize", setSidebarOnResize);
const themeMatcher = window.matchMedia("(prefers-color-scheme: dark)");
// changes theme based on changes in system mode
themeMatcher.addEventListener("change", updateTheme);
const themeMatchers = {
light: window.matchMedia("(prefers-color-scheme: light)"),
dark: window.matchMedia("(prefers-color-scheme: dark)"),
};
themeMatchers.dark.addEventListener("change", updateTheme);
themeMatchers.light.addEventListener("change", updateTheme);
function updateTheme() {
if (themeMatcher.matches) {
theme.global.name.value = AppThemeSelection.dark;
} else {
theme.global.name.value = AppThemeSelection.light;
const themeKey = getThemeKey();
theme.global.name.value = AppThemeSelection[themeKey];
localStorage.setItem(LocalStorageSettingsKey.THEME_KEY, AppThemeSelection[themeKey]);
}
function getThemeKey() {
if (themeMatchers.dark.matches) {
return "dark";
} else if (themeMatchers.light.matches) {
return "light";
}
localStorage.setItem(LocalStorageSettingsKey.THEME_KEY, ThemeSettingsInterface.System);
return "system";
}
// sets theme to system mode on application mount
onMounted(() => {
updateTheme();
});
watch(
() => $route.meta,
meta => {
Expand Down Expand Up @@ -551,7 +558,6 @@ import type { GridClient } from "@threefold/grid_client";
import { DashboardRoutes } from "@/router/routes";
import { AppThemeSelection } from "@/utils/app_theme";
import { ThemeSettingsInterface } from "@/utils/settings";
import AppTheme from "./components/app_theme.vue";
import DeploymentListManager from "./components/deployment_list_manager.vue";
Expand Down
1 change: 1 addition & 0 deletions packages/playground/src/calculator/pricing_calculator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<InputTooltip tooltip="The amount of TFT to calculate discount.">
<VTextField
label="Balance"
:max="10 ** 15"
suffix="TFT"
:rules="[balanceRules]"
:disabled="userBalance && resources.useCurrentBalance"
Expand Down
6 changes: 5 additions & 1 deletion packages/playground/src/components/app_theme.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ const theme = useTheme();
const light = ref(false);
watch(light, light => (theme.global.name.value = light ? "light" : "dark"));
watch(theme.global.name, theme => localStorage.setItem(LocalStorageSettingsKey.THEME_KEY, theme));
watch(theme.global.name, theme => {
localStorage.setItem(LocalStorageSettingsKey.THEME_KEY, theme);
light.value = theme === "light";
});
onMounted(() => {
const theme = localStorage.getItem(LocalStorageSettingsKey.THEME_KEY);
light.value = theme === "light";
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/src/components/k8s_worker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
validators.required('Name is required.'),
validators.isLowercase('Name should consist of lowercase letters only.'),
(name: string) => validators.isAlpha('Name must start with an alphabetical character.')(name[0]),
validators.isAlphanumeric('Name should consist of alphabets & numbers only.'),
validators.IsAlphanumericExpectUnderscore('Name should consist of letters ,numbers and underscores only.'),
validators.minLength('Name minimum length is 2 chars.', 2),
validators.maxLength('Name max length is 50 chars.', 50),
]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@deploy="deploy"
@delete="onDelete"
@back="updateCaprover"
@click:outside="updateCaprover"
>
<template #title>Manage Caprover({{ $props.master.name }}) Workers</template>

Expand Down Expand Up @@ -144,9 +145,17 @@ async function deploy(layout: any) {
}),
});
const leader = setCaproverWorkers(vms, props.projectName);
const [leader, ...workers] = vms;
leader.workers = workers;
leader.projectName = props.projectName;
leader.deploymentName = leader.name;
caproverData.value = leader;
deployedDialog.value = true;
workers.forEach((worker: any) => {
if (!worker.projectName) worker.projectName = props.projectName;
if (!worker.deploymentName) worker.deploymentName = leader.name;
});
emits("update:caprover", leader);
layout.setStatus("success", `Successfully add a new worker to Caprover('${props.master.name}') Instance.`);
} catch (e) {
layout.setStatus("failed", normalizeError(e, "Failed to deploy a caprover worker."));
Expand Down Expand Up @@ -180,8 +189,6 @@ async function onDelete(cb: (workers: any[]) => void) {
<script lang="ts">
import { calculateRootFileSystem, type GridClient } from "@threefold/grid_client";
import { setCaproverWorkers } from "@/utils/deploy_helpers";
import CaproverWorker, { createWorker } from "../components/caprover_worker.vue";
import ListTable from "../components/list_table.vue";
import { updateGrid } from "../utils/grid";
Expand Down
21 changes: 13 additions & 8 deletions packages/playground/src/components/smtp_server.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,23 @@
<input-validator
:value="$props.modelValue.username"
:rules="[
validators.required('Email is required.'),
validators.isEmail('Please provide a valid email address.'),
v => {
return isDiscourse ? undefined : validators.isEmail('Please provide a valid email address.')(v);
validators.required('Email or Username is required.'),
validators.minLength('Username must be at least 2 characters.', 2),
validators.maxLength('Email or Username cannot exceed 50 characters.', 50),
(v: string) => {
return (
validators.isEmail('Please provide a valid email address.')(v) &&
(validators.IsAlphanumericExpectDashAndUnderscore(
'Username should consist of letters, numbers, dashs and underscores only.'
)(v))
);
},
]"
#="{ props }"
>
<input-tooltip :tooltip="isDiscourse ? 'SMTP admin email, Username or API key.' : 'SMTP admin email'">
<input-tooltip tooltip="SMTP admin email, Username or API key.">
<v-text-field
label="Admin Email"
label="Admin Email or Username"
placeholder="email@example.com"
v-model="$props.modelValue.username"
v-bind="props"
Expand All @@ -46,7 +52,7 @@
:rules="[
validators.required('Password is required.'),
validators.minLength('Password must be at least 6 characters.', 6),
validators.maxLength('Password cannot exceed 50 characters.', 50),
validators.maxLength('Password cannot exceed 69 characters.', 69),
validators.pattern('Password should not contain whitespaces.', {
pattern: /^[^\s]+$/,
}),
Expand Down Expand Up @@ -139,7 +145,6 @@ defineProps<{
tls?: boolean;
email?: boolean;
persistent?: boolean;
isDiscourse?: boolean;
}>();
</script>

Expand Down
14 changes: 3 additions & 11 deletions packages/playground/src/components/vm_deployment_table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ async function loadDeployments() {
if (chunk2.count > 0 && migrateGateways) {
await migrateModule(grid!.gateway);
}
let chunk3: LoadedDeployments<any[]> = { count: 0, items: [], failedDeployments: [] };
if (showAllDeployments.value) {
chunk3 =
Expand All @@ -258,16 +259,7 @@ async function loadDeployments() {
const vms = mergeLoadedDeployments(chunk1, chunk2, chunk3 as any);
failedDeployments.value = vms.failedDeployments;
count.value = vms.count;
const updatedVMS = vms.items.map((_vms: any) => {
const leader = setCaproverWorkers(_vms);
return leader || _vms;
});
const has_leader = updatedVMS.filter(vm => vm.env && vm.env["SWM_NODE_MODE"] === "leader").length > 0;
if (has_leader) {
items.value = updatedVMS;
}
items.value = mergeCaproverDeployments(vms.items);
} catch (err) {
errorMessage.value = `Failed to load Deployments: ${err}`;
} finally {
Expand Down Expand Up @@ -458,7 +450,7 @@ defineExpose({ loadDeployments });

<script lang="ts">
import toHumanDate from "@/utils/date";
import { setCaproverWorkers } from "@/utils/deploy_helpers";
import { mergeCaproverDeployments } from "@/utils/deploy_helpers";
import { ProjectName } from "../types";
import { migrateModule } from "../utils/migration";
Expand Down
3 changes: 2 additions & 1 deletion packages/playground/src/dashboard/components/create_farm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import { createCustomToast, ToastType } from "../../utils/custom_toast";
export default {
name: "CreateFarm",
setup() {
setup(_, context) {
const showDialogue = ref(false);
const isCreating = ref(false);
const gridStore = useGrid();
Expand All @@ -73,6 +73,7 @@ export default {
createCustomToast("Farm created successfully.", ToastType.success);
showDialogue.value = false;
farmName.value = "";
context.emit("farm-created");
notifyDelaying();
} catch (error) {
console.log(error);
Expand Down
19 changes: 15 additions & 4 deletions packages/playground/src/dashboard/farms_view.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
<v-card-title class="pa-0">Farms</v-card-title>
</v-card>

<CreateFarm class="mt-4" @farm-created="farmsReload = true" />
<UserFarms ref="userFarms" :reloadFarms="farmsReload" />
<CreateFarm class="mt-4" @farm-created="handleFarmCreated" />
<UserFarms :ref="el => (userFarms = el)" :reloadFarms="farmsReload" />
<UserNodes />
</div>
</template>

<script lang="ts">
import { ref } from "vue";
import { ref, watch } from "vue";
import CreateFarm from "./components/create_farm.vue";
import UserFarms from "./components/user_farms.vue";
Expand All @@ -26,9 +26,20 @@ export default {
},
setup() {
const farmsReload = ref<boolean>(false);
const userFarms = ref();
function handleFarmCreated() {
farmsReload.value = !farmsReload.value;
}
watch(
() => farmsReload.value,
() => {
userFarms.value.reloadFarms = farmsReload.value;
},
);
return {
farmsReload,
handleFarmCreated,
userFarms,
};
},
};
Expand Down
1 change: 1 addition & 0 deletions packages/playground/src/utils/app_theme.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum AppThemeSelection {
dark = "dark",
light = "light",
system = "system",
}
53 changes: 36 additions & 17 deletions packages/playground/src/utils/deploy_helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { NetworkModel, type ZmachineData } from "@threefold/grid_client";

import { ProjectName } from "@/types";

import { generateName } from "./strings";

export function createNetwork(network: Network = {}): NetworkModel {
Expand All @@ -11,29 +13,46 @@ export function createNetwork(network: Network = {}): NetworkModel {
return nw;
}

export function setCaproverWorkers(vms: ZmachineData[], projectName: string | undefined = undefined): ZmachineData {
let leader: any = null;
const workers: any[] = [];
export const mergeCaproverDeployments = (clusters: ZmachineData[][]) => {
const vms: ZmachineData[] = [];

vms.forEach((vm: any) => {
if (vm.env["SWM_NODE_MODE"] === "leader") {
leader = vm;
} else if (vm.env["SWM_NODE_MODE"] === "worker") {
workers.push(vm);
}
for (const cluster of clusters) {
let clusterLeader = null;
const clusterWorkers: any[] = [];

if (projectName && leader) {
vm.projectName = projectName;
vm.deploymentName = leader.name;
if (!Array.isArray(cluster)) {
vms.push(cluster);
continue;
}
});

if (leader) {
leader.workers = workers;
for (const vm of cluster) {
const isCaprover = String((vm as any).projectName)
.toLowerCase()
.includes(ProjectName.Caprover.toLowerCase());
if (!isCaprover) {
if (!vms.includes(vm)) {
vms.push(vm);
}
continue;
}

if (vm.env["SWM_NODE_MODE"] === "leader") {
clusterLeader = vm;
} else if (vm.env["SWM_NODE_MODE"] === "worker") {
clusterWorkers.push(vm);
}

if (clusterLeader) {
(clusterLeader as any).workers = clusterWorkers;
if (!vms.includes(clusterLeader)) {
vms.push(clusterLeader);
}
}
}
}

return leader as ZmachineData;
}
return vms;
};

export interface Network {
name?: string;
Expand Down
1 change: 1 addition & 0 deletions packages/playground/src/utils/pricing_calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const hruRules = _applyRules([
export const balanceRules = _applyRules([
isNumeric("Balance must be a valid number."),
min("Minimum allowed balance is 0.", 0),
max("Maximum allowed balance is 1e15 TFT.", 10 ** 15),
]);

export function normalizePrice(price: number) {
Expand Down
Loading

0 comments on commit a56342a

Please sign in to comment.