diff --git a/src/fireedge/src/client/components/Forms/Vm/AttachNicForm/Steps/AdvancedOptions/schema.js b/src/fireedge/src/client/components/Forms/Vm/AttachNicForm/Steps/AdvancedOptions/schema.js index e1056cbcda3..3810edda604 100644 --- a/src/fireedge/src/client/components/Forms/Vm/AttachNicForm/Steps/AdvancedOptions/schema.js +++ b/src/fireedge/src/client/components/Forms/Vm/AttachNicForm/Steps/AdvancedOptions/schema.js @@ -42,6 +42,145 @@ const GENERAL_FIELDS = ({ nics = [] } = {}) => label: T.RdpConnection, type: INPUT_TYPES.SWITCH, validation: boolean().yesOrNo(), + grid: { md: 12 }, + }, + { + name: 'RDP_SERVER_LAYOUT', + label: T.RdpLayout, + type: INPUT_TYPES.AUTOCOMPLETE, + dependOf: 'RDP', + values: [ + { text: T.PortugueseBr, value: 'pt-br-qwerty' }, + { text: T.EnglishGB, value: 'en-gb-qwerty' }, + { text: T.EnglishUS, value: 'en-us-qwerty' }, + { text: T.French, value: 'fr-fr-azerty' }, + { text: T.FrenchBe, value: 'fr-be-azerty' }, + { text: T.FrenchSw, value: 'fr-ch-qwertz' }, + { text: T.German, value: 'de-de-qwertz' }, + { text: T.GermanSw, value: 'de-ch-qwertz' }, + { text: T.Hungarian, value: 'hu-hu-qwertz' }, + { text: T.Italian, value: 'it-it-qwerty' }, + { text: T.Japanese, value: 'ja-jp-qwerty' }, + { text: T.SpanishEs, value: 'es-es-qwerty' }, + { text: T.SpanishLatam, value: 'es-latam-qwerty' }, + { text: T.Swedish, value: 'sv-se-qwerty' }, + { text: T.Turkish, value: 'tr-tr-qwerty' }, + { text: T.Other, value: 'failsafe' }, + ], + validation: string().trim().notRequired().default(undefined), + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + grid: { sm: 6 }, + }, + { + name: 'RDP_RESIZE_METHOD', + label: T.RdpRizeMethod, + type: INPUT_TYPES.SELECT, + dependOf: 'RDP', + values: [ + { text: T.DisplayUpdate, value: 'display-update' }, + { text: T.Reconnect, value: 'reconnect' }, + ], + validation: string().trim().notRequired().default('display-update'), + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + grid: { sm: 6 }, + }, + { + name: 'RDP_DISABLE_AUDIO', + label: T.DisableAudio, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_ENABLE_AUDIO_INPUT', + label: T.EnableAudioInput, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_ENABLE_WALLPAPER', + label: T.EnableWallpaper, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_ENABLE_THEMING', + label: T.EnableTheming, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_ENABLE_FONT_SMOOTHING', + label: T.EnableFontSmoothing, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_ENABLE_FULL_WINDOW_DRAG', + label: T.EnableFullWindowDrag, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_ENABLE_DESKTOP_COMPOSITION', + label: T.EnableDesktopComposition, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_ENABLE_MENU_ANIMATIONS', + label: T.EnableMenuAnimations, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_DISABLE_BITMAP_CACHING', + label: T.DisableBitmapCaching, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_DISABLE_OFFSCREEN_CACHING', + label: T.DisableOffscreenCaching, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), + grid: { sm: 6 }, + }, + { + name: 'RDP_DISABLE_GLYPH_CACHING', + label: T.DisableGlyphCaching, + type: INPUT_TYPES.SWITCH, + dependOf: 'RDP', + htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, + validation: boolean().yesOrNo(), grid: { sm: 6 }, }, { @@ -49,7 +188,7 @@ const GENERAL_FIELDS = ({ nics = [] } = {}) => label: T.SshConnection, type: INPUT_TYPES.SWITCH, validation: boolean().yesOrNo(), - grid: { sm: 6 }, + grid: { md: 12 }, }, !!nics?.length && { name: 'PARENT', diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/graphicsSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/graphicsSchema.js index 03e558ceaef..518c4cf753a 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/graphicsSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/graphicsSchema.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { string, boolean, ObjectSchema } from 'yup' +import { string, boolean, ObjectSchema, lazy } from 'yup' import { Field, @@ -24,6 +24,44 @@ import { import { T, INPUT_TYPES, HYPERVISORS } from 'client/constants' const { vcenter, lxc, kvm } = HYPERVISORS +const CUSTOM_KEYMAP_VALUE = 'custom' +const KEYMAP_VALUES = { + ar: T.Arabic, + hr: T.Croatian, + cz: T.Czech, + da: T.Danish, + nl: T.Dutch, + 'en-gb': T.EnglishGB, + 'en-us': T.EnglishUS, + et: T.Estonian, + fo: T.Faroese, + fi: T.Finnish, + fr: T.French, + 'fr-be': T.FrenchBe, + 'fr-ca': T.FrenchCa, + bepo: T.FrenchBEPO, + 'fr-ch': T.FrenchSw, + de: T.German, + 'de-ch': T.GermanSw, + hu: T.Hungarian, + is: T.Icelandic, + it: T.Italian, + ja: T.Japanese, + lv: T.Latvian, + lt: T.Lithuanian, + mk: T.Macedonian, + no: T.Norwegian, + pl: T.Polish, + pt: T.Portuguese, + 'pt-br': T.PortugueseBr, + ru: T.Russian, + sl: T.Slovenian, + es: T.SpanishEs, + sv: T.Swedish, + th: T.Thai, + tr: T.Turkish, + custom: T.Custom, +} /** @type {Field} Type field */ export const TYPE = { @@ -79,14 +117,57 @@ export const PORT = { export const KEYMAP = { name: 'GRAPHICS.KEYMAP', label: T.Keymap, - type: INPUT_TYPES.TEXT, + type: INPUT_TYPES.AUTOCOMPLETE, dependOf: TYPE.name, + values: arrayToOptions(Object.entries(KEYMAP_VALUES), { + addEmpty: false, + getText: ([_, label]) => label, + getValue: ([keymap]) => keymap, + }), htmlType: (noneType) => !noneType && INPUT_TYPES.HIDDEN, validation: string() .trim() .notRequired() - .default(() => undefined), - fieldProps: { placeholder: 'en-us' }, + .transform((value) => + value && KEYMAP_VALUES[value] ? value : CUSTOM_KEYMAP_VALUE + ) + .default(() => undefined) + .afterSubmit((value, { context }) => + value === CUSTOM_KEYMAP_VALUE + ? context.extra.GRAPHICS.CUSTOM_KEYMAP + : value + ), +} + +/** @type {Field} Custom keymap field */ +export const CUSTOM_KEYMAP = { + name: 'GRAPHICS.CUSTOM_KEYMAP', + label: T.Keymap, + type: INPUT_TYPES.TEXT, + dependOf: KEYMAP.name, + htmlType: (selectedKeymap) => + (!selectedKeymap || + selectedKeymap?.toLowerCase() !== CUSTOM_KEYMAP_VALUE) && + INPUT_TYPES.HIDDEN, + validation: lazy((_, { context }) => + string() + .trim() + .when(`$extra.${KEYMAP.name}`, (keymap, schema) => + keymap === CUSTOM_KEYMAP_VALUE + ? schema.required() + : schema.notRequired() + ) + .default(() => { + const keymapFromTemplate = context.extra?.GRAPHICS?.KEYMAP + + return KEYMAP_VALUES[keymapFromTemplate] + ? undefined + : keymapFromTemplate + }) + // Modification type is not required in template + .afterSubmit(() => undefined) + ), + grid: { md: 12 }, } /** @type {Field} Password random field */ @@ -136,7 +217,7 @@ export const COMMAND = { */ export const GRAPHICS_FIELDS = (hypervisor) => filterFieldsByHypervisor( - [TYPE, LISTEN, PORT, KEYMAP, PASSWD, RANDOM_PASSWD, COMMAND], + [TYPE, LISTEN, PORT, KEYMAP, CUSTOM_KEYMAP, PASSWD, RANDOM_PASSWD, COMMAND], hypervisor ) diff --git a/src/fireedge/src/client/constants/host.js b/src/fireedge/src/client/constants/host.js index 979053abaed..da563d332cb 100644 --- a/src/fireedge/src/client/constants/host.js +++ b/src/fireedge/src/client/constants/host.js @@ -201,7 +201,7 @@ export const PIN_POLICY = { /** @enum {string} Custom Hypervisor */ export const CUSTOM_HOST_HYPERVISOR = { NAME: 'Custom', - SUNSTONE_NAME: T.CustomHypervisor, + SUNSTONE_NAME: T.Custom, } /** diff --git a/src/fireedge/src/client/constants/translates.js b/src/fireedge/src/client/constants/translates.js index 799d6bed5f4..ddf505bd14b 100644 --- a/src/fireedge/src/client/constants/translates.js +++ b/src/fireedge/src/client/constants/translates.js @@ -456,6 +456,20 @@ module.exports = { PartOf: 'Part of', GuacamoleState: 'Guacamole State', VMRCState: 'VMRC State', + RdpLayout: 'RDP keyboard layout', + RdpRizeMethod: 'RDP rezise method', + DisableAudio: 'Disable audio', + EnableAudioInput: 'Enable audio input', + EnableWallpaper: 'Render desktop wallpaper', + EnableTheming: 'Render windows theming control', + EnableFontSmoothing: 'Enable font smoothing', + EnableFullWindowDrag: 'Enable full window drag', + EnableDesktopComposition: 'Enable desktop composition', + EnableMenuAnimations: 'Enable menu animations', + DisableBitmapCaching: 'Disable bitmap caching', + DisableOffscreenCaching: 'Disable offscreen caching', + DisableGlyphCaching: 'Disable glyph caching', + Timezone: 'Timezone', /* VM schema - info */ VmName: 'VM name', UserTemplate: 'User Template', @@ -541,7 +555,7 @@ module.exports = { /* VM Template schema */ /* VM Template schema - general */ - CustomHypervisor: 'Custom', + Custom: 'Custom', CustomVariables: 'Custom Variables', CustomAttributes: 'Custom Attributes', Hypervisor: 'Hypervisor', @@ -750,6 +764,45 @@ module.exports = { GenerateRandomPassword: 'Generate random password', Command: 'Command', Bus: 'BUS', + ConnectionAttributes: '%s connection attributes', + /* VM Template schema - Input/Output - graphics - Remote Connections Keymaps */ + Arabic: 'Arabic', + Croatian: 'Croatian', + Czech: 'Czech', + Danish: 'Danish', + Dutch: 'Dutch', + EnglishGB: 'English (United Kingdom)', + EnglishUS: 'English (United States)', + Estonian: 'Estonian', + Faroese: 'Faroese', + Finnish: 'Finnish', + French: 'French', + FrenchBe: 'French (Belgium)', + FrenchCa: 'French (Canada)', + FrenchBEPO: 'French (BEPO)', + FrenchSw: 'French (Switzerland)', + German: 'German', + GermanSw: 'German (Switzerland)', + Hungarian: 'Hungarian', + Icelandic: 'Icelandic', + Italian: 'Italian', + Japanese: 'Japanese', + Latvian: 'Latvian', + Lithuanian: 'Lithuanian', + Macedonian: 'Macedonian', + Norwegian: 'Norwegian', + Polish: 'Polish', + Portuguese: 'Portuguese', + PortugueseBr: 'Portuguese (Brazil)', + Russian: 'Russian', + Slovenian: 'Slovenian', + SpanishEs: 'Spanish (Spain)', + SpanishLatam: 'Spanish (Latin American)', + Swedish: 'Swedish', + Thai: 'Thai', + Turkish: 'Turkish', + /* VM Template schema - Input/Output - graphics - Remote connections */ + DisplayUpdate: 'Display update', /* VM Template schema - NUMA */ NumaTopology: 'NUMA Topology', NumaTopologyConcept: diff --git a/src/fireedge/src/server/routes/api/vm/functions.js b/src/fireedge/src/server/routes/api/vm/functions.js index 09ea699e7c0..6e708203e22 100644 --- a/src/fireedge/src/server/routes/api/vm/functions.js +++ b/src/fireedge/src/server/routes/api/vm/functions.js @@ -265,7 +265,30 @@ const getRdpSettings = (vmInfo) => { config.port = vmInfo.TEMPLATE?.CONTEXT?.RDP_PORT ?? '3389' config.username = vmInfo.TEMPLATE?.CONTEXT?.USERNAME config.password = vmInfo.TEMPLATE?.CONTEXT?.PASSWORD - config['resize-method'] = 'display-update' + config['server-layout'] = nicWithRdp?.RDP_SERVER_LAYOUT + config['resize-method'] = nicWithRdp?.RDP_RESIZE_METHOD ?? 'display-update' + config['disable-audio'] = + nicWithRdp?.RDP_DISABLE_AUDIO?.toLowerCase() === 'yes' + config['enable-audio-input'] = + nicWithRdp?.RDP_ENABLE_AUDIO_INPUT?.toLowerCase() === 'yes' + config['enable-wallpaper'] = + nicWithRdp?.RDP_ENABLE_WALLPAPER?.toLowerCase() === 'yes' + config['enable-theming'] = + nicWithRdp?.RDP_ENABLE_THEMING?.toLowerCase() === 'yes' + config['enable-font-smoothing'] = + nicWithRdp?.RDP_ENABLE_FONT_SMOOTHING?.toLowerCase() === 'yes' + config['enable-full-window-drag'] = + nicWithRdp?.RDP_ENABLE_FULL_WINDOW_DRAG?.toLowerCase() === 'yes' + config['enable-desktop-composition'] = + nicWithRdp?.RDP_ENABLE_DESKTOP_COMPOSITION?.toLowerCase() === 'yes' + config['enable-menu-animations'] = + nicWithRdp?.RDP_ENABLE_MENU_ANIMATIONS?.toLowerCase() === 'yes' + config['disable-bitmap-caching'] = + nicWithRdp?.RDP_DISABLE_BITMAP_CACHING?.toLowerCase() === 'yes' + config['disable-offscreen-caching'] = + nicWithRdp?.RDP_DISABLE_OFFSCREEN_CACHING?.toLowerCase() === 'yes' + config['disable-glyph-caching'] = + nicWithRdp?.RDP_DISABLE_GLYPH_CACHING?.toLowerCase() === 'yes' if (config.username && config.password) config.security = 'nla'