diff --git a/apps/zui/src/js/icons/FileBorder.tsx b/apps/zui/src/js/icons/FileBorder.tsx
deleted file mode 100644
index 2fe46c4c38..0000000000
--- a/apps/zui/src/js/icons/FileBorder.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from "react"
-import {cssVar} from "../lib/cssVar"
-import FileBorderSvg from "../../static/icons/file-border"
-
-const blue = cssVar("--azure")
-
-export default function FileBorder(props: any) {
- return
-}
diff --git a/apps/zui/src/js/state/Updates/index.ts b/apps/zui/src/js/state/Updates/index.ts
new file mode 100644
index 0000000000..ec43a89a0a
--- /dev/null
+++ b/apps/zui/src/js/state/Updates/index.ts
@@ -0,0 +1,8 @@
+import {slice} from "./reducer"
+import * as selectors from "./selectors"
+
+export default {
+ reducer: slice.reducer,
+ ...slice.actions,
+ ...selectors,
+}
diff --git a/apps/zui/src/js/state/Updates/reducer.ts b/apps/zui/src/js/state/Updates/reducer.ts
new file mode 100644
index 0000000000..32eb100f17
--- /dev/null
+++ b/apps/zui/src/js/state/Updates/reducer.ts
@@ -0,0 +1,32 @@
+import {PayloadAction, createSlice} from "@reduxjs/toolkit"
+
+export const slice = createSlice({
+ name: "$UPDATES",
+ initialState: {
+ nextVersion: null as null | string,
+ isChecking: false,
+ isDownloading: false,
+ downloadProgress: null as null | number,
+ error: null,
+ },
+ reducers: {
+ reset() {
+ return slice.initialState()
+ },
+ setNextVersion(s, a: PayloadAction
) {
+ s.nextVersion = a.payload
+ },
+ setIsChecking(s, a: PayloadAction) {
+ s.isChecking = a.payload
+ },
+ setDownloadProgress(s, a: PayloadAction) {
+ s.downloadProgress = a.payload
+ },
+ setIsDownloading(s, a: PayloadAction) {
+ s.isDownloading = a.payload
+ },
+ setError(s, a: PayloadAction) {
+ s.error = a.payload
+ },
+ },
+})
diff --git a/apps/zui/src/js/state/Updates/selectors.ts b/apps/zui/src/js/state/Updates/selectors.ts
new file mode 100644
index 0000000000..070c776d47
--- /dev/null
+++ b/apps/zui/src/js/state/Updates/selectors.ts
@@ -0,0 +1,8 @@
+import {State} from "../types"
+
+export const isChecking = (state: State) => state.updates.isChecking
+export const getNextVersion = (state: State) => state.updates.nextVersion
+export const getDownloadProgress = (state: State) =>
+ state.updates.downloadProgress
+export const isDownloading = (state: State) => state.updates.isDownloading
+export const getError = (state: State) => state.updates.error
diff --git a/apps/zui/src/js/state/Updates/types.ts b/apps/zui/src/js/state/Updates/types.ts
new file mode 100644
index 0000000000..2c697e78bd
--- /dev/null
+++ b/apps/zui/src/js/state/Updates/types.ts
@@ -0,0 +1,3 @@
+import {slice} from "./reducer"
+
+export type UpdatesState = ReturnType
diff --git a/apps/zui/src/js/state/stores/root-reducer.ts b/apps/zui/src/js/state/stores/root-reducer.ts
index a757089b5c..f1aa4d40d3 100644
--- a/apps/zui/src/js/state/stores/root-reducer.ts
+++ b/apps/zui/src/js/state/stores/root-reducer.ts
@@ -21,6 +21,7 @@ import SessionHistories from "../SessionHistories"
import PoolSettings from "../PoolSettings"
import Window from "../Window"
import LoadDataForm from "../LoadDataForm"
+import Updates from "../Updates"
const rootReducer = combineReducers({
appearance: Appearance.reducer,
@@ -44,6 +45,7 @@ const rootReducer = combineReducers({
toolbars: Toolbars.reducer,
url: Url.reducer,
window: Window.reducer,
+ updates: Updates.reducer,
})
// A proof of concept. This would be a much nicer way to go
diff --git a/apps/zui/src/js/state/types.ts b/apps/zui/src/js/state/types.ts
index ce1da456cb..da41e400a5 100644
--- a/apps/zui/src/js/state/types.ts
+++ b/apps/zui/src/js/state/types.ts
@@ -20,6 +20,7 @@ import {SessionHistoriesState} from "./SessionHistories/types"
import {PoolSettingsState} from "./PoolSettings/types"
import {WindowState} from "./Window/types"
import {LoadDataFormState} from "./LoadDataForm/types"
+import {UpdatesState} from "./Updates/types"
export type ThunkExtraArg = {
api: ZuiApi
@@ -54,4 +55,5 @@ export type State = {
tabHistories: TabHistoriesState
toolbars: ToolbarsState
window: WindowState
+ updates: UpdatesState
}
diff --git a/apps/zui/src/static/AppIcon.icns b/apps/zui/src/static/AppIcon.icns
deleted file mode 100644
index 915d242357..0000000000
Binary files a/apps/zui/src/static/AppIcon.icns and /dev/null differ
diff --git a/apps/zui/src/static/AppIcon.ico b/apps/zui/src/static/AppIcon.ico
deleted file mode 100644
index 328cbf1773..0000000000
Binary files a/apps/zui/src/static/AppIcon.ico and /dev/null differ
diff --git a/apps/zui/src/static/AppIcon.png b/apps/zui/src/static/AppIcon.png
deleted file mode 100644
index d6f7d28f52..0000000000
Binary files a/apps/zui/src/static/AppIcon.png and /dev/null differ
diff --git a/apps/zui/src/static/Windows-Install.gif b/apps/zui/src/static/Windows-Install.gif
deleted file mode 100644
index 4840d95b3c..0000000000
Binary files a/apps/zui/src/static/Windows-Install.gif and /dev/null differ
diff --git a/apps/zui/src/static/fonts/recursive.woff2 b/apps/zui/src/static/fonts/recursive.woff2
deleted file mode 100644
index 353a7d2cb4..0000000000
Binary files a/apps/zui/src/static/fonts/recursive.woff2 and /dev/null differ
diff --git a/apps/zui/src/static/icons/file-border.tsx b/apps/zui/src/static/icons/file-border.tsx
deleted file mode 100644
index 4b54872a5f..0000000000
--- a/apps/zui/src/static/icons/file-border.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from "react"
-
-export default function FileBorder(props: any) {
- return (
-
- )
-}
diff --git a/apps/zui/src/static/icons/subspace-border.svg b/apps/zui/src/static/icons/subspace-border.svg
deleted file mode 100644
index 72ebbf49c3..0000000000
--- a/apps/zui/src/static/icons/subspace-border.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
diff --git a/apps/zui/src/static/icons/subspace.svg b/apps/zui/src/static/icons/subspace.svg
deleted file mode 100644
index fe50168c66..0000000000
--- a/apps/zui/src/static/icons/subspace.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/apps/zui/src/static/pool-wall-background.svg b/apps/zui/src/static/pool-wall-background.svg
deleted file mode 100644
index e1110a05a2..0000000000
--- a/apps/zui/src/static/pool-wall-background.svg
+++ /dev/null
@@ -1,5638 +0,0 @@
-
diff --git a/apps/zui/src/static/welcome-page-background.svg b/apps/zui/src/static/welcome-page-background.svg
deleted file mode 100644
index 456a7266f5..0000000000
--- a/apps/zui/src/static/welcome-page-background.svg
+++ /dev/null
@@ -1,34 +0,0 @@
-
diff --git a/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx b/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx
index 7adbfa5ee8..ed054b0b7d 100644
--- a/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx
+++ b/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx
@@ -16,7 +16,6 @@ import {newPool} from "src/domain/pools/handlers"
const BG = styled.div`
width: 100%;
height: 100%;
- background-image: url(dist/static/pool-wall-background.svg);
background-repeat: no-repeat;
background-position-x: 95%;
background-position-y: 250px;
diff --git a/apps/zui/src/views/update-window/index.module.css b/apps/zui/src/views/update-window/index.module.css
new file mode 100644
index 0000000000..4810efc40c
--- /dev/null
+++ b/apps/zui/src/views/update-window/index.module.css
@@ -0,0 +1,71 @@
+.window {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ height: 100%;
+}
+
+.header {
+ -webkit-app-region: drag;
+ padding: 3rem 1rem 2.5rem 1rem;
+ display: flex;
+ width: 100%;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ user-select: none;
+}
+
+.main {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+ flex: 1;
+ width: 100%;
+ overflow: hidden;
+}
+
+.main a {
+ color: var(--primary-color);
+}
+
+.footer {
+ display: flex;
+ width: 100%;
+ gap: 1rem;
+ padding: 1rem;
+}
+
+.footer button {
+ width: 100%;
+}
+
+.subtext {
+ font-size: 13px;
+ color: var(--foreground-color-light);
+ text-align: center;
+ overflow: auto;
+ padding: 0 1rem;
+}
+
+.title {
+ padding: 0 1rem;
+ text-align: center;
+ font-weight: bold;
+}
+
+.progress {
+ margin: 0.25rem 0;
+ padding: 0 2rem;
+}
+
+@media (prefers-color-scheme: dark) {
+ .window {
+ color: white;
+ }
+
+ .subtext {
+ color: rgb(255, 255, 255, 0.8);
+ }
+}
diff --git a/apps/zui/src/views/update-window/index.tsx b/apps/zui/src/views/update-window/index.tsx
new file mode 100644
index 0000000000..479ca3f72a
--- /dev/null
+++ b/apps/zui/src/views/update-window/index.tsx
@@ -0,0 +1,105 @@
+import {useSelector} from "react-redux"
+import Updates from "src/js/state/Updates"
+import styles from "./index.module.css"
+import forms from "src/components/forms.module.css"
+import classNames from "classnames"
+import ProgressIndicator from "src/js/components/ProgressIndicator"
+import {isNumber} from "lodash"
+import {invoke} from "src/core/invoke"
+import {errorToString} from "src/util/error-to-string"
+import Link from "src/js/components/common/Link"
+
+function useStatus() {
+ const nextVersion = useSelector(Updates.getNextVersion)
+ const isChecking = useSelector(Updates.isChecking)
+ const isDownloading = useSelector(Updates.isDownloading)
+ const error = useSelector(Updates.getError)
+
+ if (isChecking) return "checking"
+ if (error) return "error"
+ if (isDownloading) return "downloading"
+ if (nextVersion) return "available"
+ if (!nextVersion) return "not-available"
+}
+
+function useTemplate() {
+ let status = useStatus()
+ const nextVersion = useSelector(Updates.getNextVersion)
+ const downloadProgress = useSelector(Updates.getDownloadProgress)
+ const error = useSelector(Updates.getError)
+ const closeWindow = () => invoke("window.close", globalThis.windowId)
+ const install = () => invoke("updates.install")
+ const check = () => invoke("updates.check")
+ switch (status) {
+ case "error":
+ return {
+ title: "Error",
+ text: errorToString(error),
+ button: ["OK", closeWindow],
+ submit: ["Try Again", check],
+ }
+ case "checking":
+ return {
+ title: "Checking for Updates...",
+ }
+ case "not-available":
+ return {
+ title: "Up to Date!",
+ text: (
+
+ View releases
+
+ ),
+ button: ["OK", closeWindow],
+ }
+ case "available":
+ return {
+ title: "Update Available",
+ text: `Version ${nextVersion}`,
+ button: ["Later", closeWindow],
+ submit: ["Install", install],
+ }
+ case "downloading":
+ return {
+ title: "Downloading...",
+ text: "Zui will restart when download completes.",
+ progress: downloadProgress,
+ }
+ }
+}
+
+export function UpdateWindow() {
+ const data = useTemplate()
+ const version = globalThis.appMeta.version
+
+ return (
+
+
+
+ v{version}
+
+
+ {data.title && {data.title}
}
+ {data.text && {data.text}
}
+ {isNumber(data.progress) && (
+
+ )}
+
+
+
+ )
+}