diff --git a/src/actions/options.js b/src/actions/options.js
index 668137a65..0f5db99a3 100644
--- a/src/actions/options.js
+++ b/src/actions/options.js
@@ -72,7 +72,22 @@ export function loadUserOptions (userOptions: RemoteUserOptionsType): LoadUserOp
}
}
-export function saveGlobalOptions ({ values: { sshKey, language, showNotifications, notificationSnoozeDuration, refreshInterval, persistLocale } = {} }: Object, { transactionId }: Object): SaveGlobalOptionsActionType {
+export function saveGlobalOptions ({
+ values: {
+ sshKey,
+ language,
+ persistLocale,
+ showNotifications,
+ notificationSnoozeDuration,
+ refreshInterval,
+ preferredConsole,
+ fullScreenVnc,
+ ctrlAltEndVnc,
+ fullScreenSpice,
+ ctrlAltEndSpice,
+ smartcardSpice,
+ } = {},
+}: Object, { transactionId }: Object): SaveGlobalOptionsActionType {
return {
type: C.SAVE_GLOBAL_OPTIONS,
payload: {
@@ -82,6 +97,12 @@ export function saveGlobalOptions ({ values: { sshKey, language, showNotificatio
showNotifications,
notificationSnoozeDuration,
refreshInterval,
+ preferredConsole,
+ fullScreenVnc,
+ ctrlAltEndVnc,
+ fullScreenSpice,
+ ctrlAltEndSpice,
+ smartcardSpice,
},
meta: {
transactionId,
diff --git a/src/actions/types.js b/src/actions/types.js
index 2194b5368..227869f57 100644
--- a/src/actions/types.js
+++ b/src/actions/types.js
@@ -17,7 +17,13 @@ export type SaveGlobalOptionsActionType = {
persistLocale?: boolean,
showNotifications?: boolean,
notificationSnoozeDuration?: number,
- sshKey?: string
+ sshKey?: string,
+ preferredConsole?: string,
+ fullScreenVnc?: boolean,
+ ctrlAltEndVnc?: boolean,
+ fullScreenSpice?: boolean,
+ ctrlAltEndSpice?: boolean,
+ smartcardSpice?: boolean
|},
meta: {|
transactionId: string
diff --git a/src/components/Settings/SettingsBase.js b/src/components/Settings/SettingsBase.js
index 8c98b7b1e..f1248c668 100644
--- a/src/components/Settings/SettingsBase.js
+++ b/src/components/Settings/SettingsBase.js
@@ -62,13 +62,16 @@ Section.propTypes = {
}
const SettingsBase = ({ name, section }) => {
+ const sections = section.sections ? Object.entries(section.sections) : [[name, section]]
return (
-
-
-
-
-
+ { sections.map(([name, section]) =>
+
+
+
+
+
+ )}
)
}
diff --git a/src/components/UserSettings/GlobalSettings.js b/src/components/UserSettings/GlobalSettings.js
index 90cb1f610..d11b1b935 100644
--- a/src/components/UserSettings/GlobalSettings.js
+++ b/src/components/UserSettings/GlobalSettings.js
@@ -13,6 +13,7 @@ import { Settings, SettingsBase } from '../Settings'
import SelectBox from '../SelectBox'
import moment from 'moment'
import AppConfiguration from '_/config'
+import { BROWSER_VNC, NATIVE_VNC, SPICE, RDP } from '_/constants/console'
const GENERAL_SECTION = 'general'
@@ -59,8 +60,30 @@ class GlobalSettings extends Component {
]
}
+ preferredConsoleList (msg) {
+ return [
+ {
+ id: NATIVE_VNC,
+ value: msg.vncConsole(),
+ },
+ {
+ id: BROWSER_VNC,
+ value: msg.vncConsoleBrowser(),
+ },
+ {
+ id: SPICE,
+ value: msg.spiceConsole(),
+ },
+ {
+ id: RDP,
+ value: msg.remoteDesktop(),
+ },
+ ]
+ }
+
constructor (props) {
super(props)
+ const { config } = props
/**
* Typical flow (happy path):
* 1. at the begining:
@@ -99,6 +122,12 @@ class GlobalSettings extends Component {
refreshInterval: AppConfiguration.schedulerFixedDelayInSeconds,
notificationSnoozeDuration: AppConfiguration.notificationSnoozeDurationInMinutes,
persistLocale: AppConfiguration.persistLocale,
+ fullScreenVnc: false,
+ fullScreenSpice: false,
+ ctrlAltEndVnc: false,
+ ctrlAltEndSpice: false,
+ preferredConsole: config.defaultUiConsole,
+ smartcardSpice: AppConfiguration.smartcardSpice,
},
}
this.handleCancel = this.handleCancel.bind(this)
@@ -181,22 +210,6 @@ class GlobalSettings extends Component {
),
}))('language'),
- ((name) => ({
- title: msg.sshKey(),
- tooltip: msg.sshKeyTooltip(),
- name,
- body: (
-
- onChange(name)(e.target.value)}
- value={draftValues[name] || ''}
- rows={8}
- />
-
- ),
- }))('sshKey'),
],
},
refreshInterval: {
@@ -255,6 +268,144 @@ class GlobalSettings extends Component {
}))('notificationSnoozeDuration'),
],
},
+ console: {
+ title: msg.console(),
+ fields: [ ],
+ sections: {
+ console: {
+ title: msg.console(),
+ tooltip: msg.globalSettingsTooltip(),
+ fields: [],
+ },
+ preferredConsole: {
+ title: '',
+ fields: [
+ ((name) => ({
+ title: msg.preferredConsole(),
+ tooltip: msg.preferredConsoleTooltip(),
+ name,
+ body: (
+
+ ({
+ id,
+ value,
+ isDefault: id === config.defaultUiConsole,
+ }))
+ }
+ selected={draftValues[name]}
+ onChange={onChange(name)}
+ />
+
+ ),
+ }))('preferredConsole'),
+ ],
+ },
+ vnc: {
+ title: msg.vncOptions(),
+ fields: [
+ ((name) => ({
+ title: msg.fullScreenMode(),
+ name,
+ body: (
+ {
+ onChange(name)(fullScreen)
+ }}
+ />
+ ),
+ }))('fullScreenVnc'),
+ ((name) => ({
+ title: msg.ctrlAltEnd(),
+ tooltip: msg.remapCtrlAltDelete(),
+ name,
+ body: (
+ {
+ onChange(name)(ctrlAltEnd)
+ }}
+ />
+ ),
+ }))('ctrlAltEndVnc'),
+ ],
+ },
+ spice: {
+ title: msg.spiceOptions(),
+ fields: [
+ ((name) => ({
+ title: msg.fullScreenMode(),
+ name,
+ body: (
+ {
+ onChange(name)(fullScreen)
+ }}
+ />
+ ),
+ }))('fullScreenSpice'),
+ ((name) => ({
+ title: msg.ctrlAltEnd(),
+ tooltip: msg.remapCtrlAltDelete(),
+ name,
+ body: (
+ {
+ onChange(name)(ctrlAltEnd)
+ }}
+ />
+ ),
+ }))('ctrlAltEndSpice'),
+ ((name) => ({
+ title: msg.smartcard(),
+ tooltip: msg.smartcardTooltip(),
+ name,
+ body: (
+ {
+ onChange(name)(smartcard)
+ }}
+ />
+ ),
+ }))('smartcardSpice'),
+ ],
+ },
+ serial: {
+ title: msg.serialConsoleOptions(),
+ fields: [
+ ((name) => ({
+ title: msg.sshKey(),
+ tooltip: msg.sshKeyTooltip(),
+ name,
+ body: (
+
+ onChange(name)(e.target.value)}
+ value={draftValues[name] || ''}
+ rows={8}
+ />
+
+ ),
+ }))('sshKey'),
+ ],
+ },
+ },
+
+ },
advancedOptions: {
title: msg.advancedOptions(),
fields: [
@@ -347,6 +498,7 @@ export default connect(
config: {
userName: config.getIn(['user', 'name']),
email: config.getIn(['user', 'email']),
+ defaultUiConsole: config.getIn(['defaultUiConsole']),
},
currentValues: {
sshKey: options.getIn(['ssh', 'key']),
@@ -355,6 +507,12 @@ export default connect(
notificationSnoozeDuration: options.getIn(['localOptions', 'notificationSnoozeDuration']),
refreshInterval: options.getIn(['remoteOptions', 'refreshInterval', 'content']),
persistLocale: options.getIn(['remoteOptions', 'persistLocale', 'content']),
+ fullScreenVnc: options.getIn(['remoteOptions', 'fullScreenVnc', 'content']),
+ fullScreenSpice: options.getIn(['remoteOptions', 'fullScreenSpice', 'content']),
+ ctrlAltEndVnc: options.getIn(['remoteOptions', 'ctrlAltEndVnc', 'content']),
+ ctrlAltEndSpice: options.getIn(['remoteOptions', 'ctrlAltEndSpice', 'content']),
+ preferredConsole: options.getIn(['remoteOptions', 'preferredConsole', 'content'], config.getIn(['defaultUiConsole'])),
+ smartcardSpice: options.getIn(['remoteOptions', 'smartcardSpice', 'content']),
},
lastTransactionId: options.getIn(['lastTransactions', 'global', 'transactionId'], ''),
}),
diff --git a/src/components/VmActions/index.js b/src/components/VmActions/index.js
index e62db6d0b..2711c88a4 100644
--- a/src/components/VmActions/index.js
+++ b/src/components/VmActions/index.js
@@ -128,6 +128,7 @@ class VmActions extends React.Component {
onSuspend,
onRDP,
msg,
+ preferredConsole,
} = this.props
const isPoolVm = !!vm.getIn(['pool', 'id'], false)
const isPool = !!pool && !isPoolVm
@@ -137,7 +138,6 @@ class VmActions extends React.Component {
const vncConsole = vm.get('consoles').find(c => c.get('protocol') === VNC)
const spiceConsole = vm.get('consoles').find(c => c.get('protocol') === SPICE)
const hasRdp = isWindows(vm.getIn(['os', 'type']))
- const defaultUiConsole = config.get('defaultUiConsole')
let consoles = []
if (vncConsole) {
@@ -197,7 +197,7 @@ class VmActions extends React.Component {
}
consoles = consoles
- .map(({ uiConsole, ...props }) => ({ ...props, priority: uiConsole === defaultUiConsole ? 1 : 0 }))
+ .map(({ uiConsole, ...props }) => ({ ...props, priority: uiConsole === preferredConsole ? 1 : 0 }))
.sort((a, b) => b.priority - a.priority)
const actions = [
@@ -391,6 +391,7 @@ VmActions.propTypes = {
onStartVm: PropTypes.func.isRequired,
onRDP: PropTypes.func.isRequired,
msg: PropTypes.object.isRequired,
+ preferredConsole: PropTypes.string,
}
export default withRouter(
@@ -398,6 +399,7 @@ export default withRouter(
(state, { vm }) => ({
isEditable: vm.get('canUserEditVm') && state.clusters.find(cluster => cluster.get('canUserUseCluster')) !== undefined,
config: state.config,
+ preferredConsole: state.options.getIn(['remoteOptions', 'preferredConsole', 'content'], state.config.get('defaultUiConsole')),
}),
(dispatch, { vm, pool }) => ({
onShutdown: () => dispatch(shutdownVm({ vmId: vm.get('id'), force: false })),
diff --git a/src/config.js b/src/config.js
index 9b3aa708a..d78b45672 100644
--- a/src/config.js
+++ b/src/config.js
@@ -16,6 +16,7 @@ const AppConfiguration = {
notificationSnoozeDurationInMinutes: 10,
showNotificationsDefault: true,
persistLocale: true,
+ smartcardSpice: true,
consoleClientResourcesURL: 'https://www.ovirt.org/documentation/admin-guide/virt/console-client-resources/',
cockpitPort: '9090',
@@ -27,7 +28,7 @@ export const DefaultEngineOptions = Object.seal({
MaxNumOfThreadsPerCpu: 8,
MaxNumOfVmCpusPerArch: `{${DEFAULT_ARCH}=1}`,
- SpiceUsbAutoShare: 1,
+ SpiceUsbAutoShare: true,
getUSBFilter: {},
UserSessionTimeOutInterval: 30,
diff --git a/src/ovirtapi/transform.js b/src/ovirtapi/transform.js
index 776d749f3..801d54d7a 100644
--- a/src/ovirtapi/transform.js
+++ b/src/ovirtapi/transform.js
@@ -1034,12 +1034,24 @@ const RemoteUserOptions = {
locale,
refreshInterval,
persistLocale,
+ preferredConsole,
+ fullScreenVnc,
+ ctrlAltEndVnc,
+ fullScreenSpice,
+ ctrlAltEndSpice,
+ smartcardSpice,
} = fromEntries
return {
locale,
refreshInterval,
persistLocale,
+ preferredConsole,
+ fullScreenVnc,
+ ctrlAltEndVnc,
+ fullScreenSpice,
+ ctrlAltEndSpice,
+ smartcardSpice,
}
},
}
@@ -1171,6 +1183,7 @@ const EngineOptionMaxNumOfVmCpusPerArch = {
// Export each transforms individually so they can be consumed individually
//
export {
+ convertBool,
VM,
Pool,
CdRom,
diff --git a/src/ovirtapi/types.js b/src/ovirtapi/types.js
index 072e09342..591839fa3 100644
--- a/src/ovirtapi/types.js
+++ b/src/ovirtapi/types.js
@@ -232,9 +232,15 @@ export type GlobalUserSettingsType = {|
|}
export type RemoteUserOptionsType = {|
- locale: Object,
+ locale?: UserOptionType,
refreshInterval?: UserOptionType,
- persistLocale?: UserOptionType
+ persistLocale?: UserOptionType,
+ preferredConsole?: UserOptionType,
+ fullScreenVnc?: UserOptionType,
+ ctrlAltEndVnc?: UserOptionType,
+ fullScreenSpice?: UserOptionType,
+ ctrlAltEndSpice?: UserOptionType,
+ smartcardSpice?: UserOptionType
|}
export type UserOptionsType = {|
diff --git a/src/reducers/options.js b/src/reducers/options.js
index 3ed17a829..590674ee8 100644
--- a/src/reducers/options.js
+++ b/src/reducers/options.js
@@ -27,6 +27,26 @@ const defaultOptions: UserOptionsType = {
id: undefined,
content: AppConfiguration.schedulerFixedDelayInSeconds,
},
+ fullScreenVnc: {
+ id: undefined,
+ content: false,
+ },
+ ctrlAltEndVnc: {
+ id: undefined,
+ content: false,
+ },
+ fullScreenSpice: {
+ id: undefined,
+ content: false,
+ },
+ ctrlAltEndSpice: {
+ id: undefined,
+ content: false,
+ },
+ smartcardSpice: {
+ id: undefined,
+ content: AppConfiguration.smartcardSpice,
+ },
},
ssh: undefined,
lastTransactions: {},
diff --git a/src/sagas/console/index.js b/src/sagas/console/index.js
index a9ad9b8e2..c55c0a8cb 100644
--- a/src/sagas/console/index.js
+++ b/src/sagas/console/index.js
@@ -62,14 +62,14 @@ export function* downloadVmConsole (action) {
/**
*Download console if type is spice or novnc is running already
*/
- if (data.indexOf('type=spice') > -1 || !isNoVNC) {
- let options = yield select(state => state.options.getIn(['options', 'consoleOptions', vmId]))
- if (!options) {
- console.log('downloadVmConsole() console options not yet present, trying to load from local storage')
- options = yield getConsoleOptions(getConsoleOptionsAction({ vmId }))
- }
-
- data = adjustVVFile({ data, options, usbAutoshare, usbFilter })
+ const isSpice = data.indexOf('type=spice') > -1
+ if (isSpice || !isNoVNC) {
+ const legacyOptions = getLegacyOptions({ vmId })
+ const options = isSpice
+ ? yield getSpiceConsoleOptions({ legacyOptions, usbAutoshare, usbFilter, vmId })
+ : yield getVncOptions({ legacyOptions })
+
+ data = adjustVVFile({ data, options })
fileDownload({ data, fileName: `console.vv`, mimeType: 'application/x-virt-viewer' })
yield put(setConsoleStatus({ vmId, status: DOWNLOAD_CONSOLE }))
} else {
@@ -86,6 +86,50 @@ export function* downloadVmConsole (action) {
}
}
+/**
+ * Legacy options were saved in browser's local storage.
+ * The UI for setting theose options was removed in previous versions.
+ * However there is still a (small) chance that the data is still there.
+ * Note that legacy options are per VM and therefore should overwrite global defaults.
+ */
+function* getLegacyOptions ({ vmId }) {
+ const options = yield select(state => state.options.getIn(['options', 'consoleOptions', vmId]))
+ if (options) {
+ return (options.toJS && options.toJS()) || options
+ }
+ console.log('downloadVmConsole() console options not yet present, trying to load from local storage')
+ yield getConsoleOptions(getConsoleOptionsAction({ vmId }))
+}
+
+function* getSpiceConsoleOptions ({ legacyOptions, usbAutoshare, usbFilter, vmId }) {
+ const smartcardEnabledOnVm = yield select(({ vms }) => vms.getIn(['vms', vmId, 'display', 'smartcardEnabled']))
+ const newOptions = yield select(({ options, vms }) => ({
+ fullscreen: options.getIn(['remoteOptions', 'fullScreenSpice', 'content']),
+ ctrlAltDelToEnd: options.getIn(['remoteOptions', 'ctrlAltEndSpice', 'content']),
+ smartcardEnabled: options.getIn(['remoteOptions', 'smartcardSpice', 'content']),
+ }))
+
+ const merged = {
+ ...newOptions,
+ ...legacyOptions,
+ usbFilter,
+ usbAutoshare,
+ }
+ merged.smartcardEnabled = smartcardEnabledOnVm && merged.smartcardEnabled
+ return merged
+}
+
+function* getVncOptions ({ legacyOptions }) {
+ const newOptions = yield select(({ options }) => ({
+ fullscreen: options.getIn(['remoteOptions', 'fullScreenVnc', 'content']),
+ ctrlAltDelToEnd: options.getIn(['remoteOptions', 'ctrlAltEndVnc', 'content']),
+ }))
+ return {
+ ...newOptions,
+ ...legacyOptions,
+ }
+}
+
/**
* Push a RDP connection file (__console.rdp__) to connect a user to the Windows VM's RDP session
*/
diff --git a/src/sagas/console/vvFileUtils.js b/src/sagas/console/vvFileUtils.js
index f100fb5c7..1d0092b76 100644
--- a/src/sagas/console/vvFileUtils.js
+++ b/src/sagas/console/vvFileUtils.js
@@ -1,15 +1,12 @@
-export function adjustVVFile ({ data, options, usbAutoshare, usbFilter }) {
- // __options__ can either be a plain JS object or ImmutableJS Map
- console.log('adjustVVFile options:', options)
-
- if (options && ((options.get && options.get('fullscreen')) || options.fullscreen)) {
+export function adjustVVFile ({ data = '', options: { fullscreen, ctrlAltDelToEnd, smartcardEnabled, usbAutoshare, usbFilter } = {} } = {}) {
+ if (fullscreen) {
data = data.replace(/^fullscreen=0/mg, 'fullscreen=1')
}
const pattern = /^secure-attention=.*$/mg
let text = 'secure-attention=ctrl+alt+del'
- if (options && ((options.get && options.get('ctrlAltDelToEnd')) || options.ctrlAltDelToEnd)) {
+ if (ctrlAltDelToEnd) {
text = 'secure-attention=ctrl+alt+end'
}
if (data.match(pattern)) {
@@ -20,20 +17,14 @@ export function adjustVVFile ({ data, options, usbAutoshare, usbFilter }) {
data = data.replace(/^\[virt-viewer\]$/mg, `[virt-viewer]\n${text}`) // ending \n is already there
}
- const isSpice = data.indexOf('type=spice') > -1
-
- if (usbFilter && isSpice) {
+ if (usbFilter) {
data = data.replace(/^\[virt-viewer\]$/mg, `[virt-viewer]\nusb-filter=${usbFilter}`)
data = data.replace(/^usb-filter=null\n/mg, '') // remove an extra 'usb-filter=null' line if present
}
- if (options && isSpice) {
- const smartcardEnabled = options.get ? options.get('smartcardEnabled') : options.smartcardEnabled
- data = data.replace(/^enable-smartcard=[01]$/mg, `enable-smartcard=${smartcardEnabled ? 1 : 0}`)
- }
+ data = data.replace(/^enable-smartcard=[01]$/mg, `enable-smartcard=${smartcardEnabled ? 1 : 0}`)
- // make USB Auto-Share to be enabled/disabled in VM Portal according to the SpiceUsbAutoShare config value
- data = data.replace(/^enable-usb-autoshare=.*$/mg, `enable-usb-autoshare=${usbAutoshare.toString() === 'true' ? 1 : 0}`)
+ data = data.replace(/^enable-usb-autoshare=.*$/mg, `enable-usb-autoshare=${usbAutoshare ? 1 : 0}`)
console.log('adjustVVFile data after adjustment:', data)
return data
diff --git a/src/sagas/console/vvFileUtils.test.js b/src/sagas/console/vvFileUtils.test.js
new file mode 100644
index 000000000..8518a9d84
--- /dev/null
+++ b/src/sagas/console/vvFileUtils.test.js
@@ -0,0 +1,43 @@
+import { adjustVVFile } from './vvFileUtils'
+
+describe('test error handling', function () {
+ it('should return empty string when no data', function () {
+ expect(adjustVVFile()).toEqual('')
+ })
+ it('should add secure attention when missing', function() {
+ const data = '[virt-viewer]\ntype=vnc\n'
+ expect(adjustVVFile({data})).toEqual('[virt-viewer]\nsecure-attention=ctrl+alt+del\ntype=vnc\n')
+ })
+})
+
+describe('test flags one-by-one', function () {
+ it('should set fullscreen', function () {
+ const data = '[virt-viewer]\nfullscreen=0\nsecure-attention=ctrl+alt+del\n'
+ const options = {fullscreen: true}
+ expect(adjustVVFile({data, options},)).toEqual('[virt-viewer]\nfullscreen=1\nsecure-attention=ctrl+alt+del\n')
+ })
+
+ it('should set secure-attention', function () {
+ const data = '[virt-viewer]\nsecure-attention=ctrl+alt+del\n'
+ const options = {ctrlAltDelToEnd: true}
+ expect(adjustVVFile({data, options},)).toEqual('[virt-viewer]\nsecure-attention=ctrl+alt+end\n')
+ })
+
+ it('should set usb filter', function () {
+ const data = '[virt-viewer]\nusb-filter=null\nsecure-attention=ctrl+alt+del\n'
+ const options = {usbFilter: '1,1,1,1'}
+ expect(adjustVVFile({data, options},)).toEqual('[virt-viewer]\nusb-filter=1,1,1,1\nsecure-attention=ctrl+alt+del\n')
+ })
+
+ it('should set enable-smartcard', function () {
+ const data = '[virt-viewer]\nenable-smartcard=0\nsecure-attention=ctrl+alt+del\n'
+ const options = {smartcardEnabled: true}
+ expect(adjustVVFile({data, options},)).toEqual('[virt-viewer]\nenable-smartcard=1\nsecure-attention=ctrl+alt+del\n')
+ })
+
+ it('should set enable-usb-autoshare', function () {
+ const data = '[virt-viewer]\nenable-usb-autoshare=0\nsecure-attention=ctrl+alt+del\n'
+ const options = {usbAutoshare: true}
+ expect(adjustVVFile({data, options},)).toEqual('[virt-viewer]\nenable-usb-autoshare=1\nsecure-attention=ctrl+alt+del\n')
+ })
+})
\ No newline at end of file
diff --git a/src/sagas/options.js b/src/sagas/options.js
index 341023f21..b1cc9512b 100644
--- a/src/sagas/options.js
+++ b/src/sagas/options.js
@@ -166,18 +166,38 @@ function* saveLocale ([ localePropName, submittedLocale ]: any, persistLocale: b
return {}
}
-function* saveGlobalOptions ({ payload: { sshKey, showNotifications, notificationSnoozeDuration, language, refreshInterval, persistLocale }, meta: { transactionId } }: SaveGlobalOptionsActionType): Generator {
- const { ssh, locale, refresh, shouldPersistLocale } = yield all({
+function* saveGlobalOptions ({ payload: {
+ sshKey,
+ showNotifications,
+ notificationSnoozeDuration,
+ language,
+ refreshInterval,
+ persistLocale,
+ preferredConsole,
+ fullScreenVnc,
+ ctrlAltEndVnc,
+ fullScreenSpice,
+ ctrlAltEndSpice,
+ smartcardSpice,
+}, meta: { transactionId } }: SaveGlobalOptionsActionType): Generator {
+ const { ssh, locale, shouldPersistLocale, ...standardRemoteOptions } = yield all({
ssh: call(saveSSHKey, ...Object.entries({ sshKey })),
locale: call(saveLocale, ...Object.entries({ locale: language }), persistLocale),
shouldPersistLocale: call(saveRemoteOption, ...Object.entries({ persistLocale })),
refresh: call(saveRemoteOption, ...Object.entries({ refreshInterval })),
+ preferredConsole: call(saveRemoteOption, ...Object.entries({ preferredConsole })),
+ fullScreenVnc: call(saveRemoteOption, ...Object.entries({ fullScreenVnc })),
+ ctrlAltEndVnc: call(saveRemoteOption, ...Object.entries({ ctrlAltEndVnc })),
+ fullScreenSpice: call(saveRemoteOption, ...Object.entries({ fullScreenSpice })),
+ ctrlAltEndSpice: call(saveRemoteOption, ...Object.entries({ ctrlAltEndSpice })),
+ smartcardSpice: call(saveRemoteOption, ...Object.entries({ smartcardSpice })),
})
- if (!refresh.error && refresh.change && !refresh.sameAsCurrent) {
- const { name, value } = refresh.data
- yield put(A.setOption({ key: [ 'remoteOptions', name ], value }))
- }
+ yield all(
+ ((Object.values(standardRemoteOptions): Array): Array)
+ .filter(result => !result.error && result.change && !result.sameAsCurrent)
+ .map(({ data: { name, value } }) => put(A.setOption({ key: [ 'remoteOptions', name ], value })))
+ )
if (!shouldPersistLocale.error && shouldPersistLocale.change && !shouldPersistLocale.sameAsCurrent) {
const { name, value } = shouldPersistLocale.data
diff --git a/src/sagas/server-configs.js b/src/sagas/server-configs.js
index 9b9c09c92..64869a8e2 100644
--- a/src/sagas/server-configs.js
+++ b/src/sagas/server-configs.js
@@ -46,7 +46,7 @@ export function* fetchServerConfiguredValues () {
}))
if (eo.usbAutoShare) {
- yield put(setSpiceUsbAutoShare(eo.usbAutoShare))
+ yield put(setSpiceUsbAutoShare(Transforms.convertBool(eo.usbAutoShare)))
}
if (eo.usbFilter) {