mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-10-01 11:46:06 +08:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96c374b7aa | ||
|
|
bbe0c4643f |
+3
-1
@@ -7,6 +7,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/plugin-transform-class-static-block": "7.29.7",
|
||||
"@novnc/novnc": "1.7.0",
|
||||
"@rancher/shell": "3.0.13",
|
||||
"@vue-flow/background": "^1.3.0",
|
||||
"@vue-flow/controls": "^1.1.1",
|
||||
@@ -27,6 +28,7 @@
|
||||
"yaml": "^2.5.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"@novnc/novnc": "1.7.0",
|
||||
"@types/node": "25.9.5",
|
||||
"cronstrue": "2.59.0",
|
||||
"d3-color": "3.1.0",
|
||||
@@ -39,7 +41,7 @@
|
||||
"merge": "2.1.1",
|
||||
"node-forge": "1.4.0",
|
||||
"nth-check": "2.1.1",
|
||||
"qs": "6.15.3",
|
||||
"qs": "6.16.0",
|
||||
"roarr": "7.21.7",
|
||||
"semver": "7.8.5",
|
||||
"@vue/cli-service/html-webpack-plugin": "^5.0.0"
|
||||
|
||||
@@ -1,64 +1,99 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="connected && disconnected">
|
||||
<main class="main-layout error">
|
||||
<div class="text-center">
|
||||
<BrandImage
|
||||
file-name="error-desert-landscape.svg"
|
||||
width="900"
|
||||
height="300"
|
||||
/>
|
||||
<h1>
|
||||
{{ t('generic.notification.title.warning') }}
|
||||
</h1>
|
||||
<h2 class="text-secondary mt-20">
|
||||
{{ t('vncConsole.error.message') }}
|
||||
</h2>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div v-if="reconnecting">
|
||||
<main class="main-layout">
|
||||
<div class="text-center">
|
||||
<h2 class="text-secondary mt-20">
|
||||
{{ t('vncConsole.reconnecting.message') }}:{{ retryTimes }} of {{ maximumRetryTimes }}
|
||||
</h2>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div
|
||||
ref="view"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RFB from '@novnc/novnc/core/rfb';
|
||||
import BrandImage from '@shell/components/BrandImage';
|
||||
import ZoomableRFB from './ZoomableRFB';
|
||||
|
||||
export const CONSOLE_STATUS = {
|
||||
CONNECTING: 'connecting',
|
||||
CONNECTED: 'connected',
|
||||
RECONNECTING: 'reconnecting',
|
||||
DISCONNECTED: 'disconnected',
|
||||
FAILED: 'failed',
|
||||
};
|
||||
|
||||
const MAXIMUM_RETRY_TIMES = 10;
|
||||
const BASE_RECONNECT_DELAY = 1000;
|
||||
const MAXIMUM_RECONNECT_DELAY = 30000;
|
||||
|
||||
const clampLevel = (value, fallback) => {
|
||||
const level = Number.parseInt(value, 10);
|
||||
|
||||
if (Number.isNaN(level)) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return Math.min(Math.max(level, 0), 9);
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'NovncConsole',
|
||||
|
||||
components: { BrandImage },
|
||||
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
|
||||
settings: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
},
|
||||
|
||||
components: { BrandImage },
|
||||
emits: ['status-changed', 'capabilities'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
rfb: null,
|
||||
connected: false,
|
||||
disconnected: false,
|
||||
reconnectDelay: 3000,
|
||||
reconnecting: false,
|
||||
maximumRetryTimes: 10,
|
||||
status: CONSOLE_STATUS.CONNECTING,
|
||||
statusDetail: '',
|
||||
desktopName: '',
|
||||
retryTimes: 0,
|
||||
setTimeout: null,
|
||||
maximumRetryTimes: MAXIMUM_RETRY_TIMES,
|
||||
reconnectTimer: null,
|
||||
isClosed: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
statusInfo() {
|
||||
return {
|
||||
status: this.status,
|
||||
detail: this.statusDetail,
|
||||
desktopName: this.desktopName,
|
||||
retryTimes: this.retryTimes,
|
||||
maximumRetryTimes: this.maximumRetryTimes,
|
||||
};
|
||||
},
|
||||
|
||||
showError() {
|
||||
return this.status === CONSOLE_STATUS.FAILED;
|
||||
},
|
||||
|
||||
showReconnecting() {
|
||||
return this.status === CONSOLE_STATUS.RECONNECTING;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
url() {
|
||||
this.reconnect();
|
||||
},
|
||||
|
||||
settings: {
|
||||
deep: true,
|
||||
handler: 'applySettings'
|
||||
},
|
||||
|
||||
statusInfo: {
|
||||
immediate: true,
|
||||
handler(neu) {
|
||||
this.$emit('status-changed', neu);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.connect();
|
||||
@@ -66,88 +101,307 @@ export default {
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.clearTimeout();
|
||||
this.isClosed = true;
|
||||
this.clearReconnectTimer();
|
||||
this.teardown();
|
||||
},
|
||||
|
||||
methods: {
|
||||
connect() {
|
||||
const rfb = new RFB(this.$refs.view, this.url);
|
||||
connect(takeOver = false) {
|
||||
if (!this.url || this.isClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
rfb.addEventListener('connect', () => {
|
||||
this.clearTimeout();
|
||||
this.teardown();
|
||||
|
||||
this.connected = true;
|
||||
this.retryTimes = 0;
|
||||
this.reconnecting = false;
|
||||
});
|
||||
this.status = this.retryTimes > 0 ? CONSOLE_STATUS.RECONNECTING : CONSOLE_STATUS.CONNECTING;
|
||||
|
||||
rfb.addEventListener('disconnect', (e) => {
|
||||
this.clearTimeout();
|
||||
let rfb;
|
||||
|
||||
this.disconnected = true;
|
||||
this.rfb = null;
|
||||
this.reconnect();
|
||||
});
|
||||
try {
|
||||
const url = new URL(this.url);
|
||||
|
||||
url.searchParams.set('preserveSession', takeOver === true ? 'false' : 'true');
|
||||
rfb = new ZoomableRFB(this.$refs.view, url.href, { shared: true });
|
||||
} catch (err) {
|
||||
this.statusDetail = err?.message || `${ err }`;
|
||||
this.status = CONSOLE_STATUS.FAILED;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rfb.addEventListener('connect', this.onConnect);
|
||||
rfb.addEventListener('disconnect', this.onDisconnect);
|
||||
rfb.addEventListener('securityfailure', this.onSecurityFailure);
|
||||
rfb.addEventListener('credentialsrequired', this.onCredentialsRequired);
|
||||
rfb.addEventListener('desktopname', this.onDesktopName);
|
||||
rfb.addEventListener('capabilities', this.onCapabilities);
|
||||
|
||||
this.rfb = rfb;
|
||||
this.applySettings();
|
||||
},
|
||||
|
||||
reconnect() {
|
||||
this.clearReconnectTimer();
|
||||
|
||||
this.isClosed = false;
|
||||
this.retryTimes = 0;
|
||||
this.statusDetail = '';
|
||||
this.connect();
|
||||
},
|
||||
|
||||
takeOver() {
|
||||
if (!window.confirm(this.t('harvester.virtualMachine.detail.console.takeOver.confirm'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearReconnectTimer();
|
||||
this.isClosed = false;
|
||||
this.retryTimes = 0;
|
||||
this.statusDetail = '';
|
||||
this.connect(true);
|
||||
},
|
||||
|
||||
disconnect() {
|
||||
this.isClosed = true;
|
||||
this.clearReconnectTimer();
|
||||
this.teardown();
|
||||
this.status = CONSOLE_STATUS.DISCONNECTED;
|
||||
},
|
||||
|
||||
onConnect() {
|
||||
this.clearReconnectTimer();
|
||||
|
||||
this.retryTimes = 0;
|
||||
this.statusDetail = '';
|
||||
this.status = CONSOLE_STATUS.CONNECTED;
|
||||
this.applySettings();
|
||||
},
|
||||
|
||||
onDisconnect() {
|
||||
const wasConnected = this.status === CONSOLE_STATUS.CONNECTED;
|
||||
|
||||
this.teardown(false);
|
||||
|
||||
if (this.isClosed) {
|
||||
if (this.status !== CONSOLE_STATUS.FAILED) {
|
||||
this.status = CONSOLE_STATUS.DISCONNECTED;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (wasConnected) {
|
||||
this.scheduleReconnect();
|
||||
} else {
|
||||
this.clearReconnectTimer();
|
||||
this.statusDetail = this.t('harvester.virtualMachine.detail.console.status.unavailable');
|
||||
this.status = CONSOLE_STATUS.FAILED;
|
||||
}
|
||||
},
|
||||
|
||||
// Authentication problems will not fix themselves, so stop retrying.
|
||||
onSecurityFailure(e) {
|
||||
this.statusDetail = e?.detail?.reason || '';
|
||||
this.isClosed = true;
|
||||
this.clearReconnectTimer();
|
||||
this.status = CONSOLE_STATUS.FAILED;
|
||||
},
|
||||
|
||||
onCredentialsRequired() {
|
||||
this.statusDetail = this.t('harvester.virtualMachine.detail.console.status.credentialsRequired');
|
||||
this.isClosed = true;
|
||||
this.clearReconnectTimer();
|
||||
this.status = CONSOLE_STATUS.FAILED;
|
||||
},
|
||||
|
||||
onDesktopName(e) {
|
||||
this.desktopName = e?.detail?.name || '';
|
||||
},
|
||||
|
||||
onCapabilities(e) {
|
||||
this.$emit('capabilities', e?.detail?.capabilities || {});
|
||||
},
|
||||
|
||||
scheduleReconnect() {
|
||||
this.clearReconnectTimer();
|
||||
|
||||
if (this.isClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.retryTimes >= this.maximumRetryTimes) {
|
||||
this.reconnecting = false;
|
||||
this.connected = true;
|
||||
this.disconnected = true;
|
||||
this.status = CONSOLE_STATUS.FAILED;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.retryTimes += 1;
|
||||
this.reconnecting = true;
|
||||
this.connected = false;
|
||||
this.disconnected = false;
|
||||
this.status = CONSOLE_STATUS.RECONNECTING;
|
||||
|
||||
this.setTimeout = setTimeout(() => {
|
||||
const delay = Math.min(BASE_RECONNECT_DELAY * (2 ** (this.retryTimes - 1)), MAXIMUM_RECONNECT_DELAY);
|
||||
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
this.reconnectTimer = null;
|
||||
this.connect();
|
||||
}, this.reconnectDelay);
|
||||
}, delay);
|
||||
},
|
||||
|
||||
clearTimeout() {
|
||||
if (this.setTimeout) {
|
||||
clearTimeout(this.setTimeout);
|
||||
clearReconnectTimer() {
|
||||
if (this.reconnectTimer) {
|
||||
clearTimeout(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
disconnect() {
|
||||
this.rfb.disconnect();
|
||||
teardown(disconnect = true) {
|
||||
const rfb = this.rfb;
|
||||
|
||||
if (!rfb) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rfb = null;
|
||||
|
||||
rfb.removeEventListener('connect', this.onConnect);
|
||||
rfb.removeEventListener('disconnect', this.onDisconnect);
|
||||
rfb.removeEventListener('securityfailure', this.onSecurityFailure);
|
||||
rfb.removeEventListener('credentialsrequired', this.onCredentialsRequired);
|
||||
rfb.removeEventListener('desktopname', this.onDesktopName);
|
||||
rfb.removeEventListener('capabilities', this.onCapabilities);
|
||||
|
||||
if (!disconnect) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
rfb.disconnect();
|
||||
} catch (err) {
|
||||
// The socket may already be gone, nothing left to clean up.
|
||||
}
|
||||
},
|
||||
|
||||
applySettings() {
|
||||
const rfb = this.rfb;
|
||||
|
||||
if (!rfb) {
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = this.settings || {};
|
||||
|
||||
rfb.viewOnly = !!settings.viewOnly;
|
||||
rfb.scaleViewport = !!settings.scaleViewport;
|
||||
rfb.resizeSession = !!settings.resizeSession;
|
||||
rfb.clipViewport = !!settings.clipViewport;
|
||||
rfb.dragViewport = !!settings.dragViewport;
|
||||
rfb.zoomPercent = settings.zoomPercent;
|
||||
rfb.focusOnClick = settings.focusOnClick !== false;
|
||||
rfb.qualityLevel = clampLevel(settings.qualityLevel, 6);
|
||||
rfb.compressionLevel = clampLevel(settings.compressionLevel, 2);
|
||||
},
|
||||
|
||||
ctrlAltDelete() {
|
||||
this.rfb.sendCtrlAltDel();
|
||||
this.rfb?.sendCtrlAltDel();
|
||||
},
|
||||
|
||||
sendKey(keysym, code, down) {
|
||||
this.rfb.sendKey(keysym, code, down);
|
||||
}
|
||||
this.rfb?.sendKey(keysym, code, down);
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.error {
|
||||
overflow: hidden;
|
||||
<template>
|
||||
<div class="novnc-console">
|
||||
<div
|
||||
ref="view"
|
||||
class="novnc-screen"
|
||||
/>
|
||||
|
||||
.row {
|
||||
align-items: center;
|
||||
}
|
||||
<div
|
||||
v-if="showError || showReconnecting"
|
||||
class="novnc-overlay"
|
||||
>
|
||||
<div
|
||||
v-if="showError"
|
||||
class="text-center"
|
||||
>
|
||||
<BrandImage
|
||||
file-name="error-desert-landscape.svg"
|
||||
width="900"
|
||||
height="300"
|
||||
/>
|
||||
<h1>
|
||||
{{ t('generic.notification.title.warning') }}
|
||||
</h1>
|
||||
<h2 class="text-secondary mt-20">
|
||||
{{ t('vncConsole.error.message') }}
|
||||
</h2>
|
||||
<p
|
||||
v-if="statusDetail"
|
||||
class="text-muted mt-10"
|
||||
>
|
||||
{{ statusDetail }}
|
||||
</p>
|
||||
<button
|
||||
class="btn role-primary mt-20"
|
||||
@click="reconnect"
|
||||
>
|
||||
{{ t('harvester.action.reconnect') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="!isClosed"
|
||||
class="btn role-secondary mt-20 ml-10"
|
||||
@click="takeOver"
|
||||
>
|
||||
{{ t('harvester.virtualMachine.detail.console.takeOver.label') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h2
|
||||
v-else
|
||||
class="text-secondary"
|
||||
>
|
||||
{{ t('vncConsole.reconnecting.message') }}:{{ retryTimes }} of {{ maximumRetryTimes }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.novnc-console {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
padding: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.novnc-screen {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.novnc-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: auto;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
|
||||
h1 {
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
||||
.desert-landscape {
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
<script>
|
||||
import { STEVE } from '@shell/config/types';
|
||||
import Banner from '@components/Banner/Banner.vue';
|
||||
import AsyncButton from '@shell/components/AsyncButton';
|
||||
import ModalWithCard from '@shell/components/ModalWithCard';
|
||||
|
||||
const PREFERED_SHORTCUT_KEYS = 'prefered-shortcut-keys';
|
||||
|
||||
export default {
|
||||
name: 'NovncConsoleCustomKeys',
|
||||
|
||||
emits: ['close'],
|
||||
|
||||
components: {
|
||||
ModalWithCard, Banner, AsyncButton
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
keysRecord: [],
|
||||
addedShortcutKeys: [],
|
||||
preferredShortcutKeys: [],
|
||||
isRecording: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
savedShortcutKeys() {
|
||||
const preference = this.$store.getters['management/all'](STEVE.PREFERENCE);
|
||||
const preferedShortcutKeys = preference?.[0]?.data?.[PREFERED_SHORTCUT_KEYS];
|
||||
let out = [];
|
||||
|
||||
if (!preferedShortcutKeys) {
|
||||
return out;
|
||||
}
|
||||
|
||||
try {
|
||||
out = JSON.parse(preferedShortcutKeys);
|
||||
} catch (err) {
|
||||
this.$store.dispatch('growl/fromError', {
|
||||
title: this.t('generic.notification.title.error', { name: this.t('harvester.virtualMachine.detail.console.customShortcutKeys') }),
|
||||
err,
|
||||
}, { root: true });
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
displayedKeys() {
|
||||
const out = this.addedShortcutKeys.concat(this.preferredShortcutKeys).map((item) => {
|
||||
const out = item.map((K) => ` <code>${ K.key.charAt(0).toUpperCase() + K.key.slice(1) }</code>`);
|
||||
|
||||
return out.join(',');
|
||||
});
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
recordButton() {
|
||||
if (this.isRecording) {
|
||||
return 'harvester.virtualMachine.detail.console.record.stop';
|
||||
}
|
||||
|
||||
return 'harvester.virtualMachine.detail.console.record.start';
|
||||
},
|
||||
|
||||
keysRecordFormat() {
|
||||
if (!this.isRecording && this.keysRecord.length === 0) {
|
||||
return this.t('harvester.virtualMachine.detail.console.record.tips');
|
||||
}
|
||||
|
||||
const out = this.keysRecord.map((item) => ` <code>${ item.key.charAt(0).toUpperCase() + item.key.slice(1) }</code>`);
|
||||
|
||||
return `Keys: ${ out.join(',') }`;
|
||||
},
|
||||
|
||||
canAdd() {
|
||||
const hasRecord = this.keysRecord.length > 0;
|
||||
let validationList = [].concat(this.preferredShortcutKeys, this.addedShortcutKeys);
|
||||
|
||||
if (!hasRecord) {
|
||||
return false;
|
||||
}
|
||||
|
||||
validationList.push(this.keysRecord);
|
||||
|
||||
validationList = validationList.map((item) => {
|
||||
const out = item.map((K) => K.key);
|
||||
|
||||
return out.join(',');
|
||||
});
|
||||
|
||||
return validationList.length === new Set(validationList).size;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
savedShortcutKeys: {
|
||||
handler() {
|
||||
this.preferredShortcutKeys = [].concat(this.savedShortcutKeys) || [];
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
closeRecordingModal() {
|
||||
window.removeEventListener('keydown', this.handleShortcut);
|
||||
this.$emit('close');
|
||||
},
|
||||
|
||||
toggleRecording() {
|
||||
this.isRecording = !this.isRecording;
|
||||
|
||||
if (this.isRecording) {
|
||||
this.keysRecord = [];
|
||||
window.addEventListener('keydown', this.handleShortcut);
|
||||
} else {
|
||||
window.removeEventListener('keydown', this.handleShortcut);
|
||||
}
|
||||
},
|
||||
|
||||
handleShortcut(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const {
|
||||
key, keyCode, code, location, charCode
|
||||
} = event;
|
||||
|
||||
this.keysRecord.push({
|
||||
key, keyCode, code, location, charCode
|
||||
});
|
||||
},
|
||||
|
||||
addShortcutKey() {
|
||||
this.addedShortcutKeys.push([].concat(this.keysRecord));
|
||||
},
|
||||
|
||||
removeKey(keys) {
|
||||
const key = keys.replace(/(\s*)<code>|<\/code>/g, '').replace(/\s*,\s*/g, ',');
|
||||
|
||||
this.addedShortcutKeys = this.addedShortcutKeys.filter((item) => {
|
||||
const formatkey = item.map((K) => K.key.charAt(0).toUpperCase() + K.key.slice(1)).join(',');
|
||||
|
||||
return formatkey !== key;
|
||||
});
|
||||
|
||||
this.preferredShortcutKeys = this.preferredShortcutKeys.filter((item) => {
|
||||
const formatkey = item.map((K) => K.key.charAt(0).toUpperCase() + K.key.slice(1)).join(',');
|
||||
|
||||
return formatkey !== key;
|
||||
});
|
||||
},
|
||||
|
||||
async saveKeys(buttonCb) {
|
||||
const out = [].concat(this.preferredShortcutKeys, this.addedShortcutKeys);
|
||||
const preference = this.$store.getters['management/all'](STEVE.PREFERENCE)?.[0];
|
||||
|
||||
try {
|
||||
preference.data[PREFERED_SHORTCUT_KEYS] = JSON.stringify(out);
|
||||
await preference.save();
|
||||
this.closeRecordingModal();
|
||||
buttonCb(true);
|
||||
} catch (err) {
|
||||
buttonCb(false);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWithCard
|
||||
name="recordShortcutKeys"
|
||||
:width="550"
|
||||
>
|
||||
<template #title>
|
||||
<t k="harvester.virtualMachine.detail.console.customShortcutKeys" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
<Banner color="info">
|
||||
<span v-clean-html="keysRecordFormat"></span>
|
||||
</Banner>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
<button
|
||||
class="btn bg-primary"
|
||||
@click="toggleRecording"
|
||||
>
|
||||
<t :k="recordButton" />
|
||||
<i
|
||||
class="icon icon-fw"
|
||||
:class="isRecording ? 'icon-dot-open' : 'icon-dot'"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
:disabled="!canAdd"
|
||||
class="btn bg-primary"
|
||||
@click="addShortcutKey"
|
||||
>
|
||||
<t k="generic.add" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="displayed-keys mt-20">
|
||||
<h4
|
||||
v-clean-html="t('harvester.virtualMachine.detail.console.record.preferredKeys')"
|
||||
class="text-default-text"
|
||||
/>
|
||||
|
||||
<div class="displayed-banners">
|
||||
<Banner
|
||||
v-for="(keys,index) in displayedKeys"
|
||||
:key="index"
|
||||
>
|
||||
<span v-clean-html="keys"></span>
|
||||
</Banner>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<div class="actions">
|
||||
<button
|
||||
class="btn role-secondary mr-20"
|
||||
@click.prevent="closeRecordingModal"
|
||||
>
|
||||
<t k="generic.close" />
|
||||
</button>
|
||||
<AsyncButton
|
||||
mode="done"
|
||||
@click="saveKeys"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</ModalWithCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.displayed-keys {
|
||||
.banner {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.displayed-banners {
|
||||
max-height: 155px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +1,26 @@
|
||||
<script>
|
||||
import { STEVE } from '@shell/config/types';
|
||||
import { escapeHtml } from '@shell/utils/string';
|
||||
import { allHash } from '@shell/utils/promise';
|
||||
import KeyTable from '@novnc/novnc/core/input/keysym';
|
||||
import * as KeyboardUtil from '@novnc/novnc/core/input/util';
|
||||
import { HCI } from '../../types';
|
||||
import NovncConsole from './NovncConsole';
|
||||
import NovncConsoleItem from './NovncConsoleItem';
|
||||
import NovncConsoleCustomKeys from './NovncConsoleCustomKeys';
|
||||
import { normalizeZoom } from './ZoomableRFB';
|
||||
|
||||
const PREFERED_SHORTCUT_KEYS = 'prefered-shortcut-keys';
|
||||
const CONSOLE_SETTINGS_KEY = 'harvester-vnc-console-settings';
|
||||
|
||||
const VIEW_MODE = {
|
||||
SCALE: 'scale',
|
||||
NONE: 'none',
|
||||
};
|
||||
|
||||
const DEFAULT_SETTINGS = {
|
||||
viewMode: VIEW_MODE.NONE,
|
||||
zoomPercent: 100,
|
||||
viewOnly: false,
|
||||
qualityLevel: 6,
|
||||
compressionLevel: 2,
|
||||
};
|
||||
|
||||
const SHORT_KEYS = {
|
||||
ControlLeft: {
|
||||
@@ -105,9 +116,7 @@ const F_KEYS = {
|
||||
|
||||
export default {
|
||||
name: 'NovncConsoleWrapper',
|
||||
components: {
|
||||
NovncConsole, NovncConsoleItem, NovncConsoleCustomKeys
|
||||
},
|
||||
components: { NovncConsole, NovncConsoleItem },
|
||||
|
||||
async fetch() {
|
||||
const _hash = { vmResource: this.$store.dispatch('harvester/find', { type: HCI.VM, id: this.value.id }) };
|
||||
@@ -131,39 +140,21 @@ export default {
|
||||
return {
|
||||
keysRecord: [],
|
||||
vmResource: {},
|
||||
renderKeysModal: false,
|
||||
currentUser: null,
|
||||
hideCustomKeysBar: false,
|
||||
settings: { ...DEFAULT_SETTINGS },
|
||||
capabilities: {},
|
||||
isFullscreen: false,
|
||||
consoleStatus: {
|
||||
status: 'connecting',
|
||||
retryTimes: 0,
|
||||
maximumRetryTimes: 0,
|
||||
desktopName: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
savedShortcutKeys() {
|
||||
const preference = this.$store.getters['management/all'](STEVE.PREFERENCE);
|
||||
const preferedShortcutKeys = preference?.[0]?.data?.[PREFERED_SHORTCUT_KEYS];
|
||||
let out = [];
|
||||
|
||||
if (!preference?.[0]?.data) {
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
this.hideCustomKeysBar = true;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
if (!preferedShortcutKeys) {
|
||||
return out;
|
||||
}
|
||||
|
||||
try {
|
||||
out = JSON.parse(preferedShortcutKeys);
|
||||
} catch (err) {
|
||||
this.$store.dispatch('growl/fromError', {
|
||||
title: this.t('generic.notification.title.error', { name: escapeHtml(this.value.metadata.name) }),
|
||||
err,
|
||||
}, { root: true });
|
||||
}
|
||||
|
||||
return out;
|
||||
canSendKeys() {
|
||||
return this.consoleStatus.status === 'connected' && !this.settings.viewOnly;
|
||||
},
|
||||
|
||||
isDown() {
|
||||
@@ -192,13 +183,16 @@ export default {
|
||||
...F_KEYS,
|
||||
};
|
||||
|
||||
out.AltLeft.keys = { PrintScreen: FUNCTION_KEYS.PrintScreen, ...F_KEYS };
|
||||
out.ControlLeft.keys = {
|
||||
AltLeft: {
|
||||
...Object.assign(SHORT_KEYS.AltLeft, {}),
|
||||
keys: { Delete: FUNCTION_KEYS.Delete }
|
||||
out.AltLeft = { ...SHORT_KEYS.AltLeft, keys: { PrintScreen: FUNCTION_KEYS.PrintScreen, ...F_KEYS } };
|
||||
out.ControlLeft = {
|
||||
...SHORT_KEYS.ControlLeft,
|
||||
keys: {
|
||||
AltLeft: {
|
||||
...SHORT_KEYS.AltLeft,
|
||||
keys: { Delete: FUNCTION_KEYS.Delete }
|
||||
},
|
||||
...NORMAL_KEYS,
|
||||
},
|
||||
...NORMAL_KEYS,
|
||||
};
|
||||
|
||||
return out;
|
||||
@@ -208,14 +202,53 @@ export default {
|
||||
return !!this.vmResource?.actions?.softreboot;
|
||||
},
|
||||
|
||||
preferredShortcutKeys() {
|
||||
return (this.savedShortcutKeys || []).map((item) => {
|
||||
return {
|
||||
label: item.map((K) => K.key.charAt(0).toUpperCase() + K.key.slice(1)).join('+'),
|
||||
value: item
|
||||
};
|
||||
});
|
||||
rfbSettings() {
|
||||
return {
|
||||
viewOnly: this.settings.viewOnly,
|
||||
scaleViewport: this.settings.viewMode === VIEW_MODE.SCALE,
|
||||
zoomPercent: normalizeZoom(this.settings.zoomPercent),
|
||||
resizeSession: false,
|
||||
clipViewport: false,
|
||||
dragViewport: false,
|
||||
qualityLevel: this.settings.qualityLevel,
|
||||
compressionLevel: this.settings.compressionLevel,
|
||||
};
|
||||
},
|
||||
|
||||
viewModeOptions() {
|
||||
return Object.values(VIEW_MODE).map((value) => ({
|
||||
value,
|
||||
label: this.t(`harvester.virtualMachine.detail.console.settings.viewMode.${ value }`)
|
||||
}));
|
||||
},
|
||||
|
||||
statusLabel() {
|
||||
const { status, retryTimes, maximumRetryTimes } = this.consoleStatus;
|
||||
|
||||
if (status === 'reconnecting') {
|
||||
return this.t('harvester.virtualMachine.detail.console.status.reconnecting', { retryTimes, maximumRetryTimes });
|
||||
}
|
||||
|
||||
return this.t(`harvester.virtualMachine.detail.console.status.${ status }`);
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
settings: {
|
||||
deep: true,
|
||||
handler(neu) {
|
||||
window.localStorage.setItem(CONSOLE_SETTINGS_KEY, JSON.stringify(neu));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.loadSettings();
|
||||
document.addEventListener('fullscreenchange', this.onFullscreenChange);
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
document.removeEventListener('fullscreenchange', this.onFullscreenChange);
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -233,137 +266,221 @@ export default {
|
||||
|
||||
// Send function key, e.g. ALT + F
|
||||
sendKeys() {
|
||||
if (!this.canSendKeys || !this.$refs.novncConsole) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.keysRecord.forEach((key) => {
|
||||
this.$refs.novncConsole.sendKey(this.allKeys[key].value, key, true);
|
||||
});
|
||||
|
||||
this.keysRecord.reverse().forEach((key) => {
|
||||
[...this.keysRecord].reverse().forEach((key) => {
|
||||
this.$refs.novncConsole.sendKey(this.allKeys[key].value, key, false);
|
||||
});
|
||||
|
||||
this.$refs.popover.isOpen = false;
|
||||
this.$refs.popover.hide();
|
||||
this.keysRecord = [];
|
||||
},
|
||||
|
||||
sendCustomKeys(keys) {
|
||||
const keyList = [].concat(keys);
|
||||
|
||||
keyList.forEach((K) => {
|
||||
this.$refs.novncConsole.sendKey(KeyboardUtil.getKeysym(K), KeyboardUtil.getKeycode(K), true);
|
||||
});
|
||||
|
||||
keyList.reverse().forEach((K) => {
|
||||
this.$refs.novncConsole.sendKey(KeyboardUtil.getKeysym(K), KeyboardUtil.getKeycode(K), false);
|
||||
});
|
||||
},
|
||||
|
||||
reconnect() {
|
||||
this.$refs.novncConsole.reconnect();
|
||||
},
|
||||
|
||||
loadSettings() {
|
||||
try {
|
||||
const saved = JSON.parse(window.localStorage.getItem(CONSOLE_SETTINGS_KEY) || '{}');
|
||||
|
||||
this.settings = {
|
||||
viewMode: Object.values(VIEW_MODE).includes(saved?.viewMode) ? saved.viewMode : DEFAULT_SETTINGS.viewMode,
|
||||
zoomPercent: normalizeZoom(saved?.zoomPercent ?? DEFAULT_SETTINGS.zoomPercent),
|
||||
viewOnly: saved?.viewOnly === true,
|
||||
qualityLevel: saved?.qualityLevel ?? DEFAULT_SETTINGS.qualityLevel,
|
||||
compressionLevel: saved?.compressionLevel ?? DEFAULT_SETTINGS.compressionLevel,
|
||||
};
|
||||
} catch (err) {
|
||||
this.settings = { ...DEFAULT_SETTINGS };
|
||||
}
|
||||
},
|
||||
|
||||
onStatusChanged(info) {
|
||||
this.consoleStatus = info;
|
||||
},
|
||||
|
||||
onCapabilities(capabilities) {
|
||||
this.capabilities = capabilities;
|
||||
},
|
||||
|
||||
ctrlAltDelete() {
|
||||
if (this.canSendKeys) {
|
||||
this.$refs.novncConsole?.ctrlAltDelete();
|
||||
}
|
||||
},
|
||||
|
||||
async toggleFullscreen() {
|
||||
try {
|
||||
if (document.fullscreenElement) {
|
||||
await document.exitFullscreen();
|
||||
} else {
|
||||
await this.$refs.consoleContainer.requestFullscreen();
|
||||
// Keyboard lock lets shortcuts such as Ctrl+W and F11 reach the guest.
|
||||
await navigator.keyboard?.lock?.(['KeyW', 'F11']);
|
||||
}
|
||||
} catch (err) {
|
||||
this.$store.dispatch('growl/fromError', {
|
||||
title: this.t('generic.notification.title.error', { name: escapeHtml(this.value.metadata.name) }),
|
||||
err,
|
||||
}, { root: true });
|
||||
}
|
||||
},
|
||||
|
||||
onFullscreenChange() {
|
||||
this.isFullscreen = !!document.fullscreenElement;
|
||||
|
||||
if (!this.isFullscreen) {
|
||||
navigator.keyboard?.unlock?.();
|
||||
}
|
||||
},
|
||||
|
||||
softReboot() {
|
||||
this.vmResource.doSoftReboot();
|
||||
},
|
||||
|
||||
showKeysModal() {
|
||||
this.renderKeysModal = true;
|
||||
},
|
||||
|
||||
hideKeysModal() {
|
||||
this.renderKeysModal = false;
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="app">
|
||||
<div class="vm-console">
|
||||
<div
|
||||
ref="consoleContainer"
|
||||
class="vm-console"
|
||||
>
|
||||
<div class="combination-keys">
|
||||
<v-dropdown
|
||||
ref="popover"
|
||||
placement="top"
|
||||
trigger="click"
|
||||
:container="false"
|
||||
@auto-hide="keysRecord = []"
|
||||
>
|
||||
<button class="btn btn-sm bg-primary">
|
||||
{{ t("harvester.virtualMachine.detail.console.shortcutKeys") }}
|
||||
</button>
|
||||
|
||||
<template #popper>
|
||||
<novnc-console-item
|
||||
:items="keymap"
|
||||
:path="keysRecord"
|
||||
:pos="0"
|
||||
@update="update"
|
||||
@send-keys="sendKeys"
|
||||
/>
|
||||
</template>
|
||||
</v-dropdown>
|
||||
|
||||
<button
|
||||
v-if="hasSoftRebootAction"
|
||||
class="btn btn-sm bg-primary"
|
||||
@click="softReboot"
|
||||
>
|
||||
{{ t("harvester.action.softreboot") }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-sm bg-primary"
|
||||
@click="reconnect"
|
||||
>
|
||||
{{ t("harvester.action.reconnect") }}
|
||||
</button>
|
||||
|
||||
<v-dropdown
|
||||
v-if="!hideCustomKeysBar"
|
||||
ref="customKeyPopover"
|
||||
placement="top"
|
||||
trigger="click"
|
||||
:container="false"
|
||||
>
|
||||
<button class="btn btn-sm bg-primary">
|
||||
{{ t("harvester.virtualMachine.detail.console.customShortcutKeys") }}
|
||||
</button>
|
||||
|
||||
<template #popper>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-sm bg-primary"
|
||||
@click="showKeysModal"
|
||||
>
|
||||
{{ t("harvester.virtualMachine.detail.console.management") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div
|
||||
v-for="(keys, index) in preferredShortcutKeys"
|
||||
:key="index"
|
||||
<div class="toolbar-group">
|
||||
<v-dropdown
|
||||
ref="popover"
|
||||
placement="top"
|
||||
trigger="click"
|
||||
:container="false"
|
||||
@auto-hide="keysRecord = []"
|
||||
>
|
||||
<button
|
||||
class="btn btn-sm bg-primary"
|
||||
:disabled="!canSendKeys"
|
||||
>
|
||||
<button
|
||||
class="btn btn-sm bg-primary"
|
||||
@click="sendCustomKeys(keys.value)"
|
||||
>
|
||||
{{ keys.label }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-dropdown>
|
||||
{{ t("harvester.virtualMachine.detail.console.shortcutKeys") }}
|
||||
</button>
|
||||
|
||||
<NovncConsoleCustomKeys
|
||||
v-if="renderKeysModal"
|
||||
:current-user="currentUser"
|
||||
@close="hideKeysModal"
|
||||
/>
|
||||
<template #popper>
|
||||
<novnc-console-item
|
||||
:items="keymap"
|
||||
:path="keysRecord"
|
||||
:pos="0"
|
||||
@update="update"
|
||||
@send-keys="sendKeys"
|
||||
/>
|
||||
</template>
|
||||
</v-dropdown>
|
||||
|
||||
<button
|
||||
class="btn btn-sm bg-primary"
|
||||
:disabled="!canSendKeys"
|
||||
@click="ctrlAltDelete"
|
||||
>
|
||||
Ctrl+Alt+Del
|
||||
</button>
|
||||
|
||||
<v-dropdown
|
||||
placement="top"
|
||||
trigger="click"
|
||||
:container="false"
|
||||
>
|
||||
<button class="btn btn-sm bg-primary">
|
||||
{{ t("harvester.virtualMachine.detail.console.settings.label") }}
|
||||
</button>
|
||||
|
||||
<template #popper>
|
||||
<div class="console-panel">
|
||||
<label>{{ t('harvester.virtualMachine.detail.console.settings.viewMode.label') }}</label>
|
||||
<div
|
||||
v-for="option in viewModeOptions"
|
||||
:key="option.value"
|
||||
>
|
||||
<label class="console-panel__option">
|
||||
<input
|
||||
v-model="settings.viewMode"
|
||||
type="radio"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label
|
||||
for="vnc-zoom"
|
||||
class="console-panel__zoom-label"
|
||||
>
|
||||
<span>{{ t('harvester.virtualMachine.detail.console.settings.zoom') }}</span>
|
||||
<span>{{ settings.zoomPercent }}%</span>
|
||||
</label>
|
||||
<input
|
||||
id="vnc-zoom"
|
||||
v-model.number="settings.zoomPercent"
|
||||
class="console-panel__zoom"
|
||||
type="range"
|
||||
min="50"
|
||||
max="200"
|
||||
step="10"
|
||||
:disabled="settings.viewMode === 'scale'"
|
||||
:aria-valuetext="`${ settings.zoomPercent }%`"
|
||||
>
|
||||
|
||||
<label class="console-panel__option">
|
||||
<input
|
||||
v-model="settings.viewOnly"
|
||||
type="checkbox"
|
||||
>
|
||||
{{ t('harvester.virtualMachine.detail.console.settings.viewOnly') }}
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
</v-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="toolbar-group">
|
||||
<span class="console-status">{{ statusLabel }}</span>
|
||||
|
||||
<button
|
||||
v-if="hasSoftRebootAction"
|
||||
class="btn btn-sm bg-primary"
|
||||
@click="softReboot"
|
||||
>
|
||||
{{ t("harvester.action.softreboot") }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-sm bg-primary"
|
||||
@click="reconnect"
|
||||
>
|
||||
{{ t("harvester.action.reconnect") }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-sm bg-primary"
|
||||
@click="toggleFullscreen"
|
||||
>
|
||||
{{ isFullscreen ? t('harvester.virtualMachine.detail.console.fullscreen.exit') : t('harvester.virtualMachine.detail.console.fullscreen.enter') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NovncConsole
|
||||
v-if="url && !isDown"
|
||||
ref="novncConsole"
|
||||
:url="url"
|
||||
:settings="rfbSettings"
|
||||
@status-changed="onStatusChanged"
|
||||
@capabilities="onCapabilities"
|
||||
/>
|
||||
<p v-if="isDown">
|
||||
{{ t("harvester.virtualMachine.detail.console.down") }}
|
||||
@@ -374,14 +491,56 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vm-console {
|
||||
height: 100%;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
display: grid;
|
||||
grid-template-rows: 30px auto;
|
||||
grid-template-rows: 32px minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.combination-keys {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: rgb(40, 40, 40);
|
||||
}
|
||||
|
||||
.toolbar-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.console-status {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.console-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 260px;
|
||||
padding: 4px;
|
||||
|
||||
&__zoom-label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
&__zoom {
|
||||
width: 100%;
|
||||
margin: 4px 0 8px;
|
||||
}
|
||||
|
||||
&__option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin: 2px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import RFB from '@novnc/novnc/core/rfb';
|
||||
|
||||
export function normalizeZoom(value) {
|
||||
const percent = Number(value);
|
||||
|
||||
if (!Number.isFinite(percent)) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
return Math.min(200, Math.max(50, Math.round(percent / 10) * 10));
|
||||
}
|
||||
|
||||
export default class ZoomableRFB extends RFB {
|
||||
get zoomPercent() {
|
||||
return this._zoomPercent ?? 100;
|
||||
}
|
||||
|
||||
set zoomPercent(value) {
|
||||
this._zoomPercent = normalizeZoom(value);
|
||||
this._updateScale();
|
||||
}
|
||||
|
||||
_updateScale() {
|
||||
if (this.scaleViewport) {
|
||||
super._updateScale();
|
||||
} else {
|
||||
this._display.scale = this.zoomPercent / 100;
|
||||
this._fixScrollbars();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -953,15 +953,33 @@ harvester:
|
||||
console:
|
||||
down: This virtual machine is down. Please start it to access its console.
|
||||
shortcutKeys: Shortcut Keys
|
||||
customShortcutKeys: Custom Shortcut Keys
|
||||
management: Management Shortcut Keys
|
||||
record:
|
||||
start: Record
|
||||
recording: Recording
|
||||
stop: Stop Recording
|
||||
tips: Press the record button to capture your keyboard inputs.
|
||||
send: Send
|
||||
preferredKeys: Preferred Custom Shortcut Keys
|
||||
settings:
|
||||
label: Settings
|
||||
viewMode:
|
||||
label: Display
|
||||
scale: Scale the display to fit the window
|
||||
resize: Resize the virtual machine display to the window
|
||||
none: Manual zoom
|
||||
zoom: Zoom
|
||||
clipViewport: Clip to the window instead of showing scrollbars
|
||||
viewOnly: View only
|
||||
quality: JPEG quality
|
||||
compression: Compression level
|
||||
reset: Reset to defaults
|
||||
fullscreen:
|
||||
enter: Full Screen
|
||||
exit: Exit Full Screen
|
||||
takeOver:
|
||||
label: Take Over
|
||||
confirm: Take over this console? Any existing VNC session for this virtual machine will be disconnected.
|
||||
status:
|
||||
connecting: Connecting
|
||||
connected: Connected
|
||||
disconnected: Disconnected
|
||||
failed: Connection failed
|
||||
reconnecting: 'Reconnecting {retryTimes} of {maximumRetryTimes}'
|
||||
credentialsRequired: This console requires credentials that the dashboard cannot provide.
|
||||
unavailable: Unable to connect. Another VNC session may be active, or the console may be unavailable.
|
||||
terminationGracePeriodSeconds:
|
||||
label: Termination Grace Period
|
||||
affinity:
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
<script>
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import Loading from '@shell/components/Loading';
|
||||
import TabTitle from '@shell/components/TabTitle';
|
||||
import { HCI } from '../../../../../types';
|
||||
import NovncConsoleWrapper from '../../../../../components/novnc/NovncConsoleWrapper.vue';
|
||||
|
||||
export default {
|
||||
components: { NovncConsoleWrapper, Loading },
|
||||
components: {
|
||||
NovncConsoleWrapper: defineAsyncComponent({
|
||||
loader: () => import('../../../../../components/novnc/NovncConsoleWrapper.vue'),
|
||||
loadingComponent: Loading,
|
||||
}),
|
||||
Loading,
|
||||
TabTitle
|
||||
},
|
||||
|
||||
async fetch() {
|
||||
this.rows = await this.$store.dispatch('harvester/findAll', { type: HCI.VMI });
|
||||
@@ -28,17 +36,21 @@ export default {
|
||||
|
||||
mounted() {
|
||||
window.addEventListener('beforeunload', () => {
|
||||
this.$refs.console.close();
|
||||
this.$refs.console?.close();
|
||||
});
|
||||
},
|
||||
|
||||
head() {
|
||||
return { title: this.vmi?.metadata?.name };
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TabTitle
|
||||
v-if="vmi?.metadata?.name"
|
||||
:breadcrumb="false"
|
||||
:show-child="false"
|
||||
>
|
||||
{{ vmi.metadata.name }}
|
||||
</TabTitle>
|
||||
<Loading v-if="$fetchState.pending" />
|
||||
<NovncConsoleWrapper
|
||||
v-else
|
||||
|
||||
@@ -1 +1,24 @@
|
||||
module.exports = require('@rancher/shell/pkg/vue.config')(__dirname);
|
||||
const path = require('path');
|
||||
|
||||
const baseConfig = require('@rancher/shell/pkg/vue.config')(__dirname);
|
||||
|
||||
const baseConfigureWebpack = baseConfig.configureWebpack;
|
||||
|
||||
// noVNC >= 1.7 only publishes `./core/rfb.js` in its `exports` map, so resolve the
|
||||
// package by path to keep the keysym/input helpers importable.
|
||||
const NOVNC_DIR = path.resolve(__dirname, '..', '..', 'node_modules', '@novnc', 'novnc');
|
||||
|
||||
module.exports = {
|
||||
...baseConfig,
|
||||
|
||||
configureWebpack(config) {
|
||||
if (typeof baseConfigureWebpack === 'function') {
|
||||
baseConfigureWebpack(config);
|
||||
}
|
||||
|
||||
config.resolve.alias['@novnc/novnc'] = NOVNC_DIR;
|
||||
|
||||
// noVNC 1.7 uses top-level await for WebCodecs detection.
|
||||
config.output = { ...config.output, environment: { ...config.output?.environment, asyncFunction: true } };
|
||||
}
|
||||
};
|
||||
|
||||
+21
-1
@@ -1,6 +1,26 @@
|
||||
const path = require('path');
|
||||
const config = require('@rancher/shell/vue.config');
|
||||
|
||||
module.exports = config(__dirname, {
|
||||
const baseConfig = config(__dirname, {
|
||||
excludes: [],
|
||||
// excludes: ['harvester']
|
||||
});
|
||||
|
||||
const baseConfigureWebpack = baseConfig.configureWebpack;
|
||||
|
||||
module.exports = {
|
||||
...baseConfig,
|
||||
|
||||
configureWebpack(webpackConfig) {
|
||||
if (typeof baseConfigureWebpack === 'function') {
|
||||
baseConfigureWebpack(webpackConfig);
|
||||
}
|
||||
|
||||
// noVNC >= 1.7 only publishes `./core/rfb.js` in its `exports` map, so resolve the
|
||||
// package by path to keep the keysym/input helpers importable.
|
||||
webpackConfig.resolve.alias['@novnc/novnc'] = path.resolve(__dirname, 'node_modules/@novnc/novnc');
|
||||
|
||||
// noVNC 1.7 uses top-level await for WebCodecs detection.
|
||||
webpackConfig.output = { ...webpackConfig.output, environment: { ...webpackConfig.output?.environment, asyncFunction: true } };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -517,12 +517,7 @@
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
"@babel/compat-data@^7.28.6", "@babel/compat-data@^7.29.0":
|
||||
version "7.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d"
|
||||
integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==
|
||||
|
||||
"@babel/compat-data@^7.29.7":
|
||||
"@babel/compat-data@^7.28.6", "@babel/compat-data@^7.29.0", "@babel/compat-data@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629"
|
||||
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
|
||||
@@ -548,18 +543,7 @@
|
||||
json5 "^2.2.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/generator@^7.29.7", "@babel/generator@^7.7.2":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3"
|
||||
integrity sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
"@jridgewell/gen-mapping" "^0.3.12"
|
||||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/generator@^7.29.8":
|
||||
"@babel/generator@^7.29.7", "@babel/generator@^7.29.8", "@babel/generator@^7.7.2":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.8.tgz#4b0b887885422643339e09022148a4c4ebaa4979"
|
||||
integrity sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==
|
||||
@@ -577,18 +561,7 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.12.16", "@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25"
|
||||
integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.28.6"
|
||||
"@babel/helper-validator-option" "^7.27.1"
|
||||
browserslist "^4.24.0"
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.29.7":
|
||||
"@babel/helper-compilation-targets@^7.12.16", "@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.28.6", "@babel/helper-compilation-targets@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz#7a1def704302401c47f64fa85589e974ae217042"
|
||||
integrity sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==
|
||||
@@ -645,15 +618,7 @@
|
||||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.27.1", "@babel/helper-module-imports@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c"
|
||||
integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.28.6"
|
||||
"@babel/types" "^7.28.6"
|
||||
|
||||
"@babel/helper-module-imports@^7.29.7":
|
||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.27.1", "@babel/helper-module-imports@^7.28.6", "@babel/helper-module-imports@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz#ef25048a518e828d7393fac5882ddd73921d7396"
|
||||
integrity sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==
|
||||
@@ -661,16 +626,7 @@
|
||||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.28.6":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e"
|
||||
integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.28.6"
|
||||
"@babel/helper-validator-identifier" "^7.28.5"
|
||||
"@babel/traverse" "^7.28.6"
|
||||
|
||||
"@babel/helper-module-transforms@^7.29.7":
|
||||
"@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.28.6", "@babel/helper-module-transforms@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae"
|
||||
integrity sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==
|
||||
@@ -722,17 +678,12 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
|
||||
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.28.5", "@babel/helper-validator-identifier@^7.29.7":
|
||||
"@babel/helper-validator-identifier@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
|
||||
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
|
||||
|
||||
"@babel/helper-validator-option@^7.16.7", "@babel/helper-validator-option@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f"
|
||||
integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
|
||||
|
||||
"@babel/helper-validator-option@^7.29.7":
|
||||
"@babel/helper-validator-option@^7.16.7", "@babel/helper-validator-option@^7.27.1", "@babel/helper-validator-option@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a"
|
||||
integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==
|
||||
@@ -754,14 +705,7 @@
|
||||
"@babel/template" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.0", "@babel/parser@^7.29.0", "@babel/parser@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334"
|
||||
integrity sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/parser@^7.29.8":
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.0", "@babel/parser@^7.29.0", "@babel/parser@^7.29.7", "@babel/parser@^7.29.8":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.8.tgz#9653716a2f10c677b98fbc63d4bfb000c302cf17"
|
||||
integrity sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==
|
||||
@@ -926,14 +870,7 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.8.0"
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.2.0", "@babel/plugin-syntax-jsx@^7.27.1":
|
||||
version "7.28.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee"
|
||||
integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.28.6"
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.7.2":
|
||||
"@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.2.0", "@babel/plugin-syntax-jsx@^7.27.1", "@babel/plugin-syntax-jsx@^7.7.2":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz#622c16f9ad63782fe6e83dadc7e40330744b7f1e"
|
||||
integrity sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==
|
||||
@@ -1539,20 +1476,7 @@
|
||||
"@babel/parser" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.0", "@babel/traverse@^7.28.5", "@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0", "@babel/traverse@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d"
|
||||
integrity sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.29.7"
|
||||
"@babel/generator" "^7.29.7"
|
||||
"@babel/helper-globals" "^7.29.7"
|
||||
"@babel/parser" "^7.29.7"
|
||||
"@babel/template" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/traverse@^7.29.8":
|
||||
"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.0", "@babel/traverse@^7.28.5", "@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0", "@babel/traverse@^7.29.7", "@babel/traverse@^7.29.8":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.8.tgz#4111014cdc71a0f95d9471907590baa0b8a6b28a"
|
||||
integrity sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==
|
||||
@@ -1565,15 +1489,7 @@
|
||||
"@babel/types" "^7.29.8"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.29.7", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92"
|
||||
integrity sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.29.7"
|
||||
"@babel/helper-validator-identifier" "^7.29.7"
|
||||
|
||||
"@babel/types@^7.29.8":
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.29.7", "@babel/types@^7.29.8", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
|
||||
version "7.29.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.8.tgz#1229eef31d85156d70fa3f4cd859376d0eaf6863"
|
||||
integrity sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==
|
||||
@@ -1746,20 +1662,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
|
||||
integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
|
||||
|
||||
"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.5.0", "@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1":
|
||||
"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.5.0", "@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1":
|
||||
version "4.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz#8911bd72b2c3640a543609e0400b8c4d2e7e7cb6"
|
||||
integrity sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@eslint-community/eslint-utils@^4.4.0":
|
||||
version "4.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595"
|
||||
integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.12.2":
|
||||
version "4.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b"
|
||||
@@ -2188,10 +2097,10 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@novnc/novnc@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@novnc/novnc/-/novnc-1.2.0.tgz#535ffd7d074022d35205deae2753100f1f2b29f3"
|
||||
integrity sha512-FaUckOedGhSbwQBXk/KGyxKt9ngskg4wPw6ghbHWXOUEmQscAZr3467lTU5DSfppwHJt5k+lQiHoeYUuY90l2Q==
|
||||
"@novnc/novnc@1.2.0", "@novnc/novnc@1.7.0":
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@novnc/novnc/-/novnc-1.7.0.tgz#7f832cf07c66475a81a25708b8e5299a5c4efec5"
|
||||
integrity sha512-ucEJOx4T2avIRCleodk7YobZj5O2Ga2AeLfQ69A/yjG9HHba2+PDgwSkN3FttrmG+70ZGx21sElNFouK13RzyA==
|
||||
|
||||
"@one-ini/wasm@0.1.1":
|
||||
version "0.1.1"
|
||||
@@ -2912,12 +2821,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/esrecurse/-/esrecurse-4.3.1.tgz#6f636af962fbe6191b830bd676ba5986926bccec"
|
||||
integrity sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==
|
||||
|
||||
"@types/estree@*", "@types/estree@^1.0.8":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e"
|
||||
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
|
||||
|
||||
"@types/estree@^1.0.6":
|
||||
"@types/estree@*", "@types/estree@^1.0.6", "@types/estree@^1.0.8":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24"
|
||||
integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==
|
||||
@@ -3167,20 +3071,6 @@
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^2.5.0"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@8.68.0":
|
||||
version "8.68.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.68.0.tgz#a8fbdb1cf49aafaf16071b646daad890151bd149"
|
||||
integrity sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.12.2"
|
||||
"@typescript-eslint/scope-manager" "8.68.0"
|
||||
"@typescript-eslint/type-utils" "8.68.0"
|
||||
"@typescript-eslint/utils" "8.68.0"
|
||||
"@typescript-eslint/visitor-keys" "8.68.0"
|
||||
ignore "^7.0.5"
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^2.5.0"
|
||||
|
||||
"@typescript-eslint/parser@8.62.0":
|
||||
version "8.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.62.0.tgz#8533094fb44427f50b82813c6d3876782f20dc3e"
|
||||
@@ -3192,17 +3082,6 @@
|
||||
"@typescript-eslint/visitor-keys" "8.62.0"
|
||||
debug "^4.4.3"
|
||||
|
||||
"@typescript-eslint/parser@8.68.0":
|
||||
version "8.68.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.68.0.tgz#61de31481354c50457bc9621a7ed746779f09ee7"
|
||||
integrity sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.68.0"
|
||||
"@typescript-eslint/types" "8.68.0"
|
||||
"@typescript-eslint/typescript-estree" "8.68.0"
|
||||
"@typescript-eslint/visitor-keys" "8.68.0"
|
||||
debug "^4.4.3"
|
||||
|
||||
"@typescript-eslint/project-service@8.62.0":
|
||||
version "8.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.62.0.tgz#ab74c1abb4959fb4c3ba7d7edc6554ee245db990"
|
||||
@@ -3258,17 +3137,6 @@
|
||||
debug "^4.4.3"
|
||||
ts-api-utils "^2.5.0"
|
||||
|
||||
"@typescript-eslint/type-utils@8.68.0":
|
||||
version "8.68.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.68.0.tgz#8f3e838dbd740909db27053857468cd037b00220"
|
||||
integrity sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.68.0"
|
||||
"@typescript-eslint/typescript-estree" "8.68.0"
|
||||
"@typescript-eslint/utils" "8.68.0"
|
||||
debug "^4.4.3"
|
||||
ts-api-utils "^2.5.0"
|
||||
|
||||
"@typescript-eslint/types@8.62.0":
|
||||
version "8.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.62.0.tgz#601427c10203d9f0f34f0b3e474df735eb12b593"
|
||||
@@ -3319,7 +3187,7 @@
|
||||
"@typescript-eslint/types" "8.62.0"
|
||||
"@typescript-eslint/typescript-estree" "8.62.0"
|
||||
|
||||
"@typescript-eslint/utils@8.68.0", "@typescript-eslint/utils@^8.0.0", "@typescript-eslint/utils@^8.13.0":
|
||||
"@typescript-eslint/utils@^8.0.0", "@typescript-eslint/utils@^8.13.0":
|
||||
version "8.68.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.68.0.tgz#00547f2c8de8aca2a3c21752a9711f73206fd36d"
|
||||
integrity sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==
|
||||
@@ -4048,12 +3916,7 @@ acorn-walk@^8.0.0, acorn-walk@^8.0.2:
|
||||
dependencies:
|
||||
acorn "^8.11.0"
|
||||
|
||||
acorn@^8.0.4, acorn@^8.0.5, acorn@^8.11.0, acorn@^8.15.0, acorn@^8.16.0:
|
||||
version "8.16.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a"
|
||||
integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==
|
||||
|
||||
acorn@^8.1.0, acorn@^8.8.1:
|
||||
acorn@^8.0.4, acorn@^8.0.5, acorn@^8.1.0, acorn@^8.11.0, acorn@^8.15.0, acorn@^8.16.0, acorn@^8.8.1:
|
||||
version "8.18.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.18.0.tgz#4faf01b2d6d326bfeed97aea1f52220b5f4c1940"
|
||||
integrity sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==
|
||||
@@ -4102,17 +3965,7 @@ ajv-keywords@^5.1.0:
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
|
||||
ajv@^6.12.2, ajv@^6.12.5:
|
||||
version "6.14.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.14.0.tgz#fd067713e228210636ebb08c60bd3765d6dbe73a"
|
||||
integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ajv@^6.14.0:
|
||||
ajv@^6.12.2, ajv@^6.12.5, ajv@^6.14.0:
|
||||
version "6.15.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.15.0.tgz#07e982c74626167aa7a2495c53817892d7139492"
|
||||
integrity sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==
|
||||
@@ -6368,15 +6221,7 @@ end-of-stream@^1.1.0:
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
enhanced-resolve@^5.0.0, enhanced-resolve@^5.20.0:
|
||||
version "5.20.1"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz#eeeb3966bea62c348c40a0cc9e7912e2557d0be0"
|
||||
integrity sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.4"
|
||||
tapable "^2.3.0"
|
||||
|
||||
enhanced-resolve@^5.17.1:
|
||||
enhanced-resolve@^5.0.0, enhanced-resolve@^5.17.1, enhanced-resolve@^5.20.0:
|
||||
version "5.24.5"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz#b4dad3255b7545f07ba5535189868e9f85f47573"
|
||||
integrity sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==
|
||||
@@ -7471,7 +7316,7 @@ global-directory@^4.0.1:
|
||||
dependencies:
|
||||
ini "4.1.1"
|
||||
|
||||
globals@17.7.0:
|
||||
globals@17.7.0, globals@^17.3.0:
|
||||
version "17.7.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-17.7.0.tgz#553d55090b4dde8209ec2da42580d6e7e7d8b10d"
|
||||
integrity sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==
|
||||
@@ -7481,11 +7326,6 @@ globals@^15.11.0, globals@^15.15.0:
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8"
|
||||
integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==
|
||||
|
||||
globals@^17.3.0:
|
||||
version "17.11.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-17.11.0.tgz#d643485bb30220d7751e511cf4f68c73d3870d87"
|
||||
integrity sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==
|
||||
|
||||
globalthis@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236"
|
||||
@@ -7618,14 +7458,7 @@ hasha@^5.0.0:
|
||||
is-stream "^2.0.0"
|
||||
type-fest "^0.8.0"
|
||||
|
||||
hasown@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
hasown@^2.0.3, hasown@^2.0.4:
|
||||
hasown@^2.0.2, hasown@^2.0.3, hasown@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.4.tgz#8c62d8cb90beb2aad5d0a5b67581ad9854c3f003"
|
||||
integrity sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==
|
||||
@@ -8051,14 +7884,7 @@ is-callable@^1.2.7:
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
|
||||
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
|
||||
|
||||
is-core-module@^2.13.0, is-core-module@^2.16.1:
|
||||
version "2.16.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4"
|
||||
integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==
|
||||
dependencies:
|
||||
hasown "^2.0.2"
|
||||
|
||||
is-core-module@^2.16.2:
|
||||
is-core-module@^2.13.0, is-core-module@^2.16.1, is-core-module@^2.16.2:
|
||||
version "2.16.2"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.2.tgz#3e07450a8080ebce3fbf0cac494f4d2ab324e082"
|
||||
integrity sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==
|
||||
@@ -8896,7 +8722,7 @@ js-yaml-loader@1.2.2:
|
||||
loader-utils "^1.2.3"
|
||||
un-eval "^1.2.0"
|
||||
|
||||
js-yaml@4.3.0:
|
||||
js-yaml@4.3.0, js-yaml@^4.1.0, js-yaml@^4.1.1:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.3.0.tgz#d1900572a7f7cf0b5f540c83673e60bad3436592"
|
||||
integrity sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==
|
||||
@@ -8911,13 +8737,6 @@ js-yaml@^3.13.1:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
js-yaml@^4.1.0, js-yaml@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b"
|
||||
integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
|
||||
jsdom@^20.0.0:
|
||||
version "20.0.3"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db"
|
||||
@@ -10262,16 +10081,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.2.tgz#5a942915e26b372dc0f0e6753149a16e6b1c5601"
|
||||
integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==
|
||||
|
||||
picomatch@^4.0.2, picomatch@^4.0.4:
|
||||
picomatch@^4.0.2, picomatch@^4.0.3, picomatch@^4.0.4:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.7.tgz#6313360034ccb36b3dc61ecbdff78121f90fe21f"
|
||||
integrity sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==
|
||||
|
||||
picomatch@^4.0.3:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589"
|
||||
integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
|
||||
|
||||
pirates@^4.0.4:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22"
|
||||
@@ -10536,15 +10350,7 @@ postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-selector-parser@^7.0.0:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz#e75d2e0d843f620e5df69076166f4e16f891cb9f"
|
||||
integrity sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==
|
||||
dependencies:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-selector-parser@^7.1.0:
|
||||
postcss-selector-parser@^7.0.0, postcss-selector-parser@^7.1.0:
|
||||
version "7.1.5"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.1.5.tgz#ee7b090724eb60739b530660e5b402200e694a97"
|
||||
integrity sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==
|
||||
@@ -10738,10 +10544,10 @@ pure-rand@^6.0.0:
|
||||
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2"
|
||||
integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==
|
||||
|
||||
qs@6.15.3, qs@^6.12.3, qs@~6.15.1:
|
||||
version "6.15.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.15.3.tgz#76852132a58ed5c7c0ef67e4441b9bb5d6061b3b"
|
||||
integrity sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==
|
||||
qs@6.16.0, qs@^6.12.3, qs@~6.15.1:
|
||||
version "6.16.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.16.0.tgz#c22c723a28a920f3aacdce8289fabd43eccb79fd"
|
||||
integrity sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==
|
||||
dependencies:
|
||||
es-define-property "^1.0.1"
|
||||
side-channel "^1.1.1"
|
||||
@@ -11864,12 +11670,7 @@ tapable@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
||||
|
||||
tapable@^2.0.0, tapable@^2.2.1, tapable@^2.3.0:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.2.tgz#86755feabad08d82a26b891db044808c6ad00f15"
|
||||
integrity sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==
|
||||
|
||||
tapable@^2.3.3:
|
||||
tapable@^2.0.0, tapable@^2.2.1, tapable@^2.3.0, tapable@^2.3.3:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.3.tgz#5da7c9992c46038221267985ab28421a8879f160"
|
||||
integrity sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==
|
||||
@@ -12166,7 +11967,7 @@ typedarray-to-buffer@^3.1.5:
|
||||
dependencies:
|
||||
is-typedarray "^1.0.0"
|
||||
|
||||
typescript-eslint@8.62.0:
|
||||
typescript-eslint@8.62.0, typescript-eslint@^8.56.0:
|
||||
version "8.62.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.62.0.tgz#7252c3c931637cda28794c0518f321ee89621d67"
|
||||
integrity sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==
|
||||
@@ -12176,16 +11977,6 @@ typescript-eslint@8.62.0:
|
||||
"@typescript-eslint/typescript-estree" "8.62.0"
|
||||
"@typescript-eslint/utils" "8.62.0"
|
||||
|
||||
typescript-eslint@^8.56.0:
|
||||
version "8.68.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.68.0.tgz#c2abd878ba7f9f1248a58060a726342c3357b3a0"
|
||||
integrity sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "8.68.0"
|
||||
"@typescript-eslint/parser" "8.68.0"
|
||||
"@typescript-eslint/typescript-estree" "8.68.0"
|
||||
"@typescript-eslint/utils" "8.68.0"
|
||||
|
||||
typescript@5.6.3:
|
||||
version "5.6.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b"
|
||||
@@ -12973,20 +12764,7 @@ yargs@^16.0.0:
|
||||
y18n "^5.0.5"
|
||||
yargs-parser "^20.2.2"
|
||||
|
||||
yargs@^17.0.0:
|
||||
version "17.7.2"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
|
||||
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
|
||||
dependencies:
|
||||
cliui "^8.0.1"
|
||||
escalade "^3.1.1"
|
||||
get-caller-file "^2.0.5"
|
||||
require-directory "^2.1.1"
|
||||
string-width "^4.2.3"
|
||||
y18n "^5.0.5"
|
||||
yargs-parser "^21.1.1"
|
||||
|
||||
yargs@^17.3.1:
|
||||
yargs@^17.0.0, yargs@^17.3.1:
|
||||
version "17.7.3"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.3.tgz#779dffe6bcafec596a7172e983289a588647faaa"
|
||||
integrity sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==
|
||||
|
||||
Reference in New Issue
Block a user