diff --git a/src/features/preferences/renderer/preference-items/application/application-preference-page.injectable.ts b/src/features/preferences/renderer/preference-items/application/application-preference-page.injectable.ts
new file mode 100644
index 0000000000..1c193ed49e
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/application-preference-page.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable } from "@ogre-tools/injectable";
+import { preferenceItemInjectionToken } from "../preference-item-injection-token";
+import { ApplicationPreferencePage } from "./application-preference-page";
+
+const applicationPreferencePageInjectable = getInjectable({
+ id: "application-preference-page",
+
+ instantiate: () => ({
+ kind: "page" as const,
+ id: "application-page",
+ parentId: "application-tab",
+ orderNumber: 0,
+ Component: ApplicationPreferencePage,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default applicationPreferencePageInjectable;
diff --git a/src/features/preferences/renderer/preference-items/application/application-preference-page.tsx b/src/features/preferences/renderer/preference-items/application/application-preference-page.tsx
new file mode 100644
index 0000000000..10b416f7bb
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/application-preference-page.tsx
@@ -0,0 +1,11 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+
+export const ApplicationPreferencePage = () => (
+
+
Application
+
+);
diff --git a/src/features/preferences/renderer/preference-items/application/application-preference-tab.injectable.ts b/src/features/preferences/renderer/preference-items/application/application-preference-tab.injectable.ts
new file mode 100644
index 0000000000..c89b35e894
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/application-preference-tab.injectable.ts
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable } from "@ogre-tools/injectable";
+import { preferenceItemInjectionToken } from "../preference-item-injection-token";
+
+const applicationPreferenceTabInjectable = getInjectable({
+ id: "application-preference-tab",
+
+ instantiate: () => ({
+ kind: "tab" as const,
+ id: "application-tab",
+ parentId: "preference-tabs" as const,
+ pathId: "app",
+ testId: "application-preferences-page",
+ label: "Application",
+ orderNumber: 10,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default applicationPreferenceTabInjectable;
diff --git a/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry-preference-item.injectable.ts
new file mode 100644
index 0000000000..3184f2e666
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable } from "@ogre-tools/injectable";
+import { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { ExtensionInstallRegistry } from "./extension-install-registry";
+
+const extensionInstallRegistryPreferenceItemInjectable = getInjectable({
+ id: "extension-install-registry-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "extension-install-registry",
+ parentId: "application-page",
+ orderNumber: 20,
+ Component: ExtensionInstallRegistry,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default extensionInstallRegistryPreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry.tsx b/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry.tsx
new file mode 100644
index 0000000000..ce6aed0a5f
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry.tsx
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
+import { Select } from "../../../../../../renderer/components/select";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import { defaultExtensionRegistryUrl, defaultExtensionRegistryUrlLocation } from "../../../../../../common/user-store/preferences-helpers";
+import { Input } from "../../../../../../renderer/components/input";
+import { isUrl } from "../../../../../../renderer/components/input/input_validators";
+import type { UserStore } from "../../../../../../common/user-store";
+import { runInAction } from "mobx";
+import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
+import { observer } from "mobx-react";
+
+interface Dependencies {
+ userStore: UserStore;
+}
+
+const extensionInstallRegistryOptions = [
+ {
+ value: "default",
+ label: "Default Url",
+ },
+ {
+ value: "npmrc",
+ label: "Global .npmrc file's Url",
+ },
+ {
+ value: "custom",
+ label: "Custom Url",
+ },
+] as const;
+
+const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencies) => {
+ const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || "");
+
+ return (
+
+ );
+});
+
+export const ExtensionInstallRegistry = withInjectables(
+ NonInjectedExtensionInstallRegistry,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/application/start-up/start-up-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/application/start-up/start-up-preference-item.injectable.ts
new file mode 100644
index 0000000000..045477f28c
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/start-up/start-up-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable } from "@ogre-tools/injectable";
+import { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { StartUp } from "./start-up";
+
+const startUpPreferenceItemInjectable = getInjectable({
+ id: "start-up-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "start-up",
+ parentId: "application-page",
+ orderNumber: 30,
+ Component: StartUp,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default startUpPreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/application/start-up/start-up.tsx b/src/features/preferences/renderer/preference-items/application/start-up/start-up.tsx
new file mode 100644
index 0000000000..427705cca1
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/start-up/start-up.tsx
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import type { UserStore } from "../../../../../../common/user-store";
+import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
+import { Switch } from "../../../../../../renderer/components/switch";
+import { observer } from "mobx-react";
+
+interface Dependencies {
+ userStore: UserStore;
+}
+
+const NonInjectedStartUp = observer(({ userStore }: Dependencies) => (
+
+
+ (userStore.openAtLogin = !userStore.openAtLogin)}
+ >
+ Automatically start Lens on login
+
+
+));
+
+export const StartUp = withInjectables(
+ NonInjectedStartUp,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/application/theme/theme-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/application/theme/theme-preference-item.injectable.ts
new file mode 100644
index 0000000000..b19c04dad3
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/theme/theme-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable } from "@ogre-tools/injectable";
+import { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { Theme } from "./theme";
+
+const themePreferenceItemInjectable = getInjectable({
+ id: "theme-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "theme",
+ parentId: "application-page",
+ orderNumber: 10,
+ Component: Theme,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default themePreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/application/theme/theme.tsx b/src/features/preferences/renderer/preference-items/application/theme/theme.tsx
new file mode 100644
index 0000000000..851cc638d4
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/theme/theme.tsx
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
+import { Select } from "../../../../../../renderer/components/select";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import { observer } from "mobx-react";
+import type { UserStore } from "../../../../../../common/user-store";
+import type { ThemeStore } from "../../../../../../renderer/themes/store";
+import { defaultThemeId } from "../../../../../../common/vars";
+import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
+import themeStoreInjectable from "../../../../../../renderer/themes/store.injectable";
+
+interface Dependencies {
+ userStore: UserStore;
+ themeStore: ThemeStore;
+}
+
+const NonInjectedTheme = observer(({ userStore, themeStore }: Dependencies) => {
+ const themeOptions = [
+ {
+ value: "system", // TODO: replace with a sentinal value that isn't string (and serialize it differently)
+ label: "Sync with computer",
+ },
+ ...Array.from(themeStore.themes, ([themeId, { name }]) => ({
+ value: themeId,
+ label: name,
+ })),
+ ];
+
+ return (
+
+
+
+ );
+});
+
+export const Theme = withInjectables(
+ NonInjectedTheme,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ themeStore: di.inject(themeStoreInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/application/timezone/timezone-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/application/timezone/timezone-preference-item.injectable.ts
new file mode 100644
index 0000000000..f370771a71
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/timezone/timezone-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable } from "@ogre-tools/injectable";
+import { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { Timezone } from "./timezone";
+
+const timezonePreferenceItemInjectable = getInjectable({
+ id: "timezone-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "timezone",
+ parentId: "application-page",
+ orderNumber: 60,
+ Component: Timezone,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default timezonePreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx b/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx
new file mode 100644
index 0000000000..137d92531c
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import type { UserStore } from "../../../../../../common/user-store";
+import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
+import { Select } from "../../../../../../renderer/components/select";
+import { defaultLocaleTimezone } from "../../../../../../common/user-store/preferences-helpers";
+import moment from "moment-timezone";
+import { observer } from "mobx-react";
+
+interface Dependencies {
+ userStore: UserStore;
+}
+
+const timezoneOptions = moment.tz.names()
+ .map(timezone => ({
+ value: timezone,
+ label: timezone.replace("_", " "),
+ }));
+
+
+const NonInjectedTimezone = observer(({ userStore }: Dependencies) => (
+
+
+
+
+));
+
+export const Timezone = withInjectables(
+ NonInjectedTimezone,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/application/update-channel/update-channel-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/application/update-channel/update-channel-preference-item.injectable.ts
new file mode 100644
index 0000000000..c210fb5092
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/update-channel/update-channel-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable } from "@ogre-tools/injectable";
+import { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { UpdateChannel } from "./update-channel";
+
+const updateChannelPreferenceItemInjectable = getInjectable({
+ id: "update-channel-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "update-channel",
+ parentId: "application-page",
+ orderNumber: 50,
+ Component: UpdateChannel,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default updateChannelPreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/application/update-channel/update-channel.tsx b/src/features/preferences/renderer/preference-items/application/update-channel/update-channel.tsx
new file mode 100644
index 0000000000..96d2b26d24
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/application/update-channel/update-channel.tsx
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import { Select } from "../../../../../../renderer/components/select";
+import { updateChannels } from "../../../../../application-update/common/update-channels";
+import type { SelectedUpdateChannel } from "../../../../../application-update/common/selected-update-channel/selected-update-channel.injectable";
+import selectedUpdateChannelInjectable from "../../../../../application-update/common/selected-update-channel/selected-update-channel.injectable";
+import { pipeline } from "@ogre-tools/fp";
+import { map, toPairs } from "lodash/fp";
+import { observer } from "mobx-react";
+
+interface Dependencies {
+ selectedUpdateChannel: SelectedUpdateChannel;
+}
+
+const updateChannelOptions = pipeline(
+ toPairs(updateChannels),
+
+ map(([, channel]) => ({
+ value: channel.id,
+ label: channel.label,
+ })),
+);
+
+
+const NonInjectedUpdateChannel = observer(({ selectedUpdateChannel }: Dependencies) => (
+
+
+
+));
+
+export const UpdateChannel = withInjectables(
+ NonInjectedUpdateChannel,
+
+ {
+ getProps: (di) => ({
+ selectedUpdateChannel: di.inject(selectedUpdateChannelInjectable),
+ }),
+ },
+);