mirror of https://github.com/apache/cloudstack.git
noVNC: support Spanish Latin American keyboard on VMware (#12484)
* noVNC: support Spanish Latin American keyboard * Update server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
This commit is contained in:
parent
30d306622a
commit
b869913529
|
|
@ -188,7 +188,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
|
|||
@Parameter(name = ApiConstants.MAC_ADDRESS, type = CommandType.STRING, description = "the mac address for default vm's network")
|
||||
private String macAddress;
|
||||
|
||||
@Parameter(name = ApiConstants.KEYBOARD, type = CommandType.STRING, description = "an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us")
|
||||
@Parameter(name = ApiConstants.KEYBOARD, type = CommandType.STRING, description = "an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,es-latam,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us")
|
||||
private String keyboard;
|
||||
|
||||
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Deploy vm for the project")
|
||||
|
|
|
|||
|
|
@ -340,6 +340,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
|||
@Param(description = "List of read-only Instance details as comma separated string.", since = "4.16.0")
|
||||
private String readOnlyDetails;
|
||||
|
||||
@SerializedName("alloweddetails")
|
||||
@Param(description = "List of allowed Vm details as comma separated string if VM instance settings are read from OVA.", since = "4.22.1")
|
||||
private String allowedDetails;
|
||||
|
||||
@SerializedName(ApiConstants.SSH_KEYPAIRS)
|
||||
@Param(description = "SSH key-pairs")
|
||||
private String keyPairNames;
|
||||
|
|
@ -1091,6 +1095,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
|||
this.readOnlyDetails = readOnlyDetails;
|
||||
}
|
||||
|
||||
public void setAllowedDetails(String allowedDetails) {
|
||||
this.allowedDetails = allowedDetails;
|
||||
}
|
||||
|
||||
public void setOsTypeId(String osTypeId) {
|
||||
this.osTypeId = osTypeId;
|
||||
}
|
||||
|
|
@ -1115,6 +1123,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
|||
return readOnlyDetails;
|
||||
}
|
||||
|
||||
public String getAllowedDetails() {
|
||||
return allowedDetails;
|
||||
}
|
||||
|
||||
public Boolean getDynamicallyScalable() {
|
||||
return isDynamicallyScalable;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5379,7 +5379,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||
|
||||
options.put(ApiConstants.BootType.UEFI.toString(), Arrays.asList(ApiConstants.BootMode.LEGACY.toString(),
|
||||
ApiConstants.BootMode.SECURE.toString()));
|
||||
options.put(VmDetailConstants.KEYBOARD, Arrays.asList("uk", "us", "jp", "fr"));
|
||||
options.put(VmDetailConstants.KEYBOARD, Arrays.asList("uk", "us", "jp", "fr", "es-latam"));
|
||||
options.put(VmDetailConstants.CPU_CORE_PER_SOCKET, Collections.emptyList());
|
||||
options.put(VmDetailConstants.ROOT_DISK_SIZE, Collections.emptyList());
|
||||
|
||||
|
|
|
|||
|
|
@ -69,9 +69,11 @@ import com.cloud.service.ServiceOfferingDetailsVO;
|
|||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.GuestOS;
|
||||
import com.cloud.storage.Storage.TemplateType;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.VnfTemplateDetailVO;
|
||||
import com.cloud.storage.VnfTemplateNicVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||
import com.cloud.user.Account;
|
||||
|
|
@ -124,6 +126,8 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
|||
private ServiceOfferingDao serviceOfferingDao;
|
||||
@Inject
|
||||
private VgpuProfileDao vgpuProfileDao;
|
||||
@Inject
|
||||
VMTemplateDao vmTemplateDao;
|
||||
|
||||
private final SearchBuilder<UserVmJoinVO> VmDetailSearch;
|
||||
private final SearchBuilder<UserVmJoinVO> activeVmByIsoSearch;
|
||||
|
|
@ -465,6 +469,10 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
|||
if (caller.getType() != Account.Type.ADMIN) {
|
||||
userVmResponse.setReadOnlyDetails(QueryService.UserVMReadOnlyDetails.value());
|
||||
}
|
||||
VMTemplateVO template = vmTemplateDao.findByIdIncludingRemoved(userVm.getTemplateId());
|
||||
if (template != null && template.isDeployAsIs() && UserVmManager.VmwareAdditionalDetailsFromOvaEnabled.valueIn(userVm.getDataCenterId())) {
|
||||
userVmResponse.setAllowedDetails(UserVmManager.VmwareAllowedAdditionalDetailsFromOva.valueIn(userVm.getDataCenterId()));
|
||||
}
|
||||
}
|
||||
|
||||
userVmResponse.setObjectName(objectName);
|
||||
|
|
|
|||
|
|
@ -99,6 +99,15 @@ public interface UserVmManager extends UserVmService {
|
|||
ConfigKey.Scope.Account);
|
||||
|
||||
|
||||
ConfigKey<Boolean> VmwareAdditionalDetailsFromOvaEnabled = new ConfigKey<Boolean>("Advanced", Boolean.class,
|
||||
"vmware.additional.details.from.ova.enabled", "false",
|
||||
"If true, allow users to add additional VM settings if VM instance settings are read from OVA.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
ConfigKey<String> VmwareAllowedAdditionalDetailsFromOva = new ConfigKey<>(String.class,
|
||||
"vmware.allowed.additional.details.from.ova", "Advanced", "",
|
||||
"Comma separated list of allowed additional VM settings if VM instance settings are read from OVA.",
|
||||
true, ConfigKey.Scope.Zone, null, null, null, null, null, ConfigKey.Kind.CSV, null);
|
||||
|
||||
static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
|
||||
|
||||
public static final String CKS_NODE = "cksnode";
|
||||
|
|
|
|||
|
|
@ -2886,11 +2886,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
|
||||
UserVmVO vmInstance = _vmDao.findById(cmd.getId());
|
||||
VMTemplateVO template = _templateDao.findById(vmInstance.getTemplateId());
|
||||
if (MapUtils.isNotEmpty(details) || cmd.isCleanupDetails()) {
|
||||
if (template != null && template.isDeployAsIs()) {
|
||||
throw new CloudRuntimeException("Detail settings are read from OVA, it cannot be changed by API call.");
|
||||
}
|
||||
}
|
||||
|
||||
UserVmVO userVm = _vmDao.findById(cmd.getId());
|
||||
if (userVm != null && UserVmManager.SHAREDFSVM.equals(userVm.getUserVmType())) {
|
||||
throw new InvalidParameterValueException("Operation not supported on Shared FileSystem Instance");
|
||||
|
|
@ -2920,6 +2916,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
.collect(Collectors.toList());
|
||||
List<VMInstanceDetailVO> existingDetails = vmInstanceDetailsDao.listDetails(id);
|
||||
if (cleanupDetails){
|
||||
if (template != null && template.isDeployAsIs()) {
|
||||
throw new InvalidParameterValueException("Detail settings are read from OVA, it cannot be cleaned up by API call.");
|
||||
}
|
||||
if (caller != null && caller.getType() == Account.Type.ADMIN) {
|
||||
for (final VMInstanceDetailVO detail : existingDetails) {
|
||||
if (detail != null && detail.isDisplay() && !isExtraConfig(detail.getName())) {
|
||||
|
|
@ -2948,6 +2947,23 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
throw new InvalidParameterValueException("'extraconfig' should not be included in details as key");
|
||||
}
|
||||
|
||||
if (template != null && template.isDeployAsIs()) {
|
||||
final List<String> vmwareAllowedDetailsFromOva = VmwareAdditionalDetailsFromOvaEnabled.valueIn(vmInstance.getDataCenterId()) ?
|
||||
Stream.of(VmwareAllowedAdditionalDetailsFromOva.valueIn(vmInstance.getDataCenterId()).split(","))
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toList()) : List.of();
|
||||
for (String detailKey : details.keySet()) {
|
||||
if (vmwareAllowedDetailsFromOva.contains(detailKey)) {
|
||||
continue;
|
||||
}
|
||||
VMInstanceDetailVO detailVO = existingDetails.stream().filter(d -> Objects.equals(d.getName(), detailKey)).findFirst().orElse(null);
|
||||
if (detailVO != null && ObjectUtils.allNotNull(detailVO.getValue(), details.get(detailKey)) && detailVO.getValue().equals(details.get(detailKey))) {
|
||||
continue;
|
||||
}
|
||||
throw new InvalidParameterValueException("Detail settings are read from OVA, it cannot be changed by API call.");
|
||||
}
|
||||
}
|
||||
|
||||
details.entrySet().removeIf(detail -> isExtraConfig(detail.getKey()));
|
||||
|
||||
if (caller != null && caller.getType() != Account.Type.ADMIN) {
|
||||
|
|
@ -9342,7 +9358,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowDiskOfferingChangeDuringScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax,
|
||||
VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers, AllowDeployVmIfGivenHostFails, EnableAdditionalVmConfig, DisplayVMOVFProperties,
|
||||
KvmAdditionalConfigAllowList, XenServerAdditionalConfigAllowList, VmwareAdditionalConfigAllowList, DestroyRootVolumeOnVmDestruction,
|
||||
EnforceStrictResourceLimitHostTagCheck, StrictHostTags, AllowUserForceStopVm, VmDistinctHostNameScope};
|
||||
EnforceStrictResourceLimitHostTagCheck, StrictHostTags, AllowUserForceStopVm, VmDistinctHostNameScope,
|
||||
VmwareAdditionalDetailsFromOvaEnabled, VmwareAllowedAdditionalDetailsFromOva};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import static org.mockito.MockitoAnnotations.openMocks;
|
|||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
|
|
@ -78,6 +79,9 @@ public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseT
|
|||
@Mock
|
||||
private VnfTemplateDetailsDao vnfTemplateDetailsDao;
|
||||
|
||||
@Mock
|
||||
private VMTemplateDao vmTemplateDao;
|
||||
|
||||
private UserVmJoinVO userVm = new UserVmJoinVO();
|
||||
private UserVmResponse userVmResponse = new UserVmResponse();
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import ZRLEDecoder from "./decoders/zrle.js";
|
|||
import JPEGDecoder from "./decoders/jpeg.js";
|
||||
import H264Decoder from "./decoders/h264.js";
|
||||
import SCANCODES_JP from "../keymaps/keymap-ja-atset1.js"
|
||||
import SCANCODES_ES_LATAM from "../keymaps/keymap-es-latam-atset1.js"
|
||||
|
||||
// How many seconds to wait for a disconnect to finish
|
||||
const DISCONNECT_TIMEOUT = 3;
|
||||
|
|
@ -127,6 +128,8 @@ export default class RFB extends EventTargetMixin {
|
|||
this._scancodes = {};
|
||||
if (this._language === "jp") {
|
||||
this._scancodes = SCANCODES_JP;
|
||||
} else if (this._language === "es-latam") {
|
||||
this._scancodes = SCANCODES_ES_LATAM;
|
||||
}
|
||||
|
||||
// Internal state
|
||||
|
|
@ -197,6 +200,7 @@ export default class RFB extends EventTargetMixin {
|
|||
// Keys
|
||||
this._shiftPressed = false;
|
||||
this._shiftKey = KeyTable.XK_Shift_L;
|
||||
this._altgrPressed = false;
|
||||
|
||||
// Mouse state
|
||||
this._mousePos = {};
|
||||
|
|
@ -531,6 +535,10 @@ export default class RFB extends EventTargetMixin {
|
|||
this._shiftKey = down ? keysym : KeyTable.XK_Shift_L;
|
||||
}
|
||||
|
||||
if (keysym === KeyTable.XK_Alt_R) {
|
||||
this._altgrPressed = down;
|
||||
}
|
||||
|
||||
if (this._qemuExtKeyEventSupported && scancode) {
|
||||
// 0 is NoSymbol
|
||||
keysym = keysym || 0;
|
||||
|
|
@ -538,31 +546,10 @@ export default class RFB extends EventTargetMixin {
|
|||
Log.Info("Sending key (" + (down ? "down" : "up") + "): keysym " + keysym + ", scancode " + scancode);
|
||||
|
||||
RFB.messages.QEMUExtendedKeyEvent(this._sock, keysym, down, scancode);
|
||||
} else if (Object.keys(this._scancodes).length > 0) {
|
||||
let vscancode = this._scancodes[keysym]
|
||||
if (vscancode) {
|
||||
let shifted = vscancode.includes("shift");
|
||||
let vscancode_int = parseInt(vscancode);
|
||||
let isLetter = (keysym >= 65 && keysym <=90) || (keysym >=97 && keysym <=122);
|
||||
if (shifted && ! this._shiftPressed && ! isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
}
|
||||
if (! shifted && this._shiftPressed && ! isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
RFB.messages.VMwareExtendedKeyEvent(this._sock, keysym, down, vscancode_int);
|
||||
if (shifted && ! this._shiftPressed && ! isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
if (! shifted && this._shiftPressed && ! isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
}
|
||||
} else {
|
||||
if (this._language === "jp" && keysym === 65328) {
|
||||
keysym = 65509; // Caps lock
|
||||
}
|
||||
RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);
|
||||
}
|
||||
} else if (Object.keys(this._scancodes).length > 0 && this._language === "jp") {
|
||||
this.sendKeyWithJapaneseKeyboard(keysym, down)
|
||||
} else if (Object.keys(this._scancodes).length > 0 && this._language === "es-latam") {
|
||||
this.sendKeyWithSpanishLatamKeyboard(keysym, down)
|
||||
} else {
|
||||
if (!keysym) {
|
||||
return;
|
||||
|
|
@ -572,6 +559,93 @@ export default class RFB extends EventTargetMixin {
|
|||
}
|
||||
}
|
||||
|
||||
sendKeyWithJapaneseKeyboard(keysym, down) {
|
||||
let vscancode = this._scancodes[keysym]
|
||||
if (vscancode) {
|
||||
let shifted = vscancode.includes("shift");
|
||||
let vscancode_int = parseInt(vscancode);
|
||||
let isLetter = (keysym >= 65 && keysym <= 90) || (keysym >= 97 && keysym <= 122);
|
||||
if (shifted && !this._shiftPressed && !isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
}
|
||||
if (!shifted && this._shiftPressed && !isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
RFB.messages.VMwareExtendedKeyEvent(this._sock, keysym, down, vscancode_int);
|
||||
if (shifted && !this._shiftPressed && !isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
if (!shifted && this._shiftPressed && !isLetter) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
}
|
||||
} else {
|
||||
if (keysym === 65328) {
|
||||
keysym = 65509; // Caps lock
|
||||
}
|
||||
RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
sendKeyWithSpanishLatamKeyboard(keysym, down) {
|
||||
const VSCODE_ACUTE_LATAM = 26; // The ASCII code of acute is 180
|
||||
let vscancode = this._scancodes[keysym]
|
||||
if (vscancode) {
|
||||
let shifted = vscancode.includes("shift");
|
||||
let altgr = vscancode.includes("altgr");
|
||||
let acute = vscancode.includes("acute");
|
||||
let vscancode_int = parseInt(vscancode);
|
||||
if (acute) {
|
||||
let shifted_1 = vscancode.includes("shift1"); // Shift with Acute accent
|
||||
let shifted_2 = vscancode.includes("shift2"); // Shift with a/e/i/o/u
|
||||
if (down) {
|
||||
if (shifted_1 && ! this._shiftPressed) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
} else if (! shifted_1 && this._shiftPressed) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
RFB.messages.VMwareExtendedKeyEvent(this._sock, keysym, 1, VSCODE_ACUTE_LATAM);
|
||||
RFB.messages.VMwareExtendedKeyEvent(this._sock, keysym, 0, VSCODE_ACUTE_LATAM);
|
||||
if (shifted_2) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
} else {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
} else {
|
||||
RFB.messages.VMwareExtendedKeyEvent(this._sock, keysym, 0, VSCODE_ACUTE_LATAM);
|
||||
if (shifted_2 && ! this._shiftPressed) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
} else if (! shifted_2 && this._shiftPressed) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
}
|
||||
}
|
||||
RFB.messages.VMwareExtendedKeyEvent(this._sock, keysym, down, vscancode_int);
|
||||
return;
|
||||
}
|
||||
let isLetter = (keysym >= 65 && keysym <= 90) || (keysym >= 97 && keysym <= 122);
|
||||
if (shifted && !this._shiftPressed && !isLetter && down) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
}
|
||||
if (!shifted && this._shiftPressed && !isLetter && down) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
if (altgr && !this._altgrPressed && down) {
|
||||
RFB.messages.keyEvent(this._sock, KeyTable.XK_Alt_R, 1);
|
||||
}
|
||||
RFB.messages.VMwareExtendedKeyEvent(this._sock, keysym, down, vscancode_int);
|
||||
if (altgr && !this._altgrPressed && !down) {
|
||||
RFB.messages.keyEvent(this._sock, KeyTable.XK_Alt_R, 0);
|
||||
}
|
||||
if (shifted && !this._shiftPressed && !isLetter && !down) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 0);
|
||||
}
|
||||
if (!shifted && this._shiftPressed && !isLetter && !down) {
|
||||
RFB.messages.keyEvent(this._sock, this._shiftKey, 1);
|
||||
}
|
||||
} else {
|
||||
RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
focus(options) {
|
||||
this._canvas.focus(options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# This script
|
||||
# (1) loads keysym name and keycode mappings from noVNC/core/input/keysym.js and
|
||||
# (2) loads keysyn name to atset1 code mappings from keymap files which can be downloadeded from https://github.com/qemu/qemu/blob/master/pc-bios/keymaps
|
||||
# (2) loads keysym name to atset1 code mappings from keymap files which can be downloadeded from https://github.com/qemu/qemu/blob/master/pc-bios/keymaps
|
||||
# (3) generates the mappings of keycode and atset1 code
|
||||
#
|
||||
# Note: please add language specific mappings if needed.
|
||||
|
|
@ -96,7 +96,10 @@ def generate_js_file(keymap_file):
|
|||
js_config.append(" */\n")
|
||||
js_config.append("export default {\n")
|
||||
for keycode in dict(sorted(list(result_mappings.items()), key=lambda item: int(item[0]))):
|
||||
js_config.append("%10s : \"%s\",\n" % ("\"" + str(keycode) + "\"", result_mappings[keycode].strip()))
|
||||
if keycode not in list(keycode_to_x11name.keys()):
|
||||
js_config.append("%10s : \"%s\",\n" % ("\"" + str(keycode) + "\"", result_mappings[keycode].strip()))
|
||||
else:
|
||||
js_config.append("%10s : \"%s\", // %s\n" % ("\"" + str(keycode) + "\"", result_mappings[keycode].strip(), keycode_to_x11name[keycode]))
|
||||
js_config.append("}\n")
|
||||
for line in js_config:
|
||||
handle.write(line)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
/* This file is auto-generated by generate-language-keymaps.py
|
||||
* command : generate-language-keymaps.py keymap-es
|
||||
* layout : es-latam
|
||||
*/
|
||||
export default {
|
||||
"32" : "57", // XK_space
|
||||
"33" : "2 shift", // XK_exclam
|
||||
"34" : "3 shift", // XK_quotedbl
|
||||
"35" : "4 shift", // XK_numbersign
|
||||
"36" : "5 shift", // XK_dollar
|
||||
"37" : "6 shift", // XK_percent
|
||||
"38" : "7 shift", // XK_ampersand
|
||||
"39" : "12", // XK_apostrophe
|
||||
"40" : "9 shift", // XK_parenleft
|
||||
"41" : "10 shift", // XK_parenright
|
||||
"42" : "27 shift", // XK_asterisk
|
||||
"43" : "27", // XK_plus
|
||||
"44" : "51", // XK_comma
|
||||
"45" : "53", // XK_minus
|
||||
"46" : "52", // XK_period
|
||||
"47" : "8 shift", // XK_slash
|
||||
"48" : "11", // XK_0
|
||||
"49" : "2", // XK_1
|
||||
"50" : "3", // XK_2
|
||||
"51" : "4", // XK_3
|
||||
"52" : "5", // XK_4
|
||||
"53" : "6", // XK_5
|
||||
"54" : "7", // XK_6
|
||||
"55" : "8", // XK_7
|
||||
"56" : "9", // XK_8
|
||||
"57" : "10", // XK_9
|
||||
"58" : "52 shift", // XK_colon
|
||||
"59" : "51 shift", // XK_semicolon
|
||||
"60" : "86", // XK_less
|
||||
"61" : "11 shift", // XK_equal
|
||||
"62" : "86 shift", // XK_greater
|
||||
"63" : "12 shift", // XK_question
|
||||
"64" : "16 altgr", // XK_at
|
||||
"65" : "30 shift", // XK_A
|
||||
"66" : "48 shift", // XK_B
|
||||
"67" : "46 shift", // XK_C
|
||||
"68" : "32 shift", // XK_D
|
||||
"69" : "18 shift", // XK_E
|
||||
"70" : "33 shift", // XK_F
|
||||
"71" : "34 shift", // XK_G
|
||||
"72" : "35 shift", // XK_H
|
||||
"73" : "23 shift", // XK_I
|
||||
"74" : "36 shift", // XK_J
|
||||
"75" : "37 shift", // XK_K
|
||||
"76" : "38 shift", // XK_L
|
||||
"77" : "50 shift", // XK_M
|
||||
"78" : "49 shift", // XK_N
|
||||
"79" : "24 shift", // XK_O
|
||||
"80" : "25 shift", // XK_P
|
||||
"81" : "16 shift", // XK_Q
|
||||
"82" : "19 shift", // XK_R
|
||||
"83" : "31 shift", // XK_S
|
||||
"84" : "20 shift", // XK_T
|
||||
"85" : "22 shift", // XK_U
|
||||
"86" : "47 shift", // XK_V
|
||||
"87" : "17 shift", // XK_W
|
||||
"88" : "45 shift", // XK_X
|
||||
"89" : "21 shift", // XK_Y
|
||||
"90" : "44 shift", // XK_Z
|
||||
"91" : "40 shift", // XK_bracketleft
|
||||
"92" : "12 altgr", // XK_backslash
|
||||
"93" : "43 shift", // XK_bracketright
|
||||
"94": "40 altgr", // ^
|
||||
"95" : "53 shift", // XK_underscore
|
||||
"96": "43 altgr", // `
|
||||
"97" : "30", // XK_a
|
||||
"98" : "48", // XK_b
|
||||
"99" : "46", // XK_c
|
||||
"100" : "32", // XK_d
|
||||
"101" : "18", // XK_e
|
||||
"102" : "33", // XK_f
|
||||
"103" : "34", // XK_g
|
||||
"104" : "35", // XK_h
|
||||
"105" : "23", // XK_i
|
||||
"106" : "36", // XK_j
|
||||
"107" : "37", // XK_k
|
||||
"108" : "38", // XK_l
|
||||
"109" : "50", // XK_m
|
||||
"110" : "49", // XK_n
|
||||
"111" : "24", // XK_o
|
||||
"112" : "25", // XK_p
|
||||
"113" : "16", // XK_q
|
||||
"114" : "19", // XK_r
|
||||
"115" : "31", // XK_s
|
||||
"116" : "20", // XK_t
|
||||
"117" : "22", // XK_u
|
||||
"118" : "47", // XK_v
|
||||
"119" : "17", // XK_w
|
||||
"120" : "45", // XK_x
|
||||
"121" : "21", // XK_y
|
||||
"122" : "44", // XK_z
|
||||
"123" : "40", // XK_braceleft
|
||||
"124" : "41", // XK_bar
|
||||
"125" : "43", // XK_braceright
|
||||
"126" : "27 altgr", // XK_asciitilde
|
||||
"161" : "13 shift", // XK_exclamdown
|
||||
"168" : "26 shift", // ¨
|
||||
"171" : "44 altgr", // XK_guillemotleft
|
||||
"172" : "41 altgr", // XK_notsign
|
||||
"176" : "41 shift", // XK_degree
|
||||
"180" : "26", // ´
|
||||
"186" : "41", // XK_masculine
|
||||
"191" : "13", // XK_questiondown
|
||||
"193" : "30 acute shift2", // Á
|
||||
"196" : "30 shift1 acute shift2", // Ä
|
||||
"201" : "18 acute shift2", // É
|
||||
"203" : "18 shift1 acute shift2", // Ë
|
||||
"205" : "23 acute shift2", // Í
|
||||
"207" : "23 shift1 acute shift2", // Ï
|
||||
"209" : "39 shift", // XK_Ntilde
|
||||
"211" : "24 acute shift2", // Ó
|
||||
"214" : "24 shift1 acute shift2", // Ö
|
||||
"218" : "22 acute shift2", // Ú
|
||||
"220" : "22 shift1 acute shift2", // Ü
|
||||
"225" : "30 acute", // á
|
||||
"228" : "30 shift1 acute", // ä
|
||||
"233" : "18 acute", // é
|
||||
"235" : "18 shift1 acute", // ë
|
||||
"237" : "23 acute", // í
|
||||
"239" : "23 shift1 acute", // ï
|
||||
"241" : "39", // XK_ntilde
|
||||
"243" : "24 acute", // ó
|
||||
"246" : "24 shift1 acute", // ö
|
||||
"250" : "22 acute", // ú
|
||||
"252" : "22 shift1 acute", // ü
|
||||
}
|
||||
|
|
@ -61,7 +61,8 @@
|
|||
"uk": "label.uk.keyboard",
|
||||
"fr": "label.french.azerty.keyboard",
|
||||
"jp": "label.japanese.keyboard",
|
||||
"sc": "label.simplified.chinese.keyboard"
|
||||
"sc": "label.simplified.chinese.keyboard",
|
||||
"es-latam": "Spanish Latin American Keyboard"
|
||||
},
|
||||
"userCard": {
|
||||
"enabled": true,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
"error.release.dedicate.pod": "Failed to release dedicated Pod.",
|
||||
"error.release.dedicate.zone": "Failed to release dedicated Zone.",
|
||||
"error.unable.to.add.setting.extraconfig": "It is not allowed to add setting for extraconfig. Please update VirtualMachine with extraconfig parameter.",
|
||||
"error.unable.to.add.setting": "Unable to add or edit setting",
|
||||
"error.unable.to.proceed": "Unable to proceed. Please contact your administrator.",
|
||||
"firewall.close": "Firewall",
|
||||
"icmp.code.desc": "Please specify -1 if you want to allow all ICMP codes (except NSX zones).",
|
||||
|
|
@ -3401,6 +3402,7 @@
|
|||
"message.error.delete.tungsten.tag": "Removing Tag failed",
|
||||
"message.error.description": "Please enter description.",
|
||||
"message.error.discovering.feature": "Exception caught while discovering features.",
|
||||
"message.error.setting.deployasistemplate": "Settings are read directly from the template",
|
||||
"message.error.setup.2fa": "2FA setup failed while verifying the code, please retry.",
|
||||
"message.error.verifying.2fa": "Unable to verify 2FA, please retry.",
|
||||
"message.error.display.text": "Please enter display text.",
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@
|
|||
<tooltip-button
|
||||
:tooltip="$t('label.edit')"
|
||||
icon="edit-outlined"
|
||||
:disabled="deployasistemplate === true || item.name.startsWith('extraconfig')"
|
||||
:disabled="item.name.startsWith('extraconfig')"
|
||||
v-if="!item.edit"
|
||||
@onClick="showEditDetail(index)" />
|
||||
</div>
|
||||
|
|
@ -115,7 +115,7 @@
|
|||
>
|
||||
<tooltip-button
|
||||
:tooltip="$t('label.delete')"
|
||||
:disabled="deployasistemplate === true || item.name.startsWith('extraconfig')"
|
||||
:disabled="item.name.startsWith('extraconfig')"
|
||||
type="primary"
|
||||
:danger="true"
|
||||
icon="delete-outlined" />
|
||||
|
|
@ -213,11 +213,16 @@ export default {
|
|||
this.detailOptions = json.listdetailoptionsresponse.detailoptions.details
|
||||
})
|
||||
this.disableSettings = (this.$route.meta.name === 'vm' && resource.state !== 'Stopped')
|
||||
getAPI('listTemplates', { templatefilter: 'all', id: resource.templateid }).then(json => {
|
||||
this.deployasistemplate = json.listtemplatesresponse.template[0].deployasis
|
||||
})
|
||||
if (this.$route.meta.name === 'vm') {
|
||||
getAPI('listTemplates', { templatefilter: 'all', id: resource.templateid }).then(json => {
|
||||
this.deployasistemplate = json.listtemplatesresponse.template[0].deployasis
|
||||
})
|
||||
}
|
||||
},
|
||||
allowEditOfDetail (name) {
|
||||
if (this.deployasistemplate) {
|
||||
return this.resource.alloweddetails && this.resource.alloweddetails.split(',').map(item => item.trim()).includes(name)
|
||||
}
|
||||
if (this.resource.readonlydetails) {
|
||||
if (this.resource.readonlydetails.split(',').map(item => item.trim()).includes(name)) {
|
||||
return false
|
||||
|
|
@ -320,7 +325,11 @@ export default {
|
|||
return
|
||||
}
|
||||
if (!this.allowEditOfDetail(this.newKey)) {
|
||||
this.error = this.$t('error.unable.to.proceed')
|
||||
if (this.deployasistemplate) {
|
||||
this.error = this.$t('error.unable.to.add.setting') + ' : ' + this.newKey + '. ' + this.$t('message.error.setting.deployasistemplate')
|
||||
} else {
|
||||
this.error = this.$t('error.unable.to.add.setting') + ' : ' + this.newKey
|
||||
}
|
||||
return
|
||||
}
|
||||
this.error = false
|
||||
|
|
|
|||
Loading…
Reference in New Issue