+
+ {{ diskSpaceMessage }}
+
@@ -23,10 +26,12 @@
import Navbar from "@/components/Navbar.vue";
import Tabs from "@/components/Tabs.vue";
import Login from "@/views/Login.vue";
+import Alert from "@/components/Alert.vue";
import { defineComponent, onMounted, ref, Ref } from "vue";
-import { getPrincipal, getVersion, logout } from "@/api/api";
+import { getPrincipal, getVersion, logout, getFreeDiskSpace } from "@/api/api";
import { useRouter } from "vue-router";
import { ApiError } from "@/helpers/errors";
+import { diskSpaceBelowThreshold, convertBytes } from "@/helpers/utils";
export default defineComponent({
name: "ArmadilloPortal",
@@ -34,16 +39,19 @@ export default defineComponent({
Navbar,
Tabs,
Login,
+ Alert,
},
setup() {
const isAuthenticated: Ref
= ref(false);
const username: Ref = ref("");
const version: Ref = ref("");
const router = useRouter();
+ const diskSpace: Ref = ref("");
onMounted(() => {
loadUser();
loadVersion();
+ loadFreeDiskSpace();
});
const loadUser = async () => {
@@ -67,13 +75,16 @@ export default defineComponent({
const loadVersion = async () => {
version.value = await getVersion();
};
-
+ const loadFreeDiskSpace = async () => {
+ diskSpace.value = await getFreeDiskSpace();
+ };
return {
username,
isAuthenticated,
version,
loadUser,
loadVersion,
+ diskSpace,
};
},
data() {
@@ -88,6 +99,16 @@ export default defineComponent({
],
};
},
+ computed: {
+ diskNearFull() {
+ return diskSpaceBelowThreshold(this.diskSpace);
+ },
+ diskSpaceMessage() {
+ return `Disk space low (${
+ this.diskSpace === "" ? "" : convertBytes(this.diskSpace)
+ } remaining). Saving workspaces may not be possible and users risk losing workspace data. Either allocate more space or remove saved workspaces.`;
+ },
+ },
methods: {
logoutUser() {
logout().then(() => {
diff --git a/ui/src/api/api.ts b/ui/src/api/api.ts
index a467584d5..c16aee327 100644
--- a/ui/src/api/api.ts
+++ b/ui/src/api/api.ts
@@ -318,3 +318,9 @@ export async function createLinkFile(
};
return postJson(`/storage/projects/${viewProject}/objects/link`, data);
}
+
+export async function getFreeDiskSpace() {
+ return get("/actuator/metrics/disk.free").then((data) => {
+ return data.measurements[0].value;
+ });
+}
diff --git a/ui/src/components/ActuatorItem.vue b/ui/src/components/ActuatorItem.vue
index 241817a21..25b56f7b3 100644
--- a/ui/src/components/ActuatorItem.vue
+++ b/ui/src/components/ActuatorItem.vue
@@ -27,30 +27,18 @@
diff --git a/ui/src/components/Alert.vue b/ui/src/components/Alert.vue
index 0d593f328..2a220d6c1 100644
--- a/ui/src/components/Alert.vue
+++ b/ui/src/components/Alert.vue
@@ -10,6 +10,7 @@