diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index d981049d01..2320d8ed7b 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -260,6 +260,32 @@ const editorConfiguration: PreferenceDescription = { + fromStore(val) { + return updateChannels.has(val) ? val : defaultUpdateChannel; + }, + toStore(val) { + if (!updateChannels.has(val) || val === defaultUpdateChannel) { + return undefined; + } + + return val; + } +}; + type PreferencesModelType = typeof DESCRIPTORS[field] extends PreferenceDescription ? T : never; type UserStoreModelType = typeof DESCRIPTORS[field] extends PreferenceDescription ? T : never; @@ -288,4 +314,10 @@ export const DESCRIPTORS = { syncKubeconfigEntries, editorConfiguration, terminalCopyOnSelect, + updateChannel, +}; + +export const CONSTANTS = { + defaultUpdateChannel, + updateChannels, }; diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 1bd18e06e8..68e7ece0d6 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -30,7 +30,7 @@ import { appEventBus } from "../event-bus"; import path from "path"; import { fileNameMigration } from "../../migrations/user-store"; import { ObservableToggleSet, toJS } from "../../renderer/utils"; -import { DESCRIPTORS, KubeconfigSyncValue, UserPreferencesModel, EditorConfiguration } from "./preferences-helpers"; +import { DESCRIPTORS, KubeconfigSyncValue, UserPreferencesModel, EditorConfiguration, CONSTANTS } from "./preferences-helpers"; import logger from "../../main/logger"; import type { monaco } from "react-monaco-editor"; import { getPath } from "../utils/getPath"; @@ -75,6 +75,7 @@ export class UserStore extends BaseStore /* implements UserStore @observable downloadBinariesPath?: string; @observable kubectlBinariesPath?: string; @observable terminalCopyOnSelect: boolean; + @observable updateChannel?: string; /** * Download kubectl binaries matching cluster version @@ -106,6 +107,10 @@ export class UserStore extends BaseStore /* implements UserStore return this.shell || process.env.SHELL || process.env.PTYSHELL; } + @computed get isAllowedToDowngrade(): boolean { + return this.updateChannel !== CONSTANTS.defaultUpdateChannel; + } + startMainReactions() { // track telemetry availability reaction(() => this.allowTelemetry, allowed => { @@ -218,6 +223,7 @@ export class UserStore extends BaseStore /* implements UserStore this.syncKubeconfigEntries.replace(DESCRIPTORS.syncKubeconfigEntries.fromStore(preferences?.syncKubeconfigEntries)); this.editorConfiguration = DESCRIPTORS.editorConfiguration.fromStore(preferences?.editorConfiguration); this.terminalCopyOnSelect = DESCRIPTORS.terminalCopyOnSelect.fromStore(preferences?.terminalCopyOnSelect); + this.updateChannel = DESCRIPTORS.updateChannel.fromStore(preferences?.updateChannel); } toJSON(): UserStoreModel { @@ -240,6 +246,7 @@ export class UserStore extends BaseStore /* implements UserStore syncKubeconfigEntries: DESCRIPTORS.syncKubeconfigEntries.toStore(this.syncKubeconfigEntries), editorConfiguration: DESCRIPTORS.editorConfiguration.toStore(this.editorConfiguration), terminalCopyOnSelect: DESCRIPTORS.terminalCopyOnSelect.toStore(this.terminalCopyOnSelect), + updateChannel: DESCRIPTORS.updateChannel.toStore(this.updateChannel), }, }; diff --git a/src/main/app-updater.ts b/src/main/app-updater.ts index ab8a4c509b..d22f96d65d 100644 --- a/src/main/app-updater.ts +++ b/src/main/app-updater.ts @@ -27,6 +27,7 @@ import { areArgsUpdateAvailableToBackchannel, AutoUpdateLogPrefix, broadcastMess import { once } from "lodash"; import { ipcMain } from "electron"; import { nextUpdateChannel } from "./utils/update-channel"; +import { UserStore } from "../common/user-store"; const updateChannel = autoUpdater.channel; let installVersion: null | string = null; @@ -58,9 +59,13 @@ export const startUpdateChecking = once(function (interval = 1000 * 60 * 60 * 24 return; } + const us = UserStore.getInstance(); + autoUpdater.logger = logger; autoUpdater.autoDownload = false; autoUpdater.autoInstallOnAppQuit = false; + autoUpdater.channel = us.updateChannel; + autoUpdater.allowDowngrade = us.isAllowedToDowngrade; autoUpdater .on("update-available", (info: UpdateInfo) => { diff --git a/src/renderer/components/+preferences/application.tsx b/src/renderer/components/+preferences/application.tsx index ba86dc2ea8..f99b65f306 100644 --- a/src/renderer/components/+preferences/application.tsx +++ b/src/renderer/components/+preferences/application.tsx @@ -29,11 +29,16 @@ import { Input } from "../input"; import { isWindows } from "../../../common/vars"; import { FormSwitch, Switcher } from "../switch"; import moment from "moment-timezone"; +import { CONSTANTS } from "../../../common/user-store/preferences-helpers"; const timezoneOptions: SelectOption[] = moment.tz.names().map(zone => ({ label: zone, value: zone, })); +const updateChannelOptions: SelectOption[] = Array.from( + CONSTANTS.updateChannels.entries(), + ([value, { label }]) => ({ value, label }), +); export const Application = observer(() => { const defaultShell = process.env.SHELL @@ -104,6 +109,18 @@ export const Application = observer(() => {
+
+ +