diff --git a/frontend/public/icons/chevron-up.svg b/frontend/public/icons/chevron-up.svg
new file mode 100644
index 000000000..70bcaa798
--- /dev/null
+++ b/frontend/public/icons/chevron-up.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/frontend/src/components/builds/Build.tsx b/frontend/src/components/builds/Build.tsx
index 918472dff..e455a457e 100644
--- a/frontend/src/components/builds/Build.tsx
+++ b/frontend/src/components/builds/Build.tsx
@@ -1,4 +1,5 @@
import { Component, Show } from "solid-js";
+import { useAppDimensions } from "../../state/DimensionProvider";
import { useAppState } from "../../state/StateProvider";
import { useTheme } from "../../state/ThemeProvider";
import { combineClasses } from "../../util/helpers";
@@ -14,6 +15,7 @@ const Build: Component<{}> = (p) => {
const { builds, selected } = useAppState();
const build = () => builds.get(selected.id())!;
const { themeClass } = useTheme();
+ const { isMobile } = useAppDimensions();
return (
}>
@@ -22,7 +24,9 @@ const Build: Component<{}> = (p) => {
-
+
+
+
{/* right / tabs */}
diff --git a/frontend/src/components/builds/Header.tsx b/frontend/src/components/builds/Header.tsx
index 31eaf8c0c..b4202da1d 100644
--- a/frontend/src/components/builds/Header.tsx
+++ b/frontend/src/components/builds/Header.tsx
@@ -10,6 +10,9 @@ import Grid from "../util/layout/Grid";
import { useActionStates } from "./ActionStateProvider";
import { useTheme } from "../../state/ThemeProvider";
import { combineClasses } from "../../util/helpers";
+import { useAppDimensions } from "../../state/DimensionProvider";
+import Updates from "./Updates";
+import { useLocalStorageToggle } from "../../util/hooks";
const Header: Component<{}> = (p) => {
const { builds, selected, ws } = useAppState();
@@ -17,36 +20,60 @@ const Header: Component<{}> = (p) => {
const actions = useActionStates();
const { permissions, username } = useUser();
const { themeClass } = useTheme();
+ const { isMobile } = useAppDimensions();
+ const [showUpdates, toggleShowUpdates] =
+ useLocalStorageToggle("show-updates");
return (
-
-
- {build().name}
- {getSub(build())}
-
- = 2 || build().owners.includes(username()!)}>
-
-
-
- }
- >
- {
- ws.send(DELETE_BUILD, { buildID: selected.id() });
- }}
- color="red"
+ <>
+ {
+ if (isMobile()) toggleShowUpdates();
+ }}
+ >
+
+ {build().name}
+ {getSub(build())}
+
+ = 2 || build().owners.includes(username()!)}>
+
+
+
+ }
>
-
-
+ {
+ ws.send(DELETE_BUILD, { buildID: selected.id() });
+ }}
+ color="red"
+ >
+
+
+
+
+
+ updates{" "}
+
+
+
+
+
+
-
+ >
);
};
diff --git a/frontend/src/components/deployment/Deployment.tsx b/frontend/src/components/deployment/Deployment.tsx
index 8a6e8ee24..132a4c1bf 100644
--- a/frontend/src/components/deployment/Deployment.tsx
+++ b/frontend/src/components/deployment/Deployment.tsx
@@ -1,4 +1,5 @@
import { Component, Show } from "solid-js";
+import { useAppDimensions } from "../../state/DimensionProvider";
import { useAppState } from "../../state/StateProvider";
import { useTheme } from "../../state/ThemeProvider";
import { combineClasses } from "../../util/helpers";
@@ -16,6 +17,7 @@ const Deployment: Component<{}> = (p) => {
const deployment = () => deployments.get(selected.id()!);
const server = () => deployment() && servers.get(deployment()?.serverID!);
const { themeClass } = useTheme();
+ const { isMobile } = useAppDimensions();
return (
= (p) => {
-
+
+
+
{/* right / tabs */}
diff --git a/frontend/src/components/deployment/Header.tsx b/frontend/src/components/deployment/Header.tsx
index de84276dc..131f49239 100644
--- a/frontend/src/components/deployment/Header.tsx
+++ b/frontend/src/components/deployment/Header.tsx
@@ -16,6 +16,9 @@ import HoverMenu from "../util/menu/HoverMenu";
import { useActionStates } from "./ActionStateProvider";
import { useTheme } from "../../state/ThemeProvider";
import Button from "../util/Button";
+import { useLocalStorageToggle } from "../../util/hooks";
+import { useAppDimensions } from "../../state/DimensionProvider";
+import Updates from "./Updates";
const Header: Component<{ exiting?: boolean }> = (p) => {
const { deployments, ws, selected } = useAppState();
@@ -33,57 +36,88 @@ const Header: Component<{ exiting?: boolean }> = (p) => {
: (deployment()!.status as ContainerStatus).Status.toLowerCase();
const actions = useActionStates();
const { themeClass } = useTheme();
+ const { isMobile } = useAppDimensions();
+ const [showUpdates, toggleShowUpdates] =
+ useLocalStorageToggle("show-updates");
return (
-
-
- {deployment()!.name}
- = 2 || deployment().owners.includes(username()!)}
- >
+ <>
+ {
+ if (isMobile()) toggleShowUpdates();
+ }}
+ >
+
+ {deployment()!.name}
-
-
+ when={
+ permissions() >= 2 || deployment().owners.includes(username()!)
}
>
-
-
-
- }
- >
- {
- ws.send(DELETE_DEPLOYMENT, {
- deploymentID: selected.id(),
- });
- }}
- color="red"
- >
-
-
-
+
+
+
}
- content="delete deployment"
- position="bottom center"
- padding="0.5rem"
- />
+ >
+
+
+
+ }
+ >
+ {
+ ws.send(DELETE_DEPLOYMENT, {
+ deploymentID: selected.id(),
+ });
+ }}
+ color="red"
+ >
+
+
+
+ }
+ content="delete deployment"
+ position="bottom center"
+ padding="0.5rem"
+ />
+
+
+
+
+
+ {status()}
+
+
+
+
+ updates{" "}
+
+
-
-
-
-
- {status()}
-
-
-
+
+
+
+
+ >
);
};
diff --git a/frontend/src/components/server/Header.tsx b/frontend/src/components/server/Header.tsx
index b8e925354..66bb7b32c 100644
--- a/frontend/src/components/server/Header.tsx
+++ b/frontend/src/components/server/Header.tsx
@@ -9,6 +9,9 @@ import Icon from "../util/Icon";
import Flex from "../util/layout/Flex";
import Grid from "../util/layout/Grid";
import { useTheme } from "../../state/ThemeProvider";
+import { useAppDimensions } from "../../state/DimensionProvider";
+import { useLocalStorageToggle } from "../../util/hooks";
+import Updates from "./Updates";
const Header: Component<{}> = (p) => {
const { servers, selected, ws } = useAppState();
@@ -21,34 +24,60 @@ const Header: Component<{}> = (p) => {
: "DISABLED";
const { permissions, username } = useUser();
const { themeClass } = useTheme();
+ const { isMobile } = useAppDimensions();
+ const [showUpdates, toggleShowUpdates] =
+ useLocalStorageToggle("show-updates");
return (
-
-
- {server().name}
- {server().address}
-
-
-
- {status()}
- 1 || server().owners.includes(username())}
- >
- {
- ws.send(REMOVE_SERVER, { serverID: selected.id() });
- }}
- color="red"
+ <>
+ {
+ if (isMobile()) toggleShowUpdates();
+ }}
+ >
+
+ {server().name}
+ server
+
+
+
+
+ {status()}
+
+ 1 || server().owners.includes(username())}
>
-
-
-
-
+ {
+ ws.send(REMOVE_SERVER, { serverID: selected.id() });
+ }}
+ color="red"
+ >
+
+
+
+
+
+
+
+ updates{" "}
+
+
+
+
+
+
-
+ >
);
};
diff --git a/frontend/src/components/server/Server.tsx b/frontend/src/components/server/Server.tsx
index b00ffe986..4495a792f 100644
--- a/frontend/src/components/server/Server.tsx
+++ b/frontend/src/components/server/Server.tsx
@@ -1,4 +1,5 @@
import { Component, Show } from "solid-js";
+import { useAppDimensions } from "../../state/DimensionProvider";
import { useAppState } from "../../state/StateProvider";
import { useTheme } from "../../state/ThemeProvider";
import { combineClasses } from "../../util/helpers";
@@ -14,6 +15,7 @@ const Server: Component<{}> = (p) => {
const { servers, selected } = useAppState();
const server = () => servers.get(selected.id())!;
const { themeClass } = useTheme();
+ const { isMobile } = useAppDimensions();
return (
}>
@@ -22,7 +24,9 @@ const Server: Component<{}> = (p) => {
-
+
+
+
{/* right / tabs */}
diff --git a/frontend/src/components/util/Icon.tsx b/frontend/src/components/util/Icon.tsx
index 26548c433..7fcbc43e3 100644
--- a/frontend/src/components/util/Icon.tsx
+++ b/frontend/src/components/util/Icon.tsx
@@ -6,6 +6,7 @@ export type IconType =
| "arrow-up"
| "arrow-left"
| "chevron-down"
+ | "chevron-up"
| "cross"
| "double-chevron-right"
| "exchange"
diff --git a/frontend/src/style/app.scss b/frontend/src/style/app.scss
index 76007f653..e24c1cbde 100644
--- a/frontend/src/style/app.scss
+++ b/frontend/src/style/app.scss
@@ -110,6 +110,15 @@ $anim-time: 500ms;
max-height: calc(225px + 5.5rem);
}
+.show-updates-indicator {
+ font-size: 0.8rem;
+ position: absolute;
+ bottom: 0.5rem;
+ left: 50%;
+ transform: translateX(-50%);
+ opacity: .7;
+}
+
.tabs {
height: fit-content;
}