mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-02-04 06:51:44 +00:00
Compare commits
17 Commits
v1.8.0-dev
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2db7ee7397 | ||
|
|
8b9b5b41b7 | ||
|
|
77599900b5 | ||
|
|
473c1ba355 | ||
|
|
708a95b67b | ||
|
|
fecb3de0cf | ||
|
|
0781bde188 | ||
|
|
0647600e88 | ||
|
|
99dbba7958 | ||
|
|
3dcc50980b | ||
|
|
ee1c3de188 | ||
|
|
915559962a | ||
|
|
b1b1a31c04 | ||
|
|
7f52562d22 | ||
|
|
b140c05697 | ||
|
|
ad9fef63c0 | ||
|
|
786e271ac6 |
3
.github/renovate.json
vendored
3
.github/renovate.json
vendored
@ -7,7 +7,8 @@
|
|||||||
],
|
],
|
||||||
"baseBranches": [
|
"baseBranches": [
|
||||||
"main",
|
"main",
|
||||||
"/^release-harvester-v\\d+\\.\\d+$/"
|
"release-harvester-v1.7",
|
||||||
|
"release-harvester-v1.8"
|
||||||
],
|
],
|
||||||
"automergeMajor": false,
|
"automergeMajor": false,
|
||||||
"semanticCommits": "enabled",
|
"semanticCommits": "enabled",
|
||||||
|
|||||||
34
.github/workflows/fossa.yml
vendored
Normal file
34
.github/workflows/fossa.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
name: FOSSA Scanning
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main", "release-harvester-v*"]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
fossa-scanning:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||||
|
|
||||||
|
# The FOSSA token is shared between all repos in Harvester's GH org. It can
|
||||||
|
# be used directly and there is no need to request specific access to EIO.
|
||||||
|
- name: Read FOSSA token
|
||||||
|
uses: rancher-eio/read-vault-secrets@main
|
||||||
|
with:
|
||||||
|
secrets: |
|
||||||
|
secret/data/github/org/harvester/fossa/credentials token | FOSSA_API_KEY_PUSH_ONLY
|
||||||
|
|
||||||
|
- name: FOSSA scan
|
||||||
|
uses: fossas/fossa-action@main
|
||||||
|
with:
|
||||||
|
api-key: ${{ env.FOSSA_API_KEY_PUSH_ONLY }}
|
||||||
|
# Only runs the scan and do not provide/returns any results back to the
|
||||||
|
# pipeline.
|
||||||
|
run-tests: false
|
||||||
@ -163,7 +163,7 @@ If you want to contribute, start by reading this document, then visit our [Getti
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (c) 2014-2025 [SUSE, LLC.](https://www.suse.com/)
|
Copyright (c) 2014-2026 [SUSE, LLC.](https://www.suse.com/)
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/plugin-transform-class-static-block": "7.28.3",
|
"@babel/plugin-transform-class-static-block": "7.28.6",
|
||||||
"@rancher/shell": "3.0.8-rc.8",
|
"@rancher/shell": "3.0.9-rc.1",
|
||||||
"cache-loader": "^4.1.0",
|
"cache-loader": "^4.1.0",
|
||||||
"color": "4.2.3",
|
"color": "4.2.3",
|
||||||
"ip": "2.0.1",
|
"ip": "2.0.1",
|
||||||
@ -24,12 +24,12 @@
|
|||||||
"glob": "7.2.3",
|
"glob": "7.2.3",
|
||||||
"glob-parent": "6.0.2",
|
"glob-parent": "6.0.2",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"@types/lodash": "4.17.21",
|
"@types/lodash": "4.17.23",
|
||||||
"merge": "2.1.1",
|
"merge": "2.1.1",
|
||||||
"node-forge": "1.3.3",
|
"node-forge": "1.3.3",
|
||||||
"nth-check": "2.1.1",
|
"nth-check": "2.1.1",
|
||||||
"qs": "6.14.1",
|
"qs": "6.14.1",
|
||||||
"roarr": "7.21.2",
|
"roarr": "7.21.4",
|
||||||
"semver": "7.7.3",
|
"semver": "7.7.3",
|
||||||
"@vue/cli-service/html-webpack-plugin": "^5.0.0"
|
"@vue/cli-service/html-webpack-plugin": "^5.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -163,7 +163,7 @@ If you want to contribute, start by reading this document, then visit our [Getti
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (c) 2014-2025 [SUSE, LLC.](https://www.suse.com/)
|
Copyright (c) 2014-2026 [SUSE, LLC.](https://www.suse.com/)
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import Collapse from '@shell/components/Collapse';
|
import Collapse from '@shell/components/Collapse';
|
||||||
import PercentageBar from '@shell/components/PercentageBar';
|
import PercentageBar from '@shell/components/PercentageBar';
|
||||||
|
import { HCI } from '../types';
|
||||||
|
import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HarvesterUpgradeProgressList',
|
name: 'HarvesterUpgradeProgressList',
|
||||||
@ -25,13 +27,45 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
await this.$store.dispatch('harvester/findAll', { type: HCI.UPGRADE });
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return { open: true };
|
return { open: true };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
showResumeButton() {
|
||||||
|
return this.title === 'Upgrading Node';
|
||||||
|
},
|
||||||
|
latestUpgradeCR() {
|
||||||
|
return this.$store.getters['harvester/all'](HCI.UPGRADE).find( (U) => U.isLatestUpgrade);
|
||||||
|
},
|
||||||
|
resumeUpgradePausedNodeEnabled() {
|
||||||
|
return this.$store.getters['harvester-common/getFeatureEnabled']('resumeUpgradePausedNode');
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSwitch() {
|
handleSwitch() {
|
||||||
this.open = !this.open;
|
this.open = !this.open;
|
||||||
|
},
|
||||||
|
async resumeNodeUpgrade(nodeName) {
|
||||||
|
if (!this.latestUpgradeCR || !nodeName) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const upgradePauseMapString = this.latestUpgradeCR.metadata.annotations[HCI_ANNOTATIONS.NODE_UPGRADE_PAUSE_MAP] || '{}';
|
||||||
|
const upgradePauseMap = JSON.parse(upgradePauseMapString);
|
||||||
|
|
||||||
|
// update the upgrade CR annotation harvesterhci.io/node-upgrade-pause-map to unpause the node upgrade process
|
||||||
|
upgradePauseMap[`${ nodeName }`] = 'unpause';
|
||||||
|
this.latestUpgradeCR.setAnnotation(HCI_ANNOTATIONS.NODE_UPGRADE_PAUSE_MAP, JSON.stringify(upgradePauseMap));
|
||||||
|
await this.latestUpgradeCR.save();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`unable to update harvester upgrade CR annotations: ${ this.latestUpgradeCR.id }.`, e); // eslint-disable-line no-console
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -63,12 +97,28 @@ export default {
|
|||||||
v-for="(item, i) in list"
|
v-for="(item, i) in list"
|
||||||
:key="i"
|
:key="i"
|
||||||
>
|
>
|
||||||
<p>
|
<div class="upgrade-node-header">
|
||||||
{{ item.name }} <span
|
<div class="upgrade-node-title">
|
||||||
class="status"
|
<p>
|
||||||
:class="{ [item.state]: true }"
|
{{ item.name }}
|
||||||
>{{ item.state }}</span>
|
</p>
|
||||||
</p>
|
<span
|
||||||
|
class="status"
|
||||||
|
:class="{ [item.state]: true }"
|
||||||
|
>
|
||||||
|
{{ item.state }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
v-if="showResumeButton && resumeUpgradePausedNodeEnabled && item.state === 'Node-upgrade paused'"
|
||||||
|
type="button"
|
||||||
|
class="btn bg-info btn-sm"
|
||||||
|
data-testid="add-item"
|
||||||
|
@click="resumeNodeUpgrade(item.name)"
|
||||||
|
>
|
||||||
|
{{ t('action.resume') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<PercentageBar
|
<PercentageBar
|
||||||
:model-value="item.percent"
|
:model-value="item.percent"
|
||||||
preferred-direction="MORE"
|
preferred-direction="MORE"
|
||||||
@ -102,10 +152,21 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.custom-content {
|
.custom-content {
|
||||||
margin-bottom: 14px;
|
.upgrade-node-title {
|
||||||
p {
|
flex: 1 0 80%;
|
||||||
|
margin-right: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.upgrade-node-header {
|
||||||
|
display:flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
margin-bottom: 14px;
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
@ -117,6 +178,8 @@ export default {
|
|||||||
}
|
}
|
||||||
.warning {
|
.warning {
|
||||||
color: var(--error);
|
color: var(--error);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import { LabeledInput } from '@components/Form/LabeledInput';
|
|||||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
import { RadioGroup } from '@components/Form/Radio';
|
import { RadioGroup } from '@components/Form/Radio';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { allHash } from '@shell/utils/promise';
|
||||||
|
import { NODE } from '@shell/config/types';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HarvesterUpgradeConfig',
|
name: 'HarvesterUpgradeConfig',
|
||||||
@ -15,6 +17,13 @@ export default {
|
|||||||
},
|
},
|
||||||
mixins: [CreateEditView],
|
mixins: [CreateEditView],
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
const hash = { nodes: this.$store.dispatch(`${ inStore }/findAll`, { type: NODE }) };
|
||||||
|
|
||||||
|
await allHash(hash);
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
let parseDefaultValue = {};
|
let parseDefaultValue = {};
|
||||||
|
|
||||||
@ -39,7 +48,25 @@ export default {
|
|||||||
{ value: 'skip', label: 'skip' },
|
{ value: 'skip', label: 'skip' },
|
||||||
{ value: 'parallel', label: 'parallel' }
|
{ value: 'parallel', label: 'parallel' }
|
||||||
];
|
];
|
||||||
}
|
},
|
||||||
|
nodeUpgradeOptions() {
|
||||||
|
return [
|
||||||
|
{ value: 'auto', label: 'auto' },
|
||||||
|
{ value: 'manual', label: 'manual' }
|
||||||
|
];
|
||||||
|
},
|
||||||
|
nodesOptions() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
const nodes = this.$store.getters[`${ inStore }/all`](NODE);
|
||||||
|
|
||||||
|
return nodes.map((node) => ({ value: node.id, label: node.name }));
|
||||||
|
},
|
||||||
|
showPauseNodes() {
|
||||||
|
return this.parseDefaultValue.nodeUpgradeOption?.strategy?.mode === 'manual';
|
||||||
|
},
|
||||||
|
resumeUpgradePausedNodeEnabled() {
|
||||||
|
return this.$store.getters['harvester-common/getFeatureEnabled']('resumeUpgradePausedNode');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
@ -48,6 +75,18 @@ export default {
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
normalizeValue(obj) {
|
normalizeValue(obj) {
|
||||||
|
// handle nodeUpgradeOption.strategy
|
||||||
|
if (obj?.nodeUpgradeOption?.strategy?.mode === 'auto') {
|
||||||
|
delete obj.nodeUpgradeOption.strategy.pauseNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj?.nodeUpgradeOption?.strategy?.mode === 'manual') {
|
||||||
|
if (!Array.isArray(obj.nodeUpgradeOption.strategy.pauseNodes)) {
|
||||||
|
obj.nodeUpgradeOption.strategy.pauseNodes = this.nodesOptions.map((node) => node.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle imagePreloadOption.strategy
|
||||||
if (!obj.imagePreloadOption) {
|
if (!obj.imagePreloadOption) {
|
||||||
obj.imagePreloadOption = { strategy: { type: 'sequential' } };
|
obj.imagePreloadOption = { strategy: { type: 'sequential' } };
|
||||||
}
|
}
|
||||||
@ -105,8 +144,8 @@ export default {
|
|||||||
this.update();
|
this.update();
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -144,6 +183,28 @@ export default {
|
|||||||
:labels="[t('generic.enabled'), t('generic.disabled')]"
|
:labels="[t('generic.enabled'), t('generic.disabled')]"
|
||||||
@update:value="update"
|
@update:value="update"
|
||||||
/>
|
/>
|
||||||
|
<div v-if="resumeUpgradePausedNodeEnabled">
|
||||||
|
<label class="mb-5"><b>{{ t('harvester.setting.upgrade.nodeUpgradeOption') }}</b></label>
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="parseDefaultValue.nodeUpgradeOption.strategy.mode"
|
||||||
|
class="mb-20 label-select"
|
||||||
|
:mode="mode"
|
||||||
|
:label="t('harvester.setting.upgrade.strategy')"
|
||||||
|
:options="nodeUpgradeOptions"
|
||||||
|
@update:value="update"
|
||||||
|
/>
|
||||||
|
<LabeledSelect
|
||||||
|
v-if="showPauseNodes"
|
||||||
|
v-model:value="parseDefaultValue.nodeUpgradeOption.strategy.pauseNodes"
|
||||||
|
class="mb-20 label-select"
|
||||||
|
:clearable="true"
|
||||||
|
:multiple="true"
|
||||||
|
:mode="mode"
|
||||||
|
:label="t('harvester.setting.upgrade.pauseNodes')"
|
||||||
|
:options="nodesOptions"
|
||||||
|
@update:value="update"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="errors.length"
|
v-if="errors.length"
|
||||||
class="error"
|
class="error"
|
||||||
|
|||||||
@ -54,8 +54,11 @@ const FEATURE_FLAGS = {
|
|||||||
'lhV2VolExpansion',
|
'lhV2VolExpansion',
|
||||||
'l2VlanTrunkMode',
|
'l2VlanTrunkMode',
|
||||||
'kubevirtMigration',
|
'kubevirtMigration',
|
||||||
'hotplugNic'
|
'hotplugNic',
|
||||||
]
|
'resumeUpgradePausedNode',
|
||||||
|
],
|
||||||
|
'v1.7.1': [],
|
||||||
|
'v1.8.0': []
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateFeatureFlags = () => {
|
const generateFeatureFlags = () => {
|
||||||
|
|||||||
@ -35,8 +35,21 @@ import {
|
|||||||
SNAPSHOT_TARGET_VOLUME,
|
SNAPSHOT_TARGET_VOLUME,
|
||||||
IMAGE_VIRTUAL_SIZE,
|
IMAGE_VIRTUAL_SIZE,
|
||||||
IMAGE_STORAGE_CLASS,
|
IMAGE_STORAGE_CLASS,
|
||||||
HARVESTER_DESCRIPTION
|
HARVESTER_DESCRIPTION,
|
||||||
|
VM_IMPORT_SOURCE_VM,
|
||||||
|
VM_IMPORT_SOURCE_CLUSTER,
|
||||||
|
VM_IMPORT_STATUS,
|
||||||
|
VM_IMPORT_SOURCE_V_DC,
|
||||||
|
VM_IMPORT_SOURCE_V_ENDPOINT,
|
||||||
|
VM_IMPORT_SOURCE_V_STATUS,
|
||||||
|
VM_IMPORT_SOURCE_O_REGION,
|
||||||
|
VM_IMPORT_SOURCE_O_ENDPOINT,
|
||||||
|
VM_IMPORT_SOURCE_O_STATUS,
|
||||||
|
VM_IMPORT_SOURCE_OVA_URL,
|
||||||
|
VM_IMPORT_SOURCE_OVA_STATUS,
|
||||||
} from './table-headers';
|
} from './table-headers';
|
||||||
|
import { ADD_ONS } from './harvester-map';
|
||||||
|
import { registerAddonSideNav } from '../utils/dynamic-nav';
|
||||||
|
|
||||||
const TEMPLATE = HCI.VM_VERSION;
|
const TEMPLATE = HCI.VM_VERSION;
|
||||||
const MONITORING_GROUP = 'Monitoring & Logging::Monitoring';
|
const MONITORING_GROUP = 'Monitoring & Logging::Monitoring';
|
||||||
@ -195,6 +208,142 @@ export function init($plugin, store) {
|
|||||||
exact: false
|
exact: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// VM Import Controller UI Flow
|
||||||
|
// ===========================================================================
|
||||||
|
// Define group (Hidden by default)
|
||||||
|
weightGroup('vmimport', 0, false);
|
||||||
|
|
||||||
|
// VirtualMachineImport
|
||||||
|
headers(HCI.VMIMPORT, [
|
||||||
|
STATE,
|
||||||
|
NAME_COL,
|
||||||
|
NAMESPACE_COL,
|
||||||
|
VM_IMPORT_SOURCE_VM,
|
||||||
|
VM_IMPORT_SOURCE_CLUSTER,
|
||||||
|
VM_IMPORT_STATUS,
|
||||||
|
AGE
|
||||||
|
]);
|
||||||
|
configureType(HCI.VMIMPORT, {
|
||||||
|
resource: HCI.VMIMPORT,
|
||||||
|
resourceDetail: HCI.VMIMPORT,
|
||||||
|
resourceEdit: HCI.VMIMPORT,
|
||||||
|
location: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
virtualType({ // needed to avoid 404 on refresh when combined with registerAddonSideNav()
|
||||||
|
name: HCI.VMIMPORT,
|
||||||
|
labelKey: 'harvester.addons.vmImport.labels.vmimport',
|
||||||
|
group: 'vmimport',
|
||||||
|
namespaced: true,
|
||||||
|
route: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Source: VMware
|
||||||
|
headers(HCI.VMIMPORT_SOURCE_V, [
|
||||||
|
STATE,
|
||||||
|
NAME_COL,
|
||||||
|
VM_IMPORT_SOURCE_V_ENDPOINT,
|
||||||
|
VM_IMPORT_SOURCE_V_DC,
|
||||||
|
VM_IMPORT_SOURCE_V_STATUS,
|
||||||
|
AGE
|
||||||
|
]);
|
||||||
|
configureType(HCI.VMIMPORT_SOURCE_V, {
|
||||||
|
resource: HCI.VMIMPORT_SOURCE_V,
|
||||||
|
resourceDetail: HCI.VMIMPORT_SOURCE_V,
|
||||||
|
resourceEdit: HCI.VMIMPORT_SOURCE_V,
|
||||||
|
location: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT_SOURCE_V }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
virtualType({ // needed to avoid 404 on refresh when combined with registerAddonSideNav()
|
||||||
|
name: HCI.VMIMPORT_SOURCE_V,
|
||||||
|
labelKey: 'harvester.addons.vmImport.labels.vmimportSourceVMWare',
|
||||||
|
group: 'vmimport',
|
||||||
|
namespaced: true,
|
||||||
|
route: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT_SOURCE_V }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Source: OpenStack
|
||||||
|
headers(HCI.VMIMPORT_SOURCE_O, [
|
||||||
|
STATE,
|
||||||
|
NAME_COL,
|
||||||
|
VM_IMPORT_SOURCE_O_ENDPOINT,
|
||||||
|
VM_IMPORT_SOURCE_O_REGION,
|
||||||
|
VM_IMPORT_SOURCE_O_STATUS,
|
||||||
|
AGE
|
||||||
|
]);
|
||||||
|
configureType(HCI.VMIMPORT_SOURCE_O, {
|
||||||
|
resource: HCI.VMIMPORT_SOURCE_O,
|
||||||
|
resourceDetail: HCI.VMIMPORT_SOURCE_O,
|
||||||
|
resourceEdit: HCI.VMIMPORT_SOURCE_O,
|
||||||
|
location: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT_SOURCE_O }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
virtualType({ // needed to avoid 404 on refresh when combined with registerAddonSideNav()
|
||||||
|
name: HCI.VMIMPORT_SOURCE_O,
|
||||||
|
labelKey: 'harvester.addons.vmImport.labels.vmimportSourceOpenStack',
|
||||||
|
group: 'vmimport',
|
||||||
|
namespaced: true,
|
||||||
|
route: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT_SOURCE_O }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Source: OVA
|
||||||
|
headers(HCI.VMIMPORT_SOURCE_OVA, [
|
||||||
|
STATE,
|
||||||
|
NAME_COL,
|
||||||
|
VM_IMPORT_SOURCE_OVA_URL,
|
||||||
|
VM_IMPORT_SOURCE_OVA_STATUS,
|
||||||
|
AGE
|
||||||
|
]);
|
||||||
|
configureType(HCI.VMIMPORT_SOURCE_OVA, {
|
||||||
|
resource: HCI.VMIMPORT_SOURCE_OVA,
|
||||||
|
resourceDetail: HCI.VMIMPORT_SOURCE_OVA,
|
||||||
|
resourceEdit: HCI.VMIMPORT_SOURCE_OVA,
|
||||||
|
location: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT_SOURCE_OVA }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
virtualType({ // needed to avoid 404 on refresh when combined with registerAddonSideNav()
|
||||||
|
name: HCI.VMIMPORT_SOURCE_OVA,
|
||||||
|
labelKey: 'harvester.addons.vmImport.labels.vmimportSourceOVA',
|
||||||
|
group: 'vmimport',
|
||||||
|
namespaced: true,
|
||||||
|
route: {
|
||||||
|
name: `${ PRODUCT_NAME }-c-cluster-resource`,
|
||||||
|
params: { resource: HCI.VMIMPORT_SOURCE_OVA }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enable SideNav based on Addon Status
|
||||||
|
registerAddonSideNav(store, PRODUCT_NAME, {
|
||||||
|
addonName: ADD_ONS.VM_IMPORT_CONTROLLER,
|
||||||
|
resourceType: HCI.ADD_ONS,
|
||||||
|
navGroup: 'vmimport',
|
||||||
|
types: [
|
||||||
|
HCI.VMIMPORT_SOURCE_V,
|
||||||
|
HCI.VMIMPORT_SOURCE_O,
|
||||||
|
HCI.VMIMPORT_SOURCE_OVA,
|
||||||
|
HCI.VMIMPORT
|
||||||
|
]
|
||||||
|
});
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
basicType([HCI.VOLUME]);
|
basicType([HCI.VOLUME]);
|
||||||
configureType(HCI.VOLUME, {
|
configureType(HCI.VOLUME, {
|
||||||
location: {
|
location: {
|
||||||
|
|||||||
@ -78,4 +78,5 @@ export const HCI = {
|
|||||||
VOLUME_MODE_ACCESS_MODES: 'cdi.harvesterhci.io/storageProfileVolumeModeAccessModes',
|
VOLUME_MODE_ACCESS_MODES: 'cdi.harvesterhci.io/storageProfileVolumeModeAccessModes',
|
||||||
VOLUME_SNAPSHOT_CLASS: 'cdi.harvesterhci.io/storageProfileVolumeSnapshotClass',
|
VOLUME_SNAPSHOT_CLASS: 'cdi.harvesterhci.io/storageProfileVolumeSnapshotClass',
|
||||||
MAC_ADDRESS: 'harvesterhci.io/mac-address',
|
MAC_ADDRESS: 'harvesterhci.io/mac-address',
|
||||||
|
NODE_UPGRADE_PAUSE_MAP: 'harvesterhci.io/node-upgrade-pause-map',
|
||||||
};
|
};
|
||||||
|
|||||||
@ -131,3 +131,102 @@ export const PROVIDER = {
|
|||||||
value: 'spec.provider',
|
value: 'spec.provider',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Source VM column in migration.harvesterhci.io.virtualmachineimport list page
|
||||||
|
export const VM_IMPORT_SOURCE_VM = {
|
||||||
|
name: 'sourceVm',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceVm',
|
||||||
|
value: 'spec.virtualMachineName',
|
||||||
|
sort: 'spec.virtualMachineName',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Source Cluster column in migration.harvesterhci.io.virtualmachineimport list page
|
||||||
|
export const VM_IMPORT_SOURCE_CLUSTER = {
|
||||||
|
name: 'sourceCluster',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceCluster',
|
||||||
|
value: 'spec.sourceCluster.name',
|
||||||
|
sort: 'spec.sourceCluster.name',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Import Status column in migration.harvesterhci.io.virtualmachineimport list page
|
||||||
|
export const VM_IMPORT_STATUS = {
|
||||||
|
name: 'importStatus',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportStatus',
|
||||||
|
value: 'status.importStatus',
|
||||||
|
sort: 'status.importStatus',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Datacenter column in migration.harvesterhci.io.vmwaresource list page
|
||||||
|
export const VM_IMPORT_SOURCE_V_DC = {
|
||||||
|
name: 'datacenter',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceVDatacenter',
|
||||||
|
value: 'spec.dc',
|
||||||
|
sort: 'spec.dc',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Endpoint column in migration.harvesterhci.io.vmwaresource list page
|
||||||
|
export const VM_IMPORT_SOURCE_V_ENDPOINT = {
|
||||||
|
name: 'endpoint',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceVEndpoint',
|
||||||
|
value: 'spec.endpoint',
|
||||||
|
sort: 'spec.endpoint',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cluster Status column in migration.harvesterhci.io.vmwaresource list page
|
||||||
|
export const VM_IMPORT_SOURCE_V_STATUS = {
|
||||||
|
name: 'clusterStatus',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceVClusterStatus',
|
||||||
|
value: 'status.status',
|
||||||
|
sort: 'status.status',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Region column in migration.harvesterhci.io.openstacksource list page
|
||||||
|
export const VM_IMPORT_SOURCE_O_REGION = {
|
||||||
|
name: 'region',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceORegion',
|
||||||
|
value: 'spec.region',
|
||||||
|
sort: 'spec.region',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Endpoint column in migration.harvesterhci.io.openstacksource list page
|
||||||
|
export const VM_IMPORT_SOURCE_O_ENDPOINT = {
|
||||||
|
name: 'endpoint',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceOEndpoint',
|
||||||
|
value: 'spec.endpoint',
|
||||||
|
sort: 'spec.endpoint',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cluster Status column in migration.harvesterhci.io.openstacksource list page
|
||||||
|
export const VM_IMPORT_SOURCE_O_STATUS = {
|
||||||
|
name: 'clusterStatus',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceOClusterStatus',
|
||||||
|
value: 'status.status',
|
||||||
|
sort: 'status.status',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// URL column in migration.harvesterhci.io.ovasource list page
|
||||||
|
export const VM_IMPORT_SOURCE_OVA_URL = {
|
||||||
|
name: 'url',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceOVAUrl',
|
||||||
|
value: 'spec.url',
|
||||||
|
sort: 'spec.url',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Status column in migration.harvesterhci.io.ovasource list page
|
||||||
|
export const VM_IMPORT_SOURCE_OVA_STATUS = {
|
||||||
|
name: 'status',
|
||||||
|
labelKey: 'harvester.tableHeaders.vmImportSourceOVAStatus',
|
||||||
|
value: 'status.status',
|
||||||
|
sort: 'status.status',
|
||||||
|
align: 'left',
|
||||||
|
};
|
||||||
|
|||||||
@ -29,3 +29,15 @@ export const L2VLAN_MODE = {
|
|||||||
ACCESS: 'access',
|
ACCESS: 'access',
|
||||||
TRUNK: 'trunk',
|
TRUNK: 'trunk',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const VMIMPORT_SOURCE_PROVIDER = {
|
||||||
|
VMWARE: 'vmware',
|
||||||
|
OPENSTACK: 'openstack',
|
||||||
|
OVA: 'ova',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const VMIMPORT_SOURCE_KINDS = {
|
||||||
|
VMWARE: 'VmwareSource',
|
||||||
|
OPENSTACK: 'OpenstackSource',
|
||||||
|
OVA: 'OvaSource',
|
||||||
|
};
|
||||||
|
|||||||
@ -277,8 +277,9 @@ export default {
|
|||||||
:label="t('harvester.modal.bundle.namespaces.label')"
|
:label="t('harvester.modal.bundle.namespaces.label')"
|
||||||
:clearable="true"
|
:clearable="true"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
|
:append-to-body="false"
|
||||||
:options="namespaceOptions"
|
:options="namespaceOptions"
|
||||||
class="mb-10 label-select"
|
class="mb-10 namespace-select"
|
||||||
:tooltip="t('harvester.modal.bundle.namespaces.tooltip', _, true)"
|
:tooltip="t('harvester.modal.bundle.namespaces.tooltip', _, true)"
|
||||||
@update:value="updateNamespaces"
|
@update:value="updateNamespaces"
|
||||||
/>
|
/>
|
||||||
@ -372,6 +373,11 @@ export default {
|
|||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
height: 160px;
|
height: 160px;
|
||||||
}
|
}
|
||||||
|
.namespace-select {
|
||||||
|
:deep(.vs__dropdown-menu) {
|
||||||
|
max-height: 210px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
|
|||||||
@ -54,6 +54,11 @@ export default {
|
|||||||
|
|
||||||
const vmDevices = this.value?.domain?.devices?.hostDevices || [];
|
const vmDevices = this.value?.domain?.devices?.hostDevices || [];
|
||||||
const otherDevices = this.otherDevices(vmDevices).map(({ name }) => name);
|
const otherDevices = this.otherDevices(vmDevices).map(({ name }) => name);
|
||||||
|
const vmDeviceNames = vmDevices.map(({ name }) => name);
|
||||||
|
|
||||||
|
this.pciDevices.forEach((row) => {
|
||||||
|
row.allowDisable = !vmDeviceNames.includes(row.metadata.name);
|
||||||
|
});
|
||||||
|
|
||||||
vmDevices.forEach(({ name, deviceName }) => {
|
vmDevices.forEach(({ name, deviceName }) => {
|
||||||
const checkName = (deviceName || '').split('/')?.[1];
|
const checkName = (deviceName || '').split('/')?.[1];
|
||||||
|
|||||||
@ -48,6 +48,13 @@ export default {
|
|||||||
this[key] = res[key];
|
this[key] = res[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vmDevices = this.value?.domain?.devices?.hostDevices || [];
|
||||||
|
const vmDeviceNames = vmDevices.map(({ name }) => name);
|
||||||
|
|
||||||
|
this.devices.forEach((row) => {
|
||||||
|
row.allowDisable = !vmDeviceNames.includes(row.metadata.name);
|
||||||
|
});
|
||||||
|
|
||||||
this.selectedDevices = (this.value?.domain?.devices?.hostDevices || [])
|
this.selectedDevices = (this.value?.domain?.devices?.hostDevices || [])
|
||||||
.map(({ name }) => name)
|
.map(({ name }) => name)
|
||||||
.filter((name) => this.enabledDevices.find((device) => device?.metadata?.name === name));
|
.filter((name) => this.enabledDevices.find((device) => device?.metadata?.name === name));
|
||||||
|
|||||||
@ -46,6 +46,13 @@ export default {
|
|||||||
this[key] = res[key];
|
this[key] = res[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vmDevices = this.value?.domain?.devices?.gpus || [];
|
||||||
|
const vmDeviceNames = vmDevices.map(({ name }) => name);
|
||||||
|
|
||||||
|
this.devices.forEach((row) => {
|
||||||
|
row.allowDisable = !vmDeviceNames.includes(row.metadata.name);
|
||||||
|
});
|
||||||
|
|
||||||
const vGpus = this.vm.isOff ? [
|
const vGpus = this.vm.isOff ? [
|
||||||
...(this.value?.domain?.devices?.gpus || []).map(({ name }) => name),
|
...(this.value?.domain?.devices?.gpus || []).map(({ name }) => name),
|
||||||
] : [
|
] : [
|
||||||
|
|||||||
357
pkg/harvester/edit/migration.harvesterhci.io.openstacksource.vue
Normal file
357
pkg/harvester/edit/migration.harvesterhci.io.openstacksource.vue
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
<script>
|
||||||
|
import CruResource from '@shell/components/CruResource';
|
||||||
|
import Tabbed from '@shell/components/Tabbed';
|
||||||
|
import Tab from '@shell/components/Tabbed/Tab';
|
||||||
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||||
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
|
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
||||||
|
import { RadioGroup } from '@components/Form/Radio';
|
||||||
|
import UnitInput from '@shell/components/form/UnitInput';
|
||||||
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||||
|
import FormValidation from '@shell/mixins/form-validation';
|
||||||
|
import { SECRET } from '@shell/config/types';
|
||||||
|
import { randomStr } from '@shell/utils/string';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EditOpenstackSource',
|
||||||
|
|
||||||
|
emits: ['update:value'],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
CruResource,
|
||||||
|
Tabbed,
|
||||||
|
Tab,
|
||||||
|
LabeledInput,
|
||||||
|
LabeledSelect,
|
||||||
|
NameNsDescription,
|
||||||
|
RadioGroup,
|
||||||
|
UnitInput
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [CreateEditView, FormValidation],
|
||||||
|
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
this.allSecrets = await this.$store.dispatch(`${ inStore }/findAll`, { type: SECRET });
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
if (!this.value.spec) this.value.spec = {};
|
||||||
|
if (!this.value.spec.credentials) this.value.spec.credentials = {};
|
||||||
|
|
||||||
|
const initialMode = this.value.spec.credentials.name ? 'existing' : 'new';
|
||||||
|
|
||||||
|
return {
|
||||||
|
allSecrets: [],
|
||||||
|
authMode: initialMode,
|
||||||
|
|
||||||
|
newUsername: '',
|
||||||
|
newPassword: '',
|
||||||
|
newProjectName: '',
|
||||||
|
newDomainName: '',
|
||||||
|
newCaCert: '',
|
||||||
|
|
||||||
|
// Rules for fields that exist in the value object (Model)
|
||||||
|
fvFormRuleSets: [
|
||||||
|
{ path: 'metadata.name', rules: ['nameRequired'] },
|
||||||
|
{ path: 'spec.endpoint', rules: ['endpointRequired'] },
|
||||||
|
{ path: 'spec.region', rules: ['regionRequired'] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters({ t: 'i18n/t' }),
|
||||||
|
|
||||||
|
authModeOptions() {
|
||||||
|
return [
|
||||||
|
{ label: this.t('harvester.addons.vmImport.fields.createSecret'), value: 'new' },
|
||||||
|
{ label: this.t('harvester.addons.vmImport.fields.useSecret'), value: 'existing' }
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
secretOptions() {
|
||||||
|
const currentNamespace = this.value.metadata.namespace || 'default';
|
||||||
|
|
||||||
|
return this.allSecrets
|
||||||
|
.filter((s) => s.metadata.namespace === currentNamespace)
|
||||||
|
.map((s) => ({
|
||||||
|
label: s.nameDisplay,
|
||||||
|
value: s.metadata.name
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
// Define custom rules for the FormValidation mixin
|
||||||
|
fvExtraRules() {
|
||||||
|
return {
|
||||||
|
nameRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.fields.name') }) : undefined,
|
||||||
|
endpointRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.openstack.fields.endpoint') }) : undefined,
|
||||||
|
regionRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.openstack.fields.region') }) : undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// Combine mixin validation + conditional manual checks
|
||||||
|
isFormValid() {
|
||||||
|
// Check static fields via Mixin
|
||||||
|
if (!this.fvFormIsValid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check conditional fields
|
||||||
|
if (this.authMode === 'new') {
|
||||||
|
if (!this.newUsername || !this.newPassword) return false;
|
||||||
|
if (!this.newProjectName || !this.newDomainName) return false;
|
||||||
|
} else {
|
||||||
|
if (!this.value.spec.credentials.name) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
usernameRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.username') }) : undefined;
|
||||||
|
},
|
||||||
|
passwordRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.password') }) : undefined;
|
||||||
|
},
|
||||||
|
projectRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.openstack.fields.projectName') }) : undefined;
|
||||||
|
},
|
||||||
|
domainRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.openstack.fields.domainName') }) : undefined;
|
||||||
|
},
|
||||||
|
secretRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.selectSecret') }) : undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveSource(buttonCb) {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.authMode === 'new') {
|
||||||
|
const secretName = `${ this.value.metadata.name }-creds-${ randomStr(4).toLowerCase() }`;
|
||||||
|
const namespace = this.value.metadata.namespace || 'default';
|
||||||
|
|
||||||
|
const newSecret = await this.$store.dispatch(`${ inStore }/create`, {
|
||||||
|
type: SECRET,
|
||||||
|
metadata: {
|
||||||
|
name: secretName,
|
||||||
|
namespace
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
newSecret['_type'] = 'Opaque';
|
||||||
|
newSecret['data'] = {
|
||||||
|
username: btoa(this.newUsername),
|
||||||
|
password: btoa(this.newPassword),
|
||||||
|
project_name: btoa(this.newProjectName),
|
||||||
|
domain_name: btoa(this.newDomainName),
|
||||||
|
ca_cert: this.newCaCert ? btoa(this.newCaCert) : undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
await newSecret.save();
|
||||||
|
|
||||||
|
this.value.spec.credentials = {
|
||||||
|
name: secretName,
|
||||||
|
namespace
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.save(buttonCb);
|
||||||
|
} catch (err) {
|
||||||
|
this.errors = [err];
|
||||||
|
buttonCb(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CruResource
|
||||||
|
:done-route="doneRoute"
|
||||||
|
:resource="value"
|
||||||
|
:mode="mode"
|
||||||
|
:errors="errors"
|
||||||
|
:apply-hooks="applyHooks"
|
||||||
|
:validation-passed="isFormValid"
|
||||||
|
@finish="saveSource"
|
||||||
|
@error="e=>errors=e"
|
||||||
|
>
|
||||||
|
<NameNsDescription
|
||||||
|
:value="value"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="{ name: fvGetAndReportPathRules('metadata.name') }"
|
||||||
|
@update:value="$emit('update:value', $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Tabbed
|
||||||
|
v-bind="$attrs"
|
||||||
|
class="mt-15"
|
||||||
|
:side-tabs="true"
|
||||||
|
>
|
||||||
|
<Tab
|
||||||
|
name="basic"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.basic')"
|
||||||
|
:weight="3"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.spec.endpoint"
|
||||||
|
:label="t('harvester.addons.vmImport.openstack.fields.endpoint')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.openstack.placeholders.endpoint')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="fvGetAndReportPathRules('spec.endpoint')"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.spec.region"
|
||||||
|
:label="t('harvester.addons.vmImport.openstack.fields.region')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.openstack.placeholders.region')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="fvGetAndReportPathRules('spec.region')"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
name="auth"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.auth')"
|
||||||
|
:weight="2"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-12">
|
||||||
|
<RadioGroup
|
||||||
|
v-model:value="authMode"
|
||||||
|
name="authMode"
|
||||||
|
:options="authModeOptions"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="authMode === 'new'">
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newUsername"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.username')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[usernameRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newPassword"
|
||||||
|
type="password"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.password')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[passwordRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newProjectName"
|
||||||
|
:label="t('harvester.addons.vmImport.openstack.fields.projectName')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.openstack.placeholders.projectName')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[projectRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newDomainName"
|
||||||
|
:label="t('harvester.addons.vmImport.openstack.fields.domainName')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.openstack.placeholders.domainName')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[domainRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-12">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newCaCert"
|
||||||
|
type="multiline"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.caCert')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.placeholders.caCert')"
|
||||||
|
:min-height="100"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="authMode === 'existing'">
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="value.spec.credentials.name"
|
||||||
|
:options="secretOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.selectSecret')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[secretRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
name="advanced"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.advanced')"
|
||||||
|
:weight="1"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<UnitInput
|
||||||
|
v-model:value="value.spec.uploadImageRetryCount"
|
||||||
|
:label="t('harvester.addons.vmImport.openstack.fields.retryCount')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.openstack.placeholders.retryCount')"
|
||||||
|
suffix="Times"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<UnitInput
|
||||||
|
v-model:value="value.spec.uploadImageRetryDelay"
|
||||||
|
:label="t('harvester.addons.vmImport.openstack.fields.retryDelay')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.openstack.placeholders.retryDelay')"
|
||||||
|
suffix="Seconds"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
</Tabbed>
|
||||||
|
</CruResource>
|
||||||
|
</template>
|
||||||
322
pkg/harvester/edit/migration.harvesterhci.io.ovasource.vue
Normal file
322
pkg/harvester/edit/migration.harvesterhci.io.ovasource.vue
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
<script>
|
||||||
|
import CruResource from '@shell/components/CruResource';
|
||||||
|
import Tabbed from '@shell/components/Tabbed';
|
||||||
|
import Tab from '@shell/components/Tabbed/Tab';
|
||||||
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||||
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
|
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
||||||
|
import { RadioGroup } from '@components/Form/Radio';
|
||||||
|
import UnitInput from '@shell/components/form/UnitInput';
|
||||||
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||||
|
import FormValidation from '@shell/mixins/form-validation';
|
||||||
|
import { SECRET } from '@shell/config/types';
|
||||||
|
import { randomStr } from '@shell/utils/string';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EditOvaSource',
|
||||||
|
|
||||||
|
emits: ['update:value'],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
CruResource,
|
||||||
|
Tabbed,
|
||||||
|
Tab,
|
||||||
|
LabeledInput,
|
||||||
|
LabeledSelect,
|
||||||
|
NameNsDescription,
|
||||||
|
RadioGroup,
|
||||||
|
UnitInput
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [CreateEditView, FormValidation],
|
||||||
|
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
this.allSecrets = await this.$store.dispatch(`${ inStore }/findAll`, { type: SECRET });
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
if (!this.value.spec) this.value.spec = {};
|
||||||
|
|
||||||
|
// Auth is optional for OVA (public URLs).
|
||||||
|
// If credentials.name exists -> Existing.
|
||||||
|
// If not -> None (default).
|
||||||
|
let initialMode = 'none';
|
||||||
|
|
||||||
|
if (this.value.spec.credentials?.name) {
|
||||||
|
initialMode = 'existing';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
allSecrets: [],
|
||||||
|
authMode: initialMode,
|
||||||
|
|
||||||
|
newUsername: '',
|
||||||
|
newPassword: '',
|
||||||
|
newCaCert: '', // Key will be "ca.crt"
|
||||||
|
|
||||||
|
// Validation Rules for static fields
|
||||||
|
fvFormRuleSets: [
|
||||||
|
{ path: 'metadata.name', rules: ['nameRequired'] },
|
||||||
|
{ path: 'spec.url', rules: ['urlRequired'] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters({ t: 'i18n/t' }),
|
||||||
|
|
||||||
|
authModeOptions() {
|
||||||
|
return [
|
||||||
|
{ label: this.t('harvester.addons.vmImport.fields.none'), value: 'none' },
|
||||||
|
{ label: this.t('harvester.addons.vmImport.fields.createSecret'), value: 'new' },
|
||||||
|
{ label: this.t('harvester.addons.vmImport.fields.useSecret'), value: 'existing' }
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
secretOptions() {
|
||||||
|
const currentNamespace = this.value.metadata.namespace || 'default';
|
||||||
|
|
||||||
|
return this.allSecrets
|
||||||
|
.filter((s) => s.metadata.namespace === currentNamespace)
|
||||||
|
.map((s) => ({
|
||||||
|
label: s.nameDisplay,
|
||||||
|
value: s.metadata.name
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
// Define custom rules for the FormValidation mixin
|
||||||
|
fvExtraRules() {
|
||||||
|
return {
|
||||||
|
nameRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.fields.name') }) : undefined,
|
||||||
|
urlRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.ova.fields.url') }) : undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
isFormValid() {
|
||||||
|
if (!this.fvFormIsValid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authMode === 'new') {
|
||||||
|
// At least a username/password OR a CA cert to be provided.
|
||||||
|
// If the user selected "Create New", they likely intend to enter something.
|
||||||
|
if (!this.newUsername && !this.newPassword && !this.newCaCert) return false;
|
||||||
|
} else if (this.authMode === 'existing') {
|
||||||
|
if (!this.value.spec.credentials?.name) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
authMode(newMode) {
|
||||||
|
if (newMode === 'existing') {
|
||||||
|
// Bind to value.spec.credentials.name for existing credential
|
||||||
|
// Ensure 'credentials' object exists first when selected
|
||||||
|
if (!this.value.spec.credentials) {
|
||||||
|
this.value.spec.credentials = {
|
||||||
|
name: '',
|
||||||
|
namespace: this.value.metadata.namespace || 'default'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
secretRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.selectSecret') }) : undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveSource(buttonCb) {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.authMode === 'none') {
|
||||||
|
// Clear any credential reference
|
||||||
|
delete this.value.spec.credentials;
|
||||||
|
} else if (this.authMode === 'new') {
|
||||||
|
const secretName = `${ this.value.metadata.name }-creds-${ randomStr(4).toLowerCase() }`;
|
||||||
|
const namespace = this.value.metadata.namespace || 'default';
|
||||||
|
|
||||||
|
const newSecret = await this.$store.dispatch(`${ inStore }/create`, {
|
||||||
|
type: SECRET,
|
||||||
|
metadata: {
|
||||||
|
name: secretName,
|
||||||
|
namespace
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
newSecret['_type'] = 'Opaque';
|
||||||
|
newSecret['data'] = {
|
||||||
|
// Optional fields logic
|
||||||
|
username: this.newUsername ? btoa(this.newUsername) : undefined,
|
||||||
|
password: this.newPassword ? btoa(this.newPassword) : undefined,
|
||||||
|
// vm-import-controller code specifies "ca.crt" with a dot.
|
||||||
|
'ca.crt': this.newCaCert ? btoa(this.newCaCert) : undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
await newSecret.save();
|
||||||
|
|
||||||
|
this.value.spec.credentials = {
|
||||||
|
name: secretName,
|
||||||
|
namespace
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.save(buttonCb);
|
||||||
|
} catch (err) {
|
||||||
|
this.errors = [err];
|
||||||
|
buttonCb(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CruResource
|
||||||
|
:done-route="doneRoute"
|
||||||
|
:resource="value"
|
||||||
|
:mode="mode"
|
||||||
|
:errors="errors"
|
||||||
|
:apply-hooks="applyHooks"
|
||||||
|
:validation-passed="isFormValid"
|
||||||
|
@finish="saveSource"
|
||||||
|
@error="e=>errors=e"
|
||||||
|
>
|
||||||
|
<NameNsDescription
|
||||||
|
:value="value"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="{ name: fvGetAndReportPathRules('metadata.name') }"
|
||||||
|
@update:value="$emit('update:value', $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Tabbed
|
||||||
|
v-bind="$attrs"
|
||||||
|
class="mt-15"
|
||||||
|
:side-tabs="true"
|
||||||
|
>
|
||||||
|
<Tab
|
||||||
|
name="basic"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.basic')"
|
||||||
|
:weight="3"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-12">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.spec.url"
|
||||||
|
:label="t('harvester.addons.vmImport.ova.fields.url')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.ova.placeholders.url')"
|
||||||
|
tooltip="Supports HTTP and HTTPS protocols."
|
||||||
|
:mode="mode"
|
||||||
|
:rules="fvGetAndReportPathRules('spec.url')"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
name="auth"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.auth')"
|
||||||
|
:weight="2"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-12">
|
||||||
|
<RadioGroup
|
||||||
|
v-model:value="authMode"
|
||||||
|
name="authMode"
|
||||||
|
:options="authModeOptions"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="authMode === 'new'">
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newUsername"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.username')"
|
||||||
|
placeholder="(Optional)"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newPassword"
|
||||||
|
type="password"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.password')"
|
||||||
|
placeholder="(Optional)"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-12">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newCaCert"
|
||||||
|
type="multiline"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.caCert')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.placeholders.caCert')"
|
||||||
|
:min-height="100"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="authMode === 'existing'">
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="value.spec.credentials.name"
|
||||||
|
:options="secretOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.selectSecret')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[secretRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
name="advanced"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.advanced')"
|
||||||
|
:weight="1"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<UnitInput
|
||||||
|
v-model:value="value.spec.httpTimeoutSeconds"
|
||||||
|
:label="t('harvester.addons.vmImport.ova.fields.httpTimeout')"
|
||||||
|
placeholder="Default: 600"
|
||||||
|
suffix="Seconds"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
</Tabbed>
|
||||||
|
</CruResource>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,570 @@
|
|||||||
|
<script>
|
||||||
|
import CruResource from '@shell/components/CruResource';
|
||||||
|
import Tabbed from '@shell/components/Tabbed';
|
||||||
|
import Tab from '@shell/components/Tabbed/Tab';
|
||||||
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||||
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
|
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
||||||
|
import { Checkbox } from '@components/Form/Checkbox';
|
||||||
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||||
|
import FormValidation from '@shell/mixins/form-validation';
|
||||||
|
import { STORAGE_CLASS, NETWORK_ATTACHMENT } from '@shell/config/types';
|
||||||
|
import { allHash } from '@shell/utils/promise';
|
||||||
|
import { MANAGEMENT_NETWORK } from '../mixins/harvester-vm';
|
||||||
|
import { VMIMPORT_SOURCE_PROVIDER, VMIMPORT_SOURCE_KINDS } from '../config/types';
|
||||||
|
import { HCI } from '../types';
|
||||||
|
import { isValidDNSLabelName } from '@pkg/utils/regular';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
// Full API types for the fetch dispatch
|
||||||
|
const VMWARE_SOURCE_TYPE = `${ HCI.MIGRATION }.${ VMIMPORT_SOURCE_KINDS.VMWARE.toLowerCase() }`;
|
||||||
|
const OPENSTACK_SOURCE_TYPE = `${ HCI.MIGRATION }.${ VMIMPORT_SOURCE_KINDS.OPENSTACK.toLowerCase() }`;
|
||||||
|
const OVA_SOURCE_TYPE = `${ HCI.MIGRATION }.${ VMIMPORT_SOURCE_KINDS.OVA.toLowerCase() }`;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EditVirtualMachineImport',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
CruResource,
|
||||||
|
Tabbed,
|
||||||
|
Tab,
|
||||||
|
LabeledInput,
|
||||||
|
LabeledSelect,
|
||||||
|
NameNsDescription,
|
||||||
|
Checkbox
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [CreateEditView, FormValidation],
|
||||||
|
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
// Fetch all dependencies in parallel to speed up the page load
|
||||||
|
const hash = {
|
||||||
|
storageClasses: this.$store.dispatch(`${ inStore }/findAll`, { type: STORAGE_CLASS }),
|
||||||
|
networks: this.$store.dispatch(`${ inStore }/findAll`, { type: NETWORK_ATTACHMENT }),
|
||||||
|
vmwareSources: this.$store.dispatch(`${ inStore }/findAll`, { type: VMWARE_SOURCE_TYPE }),
|
||||||
|
openstackSources: this.$store.dispatch(`${ inStore }/findAll`, { type: OPENSTACK_SOURCE_TYPE }),
|
||||||
|
ovaSources: this.$store.dispatch(`${ inStore }/findAll`, { type: OVA_SOURCE_TYPE }).catch(() => []),
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await allHash(hash);
|
||||||
|
|
||||||
|
this.allStorageClasses = res.storageClasses;
|
||||||
|
this.allNetworks = res.networks;
|
||||||
|
this.vmwareSources = res.vmwareSources;
|
||||||
|
this.openstackSources = res.openstackSources;
|
||||||
|
this.ovaSources = res.ovaSources;
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
// Ensure the spec object exists to prevent 'undefined' errors during rendering
|
||||||
|
if (!this.value.spec) this.value.spec = {};
|
||||||
|
if (!this.value.spec.sourceCluster) this.value.spec.sourceCluster = {};
|
||||||
|
if (!this.value.spec.networkMapping) this.value.spec.networkMapping = [];
|
||||||
|
|
||||||
|
// Detect if in Edit mode by checking the existing kind
|
||||||
|
// This allows to pre-select the correct Provider Type tab
|
||||||
|
let initialProvider = '';
|
||||||
|
const existingKind = this.value.spec.sourceCluster.kind;
|
||||||
|
|
||||||
|
if (existingKind === VMIMPORT_SOURCE_KINDS.VMWARE) initialProvider = VMIMPORT_SOURCE_PROVIDER.VMWARE;
|
||||||
|
else if (existingKind === VMIMPORT_SOURCE_KINDS.OPENSTACK) initialProvider = VMIMPORT_SOURCE_PROVIDER.OPENSTACK;
|
||||||
|
else if (existingKind === VMIMPORT_SOURCE_KINDS.OVA) initialProvider = VMIMPORT_SOURCE_PROVIDER.OVA;
|
||||||
|
|
||||||
|
// Construct the unique key (Kind/Namespace/Name) if we are editing an existing resource
|
||||||
|
let initialSourceKey = null;
|
||||||
|
|
||||||
|
if (this.value.spec.sourceCluster.name) {
|
||||||
|
initialSourceKey = `${ existingKind }/${ this.value.spec.sourceCluster.namespace }/${ this.value.spec.sourceCluster.name }`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
allStorageClasses: [],
|
||||||
|
allNetworks: [],
|
||||||
|
vmwareSources: [],
|
||||||
|
openstackSources: [],
|
||||||
|
ovaSources: [],
|
||||||
|
|
||||||
|
// UI State
|
||||||
|
sourceProviderType: initialProvider,
|
||||||
|
selectedSourceKey: initialSourceKey,
|
||||||
|
|
||||||
|
// Static Options
|
||||||
|
providerTypeOptions: [
|
||||||
|
{ label: 'VMware', value: VMIMPORT_SOURCE_PROVIDER.VMWARE },
|
||||||
|
{ label: 'OpenStack', value: VMIMPORT_SOURCE_PROVIDER.OPENSTACK },
|
||||||
|
{ label: 'OVA', value: VMIMPORT_SOURCE_PROVIDER.OVA }
|
||||||
|
],
|
||||||
|
diskBusOptions: [
|
||||||
|
// Allow resetting selection / reset to the default behavior (sending null/empty)
|
||||||
|
{ label: this.t('harvester.addons.vmImport.options.useDefault'), value: '' },
|
||||||
|
{ label: 'VirtIO', value: 'virtio' },
|
||||||
|
{ label: 'SCSI', value: 'scsi' },
|
||||||
|
{ label: 'SATA', value: 'sata' },
|
||||||
|
{ label: 'USB', value: 'usb' },
|
||||||
|
],
|
||||||
|
interfaceModelOptions: [
|
||||||
|
// Allow resetting selection / reset to the default behavior (sending null/empty)
|
||||||
|
{ label: this.t('harvester.addons.vmImport.options.useDefault'), value: '' },
|
||||||
|
{ label: 'VirtIO', value: 'virtio' },
|
||||||
|
{ label: 'e1000', value: 'e1000' },
|
||||||
|
{ label: 'e1000e', value: 'e1000e' },
|
||||||
|
{ label: 'ne2k_pci', value: 'ne2k_pci' },
|
||||||
|
{ label: 'pcnet', value: 'pcnet' },
|
||||||
|
{ label: 'rtl8139', value: 'rtl8139' },
|
||||||
|
],
|
||||||
|
|
||||||
|
fvFormRuleSets: [
|
||||||
|
{ path: 'metadata.name', rules: ['nameRequired'] },
|
||||||
|
{ path: 'spec.virtualMachineName', rules: ['vmNameRequired', 'rfc1123'] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
if (this.registerBeforeHook) {
|
||||||
|
this.registerBeforeHook(this.updateBeforeSave);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters({ t: 'i18n/t' }),
|
||||||
|
|
||||||
|
// Return only the sources that match the selected Provider Type (VMware or OpenStack)
|
||||||
|
sourceOptions() {
|
||||||
|
let list = [];
|
||||||
|
|
||||||
|
if (this.sourceProviderType === VMIMPORT_SOURCE_PROVIDER.VMWARE) {
|
||||||
|
list = this.vmwareSources;
|
||||||
|
} else if (this.sourceProviderType === VMIMPORT_SOURCE_PROVIDER.OPENSTACK) {
|
||||||
|
list = this.openstackSources;
|
||||||
|
} else if (this.sourceProviderType === VMIMPORT_SOURCE_PROVIDER.OVA) {
|
||||||
|
list = this.ovaSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.map((s) => {
|
||||||
|
// Fallback for API version/kind if missing on the object
|
||||||
|
let kind = s.kind;
|
||||||
|
|
||||||
|
if (!kind) {
|
||||||
|
if (this.sourceProviderType === VMIMPORT_SOURCE_PROVIDER.VMWARE) kind = VMIMPORT_SOURCE_KINDS.VMWARE;
|
||||||
|
else if (this.sourceProviderType === VMIMPORT_SOURCE_PROVIDER.OPENSTACK) kind = VMIMPORT_SOURCE_KINDS.OPENSTACK;
|
||||||
|
else if (this.sourceProviderType === VMIMPORT_SOURCE_PROVIDER.OVA) kind = VMIMPORT_SOURCE_KINDS.OVA;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiVersion = s.apiVersion || `${ HCI.MIGRATION }/v1beta1`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: s.metadata.name,
|
||||||
|
value: `${ kind }/${ s.metadata.namespace }/${ s.metadata.name }`,
|
||||||
|
// We attach the raw metadata so we can easily populate the spec later without re-finding the object
|
||||||
|
raw: {
|
||||||
|
kind,
|
||||||
|
apiVersion,
|
||||||
|
name: s.metadata.name,
|
||||||
|
namespace: s.metadata.namespace
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
fvExtraRules() {
|
||||||
|
return {
|
||||||
|
nameRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.fields.name') }) : undefined,
|
||||||
|
vmNameRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.vmName') }) : undefined,
|
||||||
|
rfc1123:
|
||||||
|
(val) => {
|
||||||
|
if (val && !isValidDNSLabelName(val)) {
|
||||||
|
return this.t('harvester.addons.vmImport.errors.rfc1123');
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// Perform various form validations before allowing to submit
|
||||||
|
isFormValid() {
|
||||||
|
// Check VM Name is valid
|
||||||
|
const nameError = this.fvNameRule(this.value.spec.virtualMachineName);
|
||||||
|
|
||||||
|
if (nameError) return false;
|
||||||
|
|
||||||
|
// Check mandatory fields in Basics
|
||||||
|
if (!this.value.spec.virtualMachineName) return false;
|
||||||
|
if (!this.selectedSourceKey) return false;
|
||||||
|
|
||||||
|
// Check Network Mappings
|
||||||
|
// If any row is missing source or destination, the form is invalid.
|
||||||
|
const networks = this.value.spec.networkMapping || [];
|
||||||
|
const hasInvalidRow = networks.some((row) => !row.sourceNetwork || !row.destinationNetwork);
|
||||||
|
|
||||||
|
if (hasInvalidRow) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
isNetworkTabInvalid() {
|
||||||
|
const networks = this.value.spec.networkMapping || [];
|
||||||
|
// Only error if a row exists AND it is missing fields
|
||||||
|
|
||||||
|
return networks.some((row) => !row.sourceNetwork || !row.destinationNetwork);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Filter out internal storage classes
|
||||||
|
// to prevent selecting a class that might cause the import to fail
|
||||||
|
storageClassOptions() {
|
||||||
|
return this.allStorageClasses
|
||||||
|
.filter((sc) => {
|
||||||
|
const isInternal = sc.parameters?.['harvesterhci.io/isInternalStorageClass'] === 'true';
|
||||||
|
|
||||||
|
return !isInternal;
|
||||||
|
})
|
||||||
|
.map((sc) => ({
|
||||||
|
label: sc.nameDisplay,
|
||||||
|
value: sc.id
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
networkOptions() {
|
||||||
|
const mgmtOption = {
|
||||||
|
label: 'Management Network',
|
||||||
|
value: MANAGEMENT_NETWORK
|
||||||
|
};
|
||||||
|
|
||||||
|
const vlanOptions = this.allNetworks.map((n) => ({
|
||||||
|
label: n.nameDisplay || n.metadata.name,
|
||||||
|
value: n.id
|
||||||
|
}));
|
||||||
|
|
||||||
|
return [mgmtOption, ...vlanOptions];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
// Clear the selected cluster if the user switches providers (e.g. VMware -> OpenStack)
|
||||||
|
// Prevents submitting a VMware cluster name while the kind is OpenStack
|
||||||
|
onProviderTypeChange(newType) {
|
||||||
|
this.selectedSourceKey = null;
|
||||||
|
this.value.spec.sourceCluster = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update the sourceCluster object based on the single dropdown selection
|
||||||
|
updateSource(key) {
|
||||||
|
this.selectedSourceKey = key;
|
||||||
|
const selectedOption = this.sourceOptions.find((o) => o.value === key);
|
||||||
|
|
||||||
|
if (selectedOption) {
|
||||||
|
const {
|
||||||
|
kind, apiVersion, name, namespace
|
||||||
|
} = selectedOption.raw;
|
||||||
|
|
||||||
|
this.value.spec.sourceCluster = {
|
||||||
|
kind,
|
||||||
|
apiVersion,
|
||||||
|
name,
|
||||||
|
namespace
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.value.spec.sourceCluster = {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addNetworkMapping() {
|
||||||
|
this.value.spec.networkMapping.push({
|
||||||
|
sourceNetwork: '',
|
||||||
|
destinationNetwork: '',
|
||||||
|
networkInterfaceModel: ''
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeNetworkMapping(index) {
|
||||||
|
if (!this.value?.spec?.networkMapping) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0 && index < this.value.spec.networkMapping.length) {
|
||||||
|
this.value.spec.networkMapping.splice(index, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
requiredRule(val) {
|
||||||
|
if (!val) {
|
||||||
|
return this.t('validation.required', { key: this.t('generic.value') });
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Validates that the input follows Kubernetes Naming Rules (RFC 1123).
|
||||||
|
// If the source VM has uppercase letters or spaces, the user must be warned
|
||||||
|
// that they cannot import it until they rename it on the source. See:
|
||||||
|
// https://docs.harvesterhci.io/v1.6/advanced/addons/vmimport/#source-virtual-machine-name-is-not-rfc1123-compliant
|
||||||
|
fvNameRule(val) {
|
||||||
|
if (!val) return undefined; // 'Required' check handles empty state separately
|
||||||
|
|
||||||
|
// valid RFC 1123
|
||||||
|
if (!isValidDNSLabelName(val)) {
|
||||||
|
return this.t('harvester.addons.vmImport.errors.rfc1123');
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateBeforeSave() {
|
||||||
|
// If networkMapping exists, filter out the "Management Network" rows
|
||||||
|
// Let the vm-import-controller set the default network mapping
|
||||||
|
if (this.value.spec.networkMapping) {
|
||||||
|
this.value.spec.networkMapping = this.value.spec.networkMapping.filter((row) => {
|
||||||
|
return row.destinationNetwork !== MANAGEMENT_NETWORK;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Only handles complex logic that doesn't fit into simple field rules
|
||||||
|
async saveOverride(buttonCb) {
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
this.errors = [];
|
||||||
|
|
||||||
|
// Validate Provider Type
|
||||||
|
if (!this.sourceProviderType) {
|
||||||
|
errors.push(this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.sourceProvider') }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate Network Tab
|
||||||
|
if (this.isNetworkTabInvalid) {
|
||||||
|
errors.push(this.t('harvester.addons.vmImport.errors.networkMappingRequired'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return immediately in case of an error, avoid that `this.save()` runs, preventing `updateBeforeSave` from resetting data.
|
||||||
|
if (errors.length > 0) {
|
||||||
|
this.errors = errors;
|
||||||
|
buttonCb(false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only proceed if valid
|
||||||
|
this.save(buttonCb);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CruResource
|
||||||
|
:done-route="doneRoute"
|
||||||
|
:resource="value"
|
||||||
|
:mode="mode"
|
||||||
|
:errors="errors"
|
||||||
|
:apply-hooks="applyHooks"
|
||||||
|
:validation-passed="fvFormIsValid"
|
||||||
|
@finish="saveOverride"
|
||||||
|
@error="e=>errors=e"
|
||||||
|
>
|
||||||
|
<NameNsDescription
|
||||||
|
:value="value"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="{ name: fvGetAndReportPathRules('metadata.name') }"
|
||||||
|
@update:value="$emit('update:value', $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Tabbed
|
||||||
|
v-bind="$attrs"
|
||||||
|
class="mt-15"
|
||||||
|
:side-tabs="true"
|
||||||
|
>
|
||||||
|
<Tab
|
||||||
|
name="basic"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.basic')"
|
||||||
|
:weight="3"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="sourceProviderType"
|
||||||
|
:options="providerTypeOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.sourceProvider')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[requiredRule]"
|
||||||
|
required
|
||||||
|
@update:value="onProviderTypeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
:value="selectedSourceKey"
|
||||||
|
:options="sourceOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.sourceCluster')"
|
||||||
|
:placeholder="sourceProviderType ? t('harvester.addons.vmImport.placeholders.selectCluster') : t('harvester.addons.vmImport.placeholders.selectProviderFirst')"
|
||||||
|
:disabled="!sourceProviderType"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="fvGetAndReportPathRules('selectedSourceKey')"
|
||||||
|
required
|
||||||
|
@update:value="updateSource"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.spec.virtualMachineName"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.vmName')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.placeholders.matchSource')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="fvGetAndReportPathRules('spec.virtualMachineName')"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="value.spec.storageClass"
|
||||||
|
:options="storageClassOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.targetStorageClass')"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
name="networking"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.networking')"
|
||||||
|
:weight="2"
|
||||||
|
:error="isNetworkTabInvalid"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(row, i) in value.spec.networkMapping"
|
||||||
|
:key="i"
|
||||||
|
class="network-row box mb-10"
|
||||||
|
>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col span-4">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="row.sourceNetwork"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.sourceNetwork')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[requiredRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-4">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="row.destinationNetwork"
|
||||||
|
:options="networkOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.destNetwork')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[requiredRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-3">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="row.networkInterfaceModel"
|
||||||
|
:options="interfaceModelOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.interfaceModel')"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-1 remove-btn-container">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn role-link"
|
||||||
|
@click="removeNetworkMapping(i)"
|
||||||
|
>
|
||||||
|
{{ t('harvester.addons.vmImport.actions.remove') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn role-secondary"
|
||||||
|
@click="addNetworkMapping"
|
||||||
|
>
|
||||||
|
{{ t('harvester.addons.vmImport.actions.addNetwork') }}
|
||||||
|
</button>
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
name="advanced"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.advanced')"
|
||||||
|
:weight="1"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.spec.folder"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.folder')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.placeholders.folderExample')"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="value.spec.defaultDiskBusType"
|
||||||
|
:options="diskBusOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.diskBus')"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="value.spec.defaultNetworkInterfaceModel"
|
||||||
|
:options="interfaceModelOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.defaultInterface')"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col span-12">
|
||||||
|
<Checkbox
|
||||||
|
v-model:value="value.spec.skipPreflightChecks"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.skipPreflight')"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
v-model:value="value.spec.forcePowerOff"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.forcePowerOff')"
|
||||||
|
:mode="mode"
|
||||||
|
class="mt-10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
</Tabbed>
|
||||||
|
</CruResource>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.network-row {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
background: var(--body-bg);
|
||||||
|
}
|
||||||
|
.remove-btn-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
302
pkg/harvester/edit/migration.harvesterhci.io.vmwaresource.vue
Normal file
302
pkg/harvester/edit/migration.harvesterhci.io.vmwaresource.vue
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
<script>
|
||||||
|
import CruResource from '@shell/components/CruResource';
|
||||||
|
import Tabbed from '@shell/components/Tabbed';
|
||||||
|
import Tab from '@shell/components/Tabbed/Tab';
|
||||||
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||||
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
|
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
||||||
|
import { RadioGroup } from '@components/Form/Radio';
|
||||||
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||||
|
import FormValidation from '@shell/mixins/form-validation';
|
||||||
|
import { SECRET } from '@shell/config/types';
|
||||||
|
import { randomStr } from '@shell/utils/string';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EditVmwareSource',
|
||||||
|
|
||||||
|
// Declare the event, fixes a console warning
|
||||||
|
emits: ['update:value'],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
CruResource,
|
||||||
|
Tabbed,
|
||||||
|
Tab,
|
||||||
|
LabeledInput,
|
||||||
|
LabeledSelect,
|
||||||
|
NameNsDescription,
|
||||||
|
RadioGroup,
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [CreateEditView, FormValidation],
|
||||||
|
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
this.allSecrets = await this.$store.dispatch(`${ inStore }/findAll`, { type: SECRET });
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
if (!this.value.spec) this.value.spec = {};
|
||||||
|
if (!this.value.spec.credentials) this.value.spec.credentials = {};
|
||||||
|
|
||||||
|
const initialMode = this.value.spec.credentials.name ? 'existing' : 'new';
|
||||||
|
|
||||||
|
return {
|
||||||
|
allSecrets: [],
|
||||||
|
authMode: initialMode,
|
||||||
|
newUsername: '',
|
||||||
|
newPassword: '',
|
||||||
|
newCaCert: '',
|
||||||
|
|
||||||
|
fvFormRuleSets: [
|
||||||
|
{ path: 'metadata.name', rules: ['nameRequired'] },
|
||||||
|
{ path: 'spec.endpoint', rules: ['endpointRequired'] },
|
||||||
|
{ path: 'spec.dc', rules: ['dcRequired'] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters({ t: 'i18n/t' }),
|
||||||
|
|
||||||
|
authModeOptions() {
|
||||||
|
return [
|
||||||
|
{ label: this.t('harvester.addons.vmImport.fields.createSecret'), value: 'new' },
|
||||||
|
{ label: this.t('harvester.addons.vmImport.fields.useSecret'), value: 'existing' }
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
secretOptions() {
|
||||||
|
const currentNamespace = this.value.metadata.namespace || 'default';
|
||||||
|
|
||||||
|
return this.allSecrets
|
||||||
|
.filter((s) => s.metadata.namespace === currentNamespace)
|
||||||
|
.map((s) => ({
|
||||||
|
label: s.nameDisplay,
|
||||||
|
value: s.metadata.name
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
// Define custom rules for the FormValidation mixin
|
||||||
|
fvExtraRules() {
|
||||||
|
return {
|
||||||
|
nameRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.fields.name') }) : undefined,
|
||||||
|
endpointRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.vmware.fields.endpoint') }) : undefined,
|
||||||
|
dcRequired: (val) => !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.vmware.fields.datacenter') }) : undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
isFormValid() {
|
||||||
|
if (!this.fvFormIsValid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authMode === 'new') {
|
||||||
|
if (!this.newUsername || !this.newPassword) return false;
|
||||||
|
} else {
|
||||||
|
if (!this.value.spec.credentials.name) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
usernameRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.username') }) : undefined;
|
||||||
|
},
|
||||||
|
passwordRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.password') }) : undefined;
|
||||||
|
},
|
||||||
|
secretRule(val) {
|
||||||
|
return !val ? this.t('validation.required', { key: this.t('harvester.addons.vmImport.fields.selectSecret') }) : undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveSource(buttonCb) {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.authMode === 'new') {
|
||||||
|
const secretName = `${ this.value.metadata.name }-creds-${ randomStr(4).toLowerCase() }`;
|
||||||
|
const namespace = this.value.metadata.namespace || 'default';
|
||||||
|
|
||||||
|
// Create the model with the correct Schema ID (SECRET)
|
||||||
|
const newSecret = await this.$store.dispatch(`${ inStore }/create`, {
|
||||||
|
type: SECRET,
|
||||||
|
metadata: {
|
||||||
|
name: secretName,
|
||||||
|
namespace
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use '_type' to set the Kubernetes 'type' field.
|
||||||
|
newSecret['_type'] = 'Opaque';
|
||||||
|
|
||||||
|
// base64 encode the data
|
||||||
|
newSecret['data'] = {
|
||||||
|
username: btoa(this.newUsername),
|
||||||
|
password: btoa(this.newPassword),
|
||||||
|
// Only include CA cert if the user provided one
|
||||||
|
caCert: this.newCaCert ? btoa(this.newCaCert) : undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
await newSecret.save();
|
||||||
|
|
||||||
|
// Link the new secret to the Source
|
||||||
|
this.value.spec.credentials = {
|
||||||
|
name: secretName,
|
||||||
|
namespace
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.save(buttonCb);
|
||||||
|
} catch (err) {
|
||||||
|
this.errors = [err];
|
||||||
|
buttonCb(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CruResource
|
||||||
|
:done-route="doneRoute"
|
||||||
|
:resource="value"
|
||||||
|
:mode="mode"
|
||||||
|
:errors="errors"
|
||||||
|
:apply-hooks="applyHooks"
|
||||||
|
:validation-passed="isFormValid"
|
||||||
|
@finish="saveSource"
|
||||||
|
@error="e=>errors=e"
|
||||||
|
>
|
||||||
|
<NameNsDescription
|
||||||
|
:value="value"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="{ name: fvGetAndReportPathRules('metadata.name') }"
|
||||||
|
@update:value="$emit('update:value', $event)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Tabbed
|
||||||
|
v-bind="$attrs"
|
||||||
|
class="mt-15"
|
||||||
|
:side-tabs="true"
|
||||||
|
>
|
||||||
|
<Tab
|
||||||
|
name="basic"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.basic')"
|
||||||
|
:weight="2"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.spec.endpoint"
|
||||||
|
:label="t('harvester.addons.vmImport.vmware.fields.endpoint')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.vmware.placeholders.endpoint')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="fvGetAndReportPathRules('spec.endpoint')"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="value.spec.dc"
|
||||||
|
:label="t('harvester.addons.vmImport.vmware.fields.datacenter')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.vmware.placeholders.datacenter')"
|
||||||
|
:tooltip="t('harvester.addons.vmImport.vmware.tooltips.datacenter')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="fvGetAndReportPathRules('spec.dc')"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
name="auth"
|
||||||
|
:label="t('harvester.addons.vmImport.titles.auth')"
|
||||||
|
:weight="1"
|
||||||
|
>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-12">
|
||||||
|
<RadioGroup
|
||||||
|
v-model:value="authMode"
|
||||||
|
name="authMode"
|
||||||
|
:options="authModeOptions"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="authMode === 'new'">
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newUsername"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.username')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[usernameRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newPassword"
|
||||||
|
type="password"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.password')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[passwordRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-12">
|
||||||
|
<LabeledInput
|
||||||
|
v-model:value="newCaCert"
|
||||||
|
type="multiline"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.caCert')"
|
||||||
|
:placeholder="t('harvester.addons.vmImport.placeholders.caCert')"
|
||||||
|
:min-height="100"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-muted">
|
||||||
|
Note: A new Kubernetes Secret will be created to store these credentials.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="authMode === 'existing'">
|
||||||
|
<div class="row mb-20">
|
||||||
|
<div class="col span-6">
|
||||||
|
<LabeledSelect
|
||||||
|
v-model:value="value.spec.credentials.name"
|
||||||
|
:options="secretOptions"
|
||||||
|
:label="t('harvester.addons.vmImport.fields.selectSecret')"
|
||||||
|
:mode="mode"
|
||||||
|
:rules="[secretRule]"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tab>
|
||||||
|
</Tabbed>
|
||||||
|
</CruResource>
|
||||||
|
</template>
|
||||||
@ -20,6 +20,7 @@ nav:
|
|||||||
Monitoring: Monitoring
|
Monitoring: Monitoring
|
||||||
Logging: Logging
|
Logging: Logging
|
||||||
'Monitoring and Logging': Monitoring and Logging
|
'Monitoring and Logging': Monitoring and Logging
|
||||||
|
vmimport: Virtual Machine Imports
|
||||||
|
|
||||||
resourceTable:
|
resourceTable:
|
||||||
groupBy:
|
groupBy:
|
||||||
@ -189,12 +190,16 @@ harvester:
|
|||||||
title: Restart Virtual Machine
|
title: Restart Virtual Machine
|
||||||
tip: Restart the virtual machine for configuration changes to take effect.
|
tip: Restart the virtual machine for configuration changes to take effect.
|
||||||
cancel: Save
|
cancel: Save
|
||||||
|
|
||||||
notification:
|
notification:
|
||||||
title:
|
title:
|
||||||
succeed: Succeed
|
succeed: Succeed
|
||||||
info: Info
|
info: Info
|
||||||
warning: Warning
|
warning: Warning
|
||||||
error: Error
|
error: Error
|
||||||
|
restartRequired:
|
||||||
|
title: '{count} {count, plural, =1 {Virtual Machine is} other {Virtual Machines are}} Pending Restart'
|
||||||
|
message: 'Please restart { vmNames } to apply updated configurations'
|
||||||
action:
|
action:
|
||||||
createVM: Create Virtual Machine
|
createVM: Create Virtual Machine
|
||||||
start: Start
|
start: Start
|
||||||
@ -295,6 +300,17 @@ harvester:
|
|||||||
totalSnapshotQuota: Total Snapshot Quota
|
totalSnapshotQuota: Total Snapshot Quota
|
||||||
storageClass: Storage Class
|
storageClass: Storage Class
|
||||||
restore: Restore
|
restore: Restore
|
||||||
|
vmImportSourceVm: Source VM
|
||||||
|
vmImportSourceCluster: Source Cluster
|
||||||
|
vmImportStatus: Import Status
|
||||||
|
vmImportSourceVDatacenter: Datacenter
|
||||||
|
vmImportSourceVEndpoint: Endpoint
|
||||||
|
vmImportSourceVClusterStatus: Cluster Status
|
||||||
|
vmImportSourceORegion: Region
|
||||||
|
vmImportSourceOEndpoint: Endpoint
|
||||||
|
vmImportSourceOClusterStatus: Cluster Status
|
||||||
|
vmImportSourceOVAUrl: URL
|
||||||
|
vmImportSourceOVAStatus: Status
|
||||||
tab:
|
tab:
|
||||||
volume: Volumes
|
volume: Volumes
|
||||||
network: Networks
|
network: Networks
|
||||||
@ -357,6 +373,9 @@ harvester:
|
|||||||
claimError: Error enabling passthrough on {name}
|
claimError: Error enabling passthrough on {name}
|
||||||
unclaimError: Error disabling passthrough on {name}
|
unclaimError: Error disabling passthrough on {name}
|
||||||
cantUnclaim: You cannot disable passthrough on a device claimed by another user.
|
cantUnclaim: You cannot disable passthrough on a device claimed by another user.
|
||||||
|
detachWarning:
|
||||||
|
title: Cannot Disable Passthrough
|
||||||
|
message: Please detach the device from the VM and save it first before disabling passthrough.
|
||||||
enableGroup: Enable Group
|
enableGroup: Enable Group
|
||||||
disableGroup: Disable Group
|
disableGroup: Disable Group
|
||||||
labelRequired: "This rule should not be manually altered: it ensures that the PCI devices selected for this virtual machine are available on the virtual machine's host."
|
labelRequired: "This rule should not be manually altered: it ensures that the PCI devices selected for this virtual machine are available on the virtual machine's host."
|
||||||
@ -922,6 +941,8 @@ harvester:
|
|||||||
checksumTip: Validate the image using the SHA512 checksum, if specified.
|
checksumTip: Validate the image using the SHA512 checksum, if specified.
|
||||||
tooltip:
|
tooltip:
|
||||||
imported: Created automatically by the vm-import-controller
|
imported: Created automatically by the vm-import-controller
|
||||||
|
errors:
|
||||||
|
unsupportedBackend: 'Unsupported backend type: {backend}'
|
||||||
|
|
||||||
vmTemplate:
|
vmTemplate:
|
||||||
label: Templates
|
label: Templates
|
||||||
@ -1278,7 +1299,10 @@ harvester:
|
|||||||
deleteImage: Please select an image to delete.
|
deleteImage: Please select an image to delete.
|
||||||
deleteSuccess: "{name} deleted successfully."
|
deleteSuccess: "{name} deleted successfully."
|
||||||
imagePreloadStrategy: Image Preload Strategy
|
imagePreloadStrategy: Image Preload Strategy
|
||||||
|
nodeUpgradeOption: Node Upgrade Option
|
||||||
restoreVM: Restore VM
|
restoreVM: Restore VM
|
||||||
|
strategy: Strategy
|
||||||
|
pauseNodes: Pause Nodes
|
||||||
strategyType: Strategy Type
|
strategyType: Strategy Type
|
||||||
concurrency: Concurrency
|
concurrency: Concurrency
|
||||||
harvesterMonitoring:
|
harvesterMonitoring:
|
||||||
@ -1564,10 +1588,84 @@ harvester:
|
|||||||
'harvester-system/harvester-seeder': harvester-seeder is an add-on that uses IPMI and Redfish to discover hardware information and perform out-of-band operations.
|
'harvester-system/harvester-seeder': harvester-seeder is an add-on that uses IPMI and Redfish to discover hardware information and perform out-of-band operations.
|
||||||
'harvester-csi-driver-lvm': harvester-csi-driver-lvm is an add-on allowing users to create PVC through the LVM with local devices.
|
'harvester-csi-driver-lvm': harvester-csi-driver-lvm is an add-on allowing users to create PVC through the LVM with local devices.
|
||||||
'descheduler': 'The virtual machine auto balance optimizes workload scheduling by evicting pods that are not optimally placed according to administrator-defined policies.'
|
'descheduler': 'The virtual machine auto balance optimizes workload scheduling by evicting pods that are not optimally placed according to administrator-defined policies.'
|
||||||
|
|
||||||
vmImport:
|
vmImport:
|
||||||
titles:
|
titles:
|
||||||
basic: Basic
|
basic: Basic
|
||||||
|
auth: Authentication
|
||||||
pvc: Volume
|
pvc: Volume
|
||||||
|
networking: Network Mapping
|
||||||
|
advanced: Advanced
|
||||||
|
labels:
|
||||||
|
vmimport: Virtual Machine Import
|
||||||
|
vmimportSourceVMWare: Source VMWare
|
||||||
|
vmimportSourceOpenStack: Source OpenStack
|
||||||
|
vmimportSourceOVA: Source OVA
|
||||||
|
fields:
|
||||||
|
sourceProvider: Source Provider Type
|
||||||
|
sourceCluster: Source Cluster
|
||||||
|
vmName: VM Name
|
||||||
|
targetStorageClass: Target Storage Class
|
||||||
|
sourceNetwork: Source Network Name
|
||||||
|
destNetwork: Destination Network
|
||||||
|
interfaceModel: Interface Model
|
||||||
|
folder: Folder
|
||||||
|
diskBus: Default Disk Bus
|
||||||
|
defaultInterface: Default Network Interface
|
||||||
|
skipPreflight: Skip Preflight Checks
|
||||||
|
forcePowerOff: Force Power Off Source VM
|
||||||
|
username: Username
|
||||||
|
password: Password
|
||||||
|
caCert: CA Certificate (PEM)
|
||||||
|
selectSecret: Select Secret
|
||||||
|
createSecret: Create New Credentials
|
||||||
|
useSecret: Use Existing Secret
|
||||||
|
none: None (Public URL)
|
||||||
|
placeholders:
|
||||||
|
selectCluster: Select a cluster...
|
||||||
|
selectProviderFirst: Select a provider type first
|
||||||
|
matchSource: Must match the name in the source cluster
|
||||||
|
folderExample: e.g. /Datacenters/DC1/vm
|
||||||
|
caCert: "-----BEGIN CERTIFICATE----- ..."
|
||||||
|
options:
|
||||||
|
useDefault: Use Default
|
||||||
|
actions:
|
||||||
|
addNetwork: Add Network Mapping
|
||||||
|
remove: Remove
|
||||||
|
errors:
|
||||||
|
rfc1123: 'Invalid format. Name must be lowercase, alphanumeric, and cannot contain spaces (e.g. "my-vm-1"). If your Source VM name does not match this, you must rename it on the Source cluster first.'
|
||||||
|
networkMappingRequired: Every Network Mapping row must have a Source and Destination selected.
|
||||||
|
openstack:
|
||||||
|
fields:
|
||||||
|
endpoint: Identity Service Endpoint
|
||||||
|
region: Region
|
||||||
|
projectName: Project Name
|
||||||
|
domainName: Domain Name
|
||||||
|
retryCount: Upload Image Retry Count
|
||||||
|
retryDelay: Upload Image Retry Delay
|
||||||
|
placeholders:
|
||||||
|
endpoint: "e.g. https://devstack/identity"
|
||||||
|
region: e.g. RegionOne
|
||||||
|
projectName: e.g. admin
|
||||||
|
domainName: e.g. default
|
||||||
|
retryCount: "Default: 30"
|
||||||
|
retryDelay: "Default: 10"
|
||||||
|
vmware:
|
||||||
|
fields:
|
||||||
|
endpoint: vCenter Endpoint
|
||||||
|
datacenter: Datacenter
|
||||||
|
placeholders:
|
||||||
|
endpoint: "e.g. https://vscim/sdk"
|
||||||
|
datacenter: e.g. DC0
|
||||||
|
tooltips:
|
||||||
|
datacenter: The exact name of the Datacenter object in vCenter
|
||||||
|
ova:
|
||||||
|
fields:
|
||||||
|
url: OVA URL
|
||||||
|
httpTimeout: HTTP Timeout
|
||||||
|
placeholders:
|
||||||
|
url: "e.g. https://download.example.com/images/my-vm.ova"
|
||||||
|
|
||||||
rancherVcluster:
|
rancherVcluster:
|
||||||
accessRancher: Access the Rancher Dashboard
|
accessRancher: Access the Rancher Dashboard
|
||||||
hostname: Hostname
|
hostname: Hostname
|
||||||
@ -1733,6 +1831,9 @@ harvester:
|
|||||||
vgpu:
|
vgpu:
|
||||||
label: vGPU Devices
|
label: vGPU Devices
|
||||||
noPermission: Please contact system administrator to add Harvester add-ons first.
|
noPermission: Please contact system administrator to add Harvester add-ons first.
|
||||||
|
detachWarning:
|
||||||
|
title: Cannot Disable vGPU
|
||||||
|
message: Please detach the device from the VM and save it first before disabling this vGPU device.
|
||||||
goSetting:
|
goSetting:
|
||||||
prefix: The nvidia-driver-toolkit add-on is not enabled, click
|
prefix: The nvidia-driver-toolkit add-on is not enabled, click
|
||||||
middle: here
|
middle: here
|
||||||
@ -1767,6 +1868,9 @@ harvester:
|
|||||||
claimError: Error enabling passthrough on {name}
|
claimError: Error enabling passthrough on {name}
|
||||||
unclaimError: Error disabling passthrough on {name}
|
unclaimError: Error disabling passthrough on {name}
|
||||||
cantUnclaim: You cannot disable passthrough on a device claimed by another user.
|
cantUnclaim: You cannot disable passthrough on a device claimed by another user.
|
||||||
|
detachWarning:
|
||||||
|
title: Cannot Disable Passthrough
|
||||||
|
message: Please detach the device from the VM and save it first before disabling passthrough.
|
||||||
enablePassthroughWarning: 'Please re-enable the USB device if the device path changes in the following situations:<br/> 1) Re-plugging the USB device.<br/> 2) Rebooting the node.<br/><br/>An incorrect device path may cause passthrough to fail.'
|
enablePassthroughWarning: 'Please re-enable the USB device if the device path changes in the following situations:<br/> 1) Re-plugging the USB device.<br/> 2) Rebooting the node.<br/><br/>An incorrect device path may cause passthrough to fail.'
|
||||||
|
|
||||||
harvesterVlanConfigMigrateDialog:
|
harvesterVlanConfigMigrateDialog:
|
||||||
|
|||||||
@ -64,6 +64,10 @@ export default {
|
|||||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
const rows = this.$store.getters[`${ inStore }/all`](HCI.PCI_DEVICE);
|
const rows = this.$store.getters[`${ inStore }/all`](HCI.PCI_DEVICE);
|
||||||
|
|
||||||
|
rows.forEach((row) => {
|
||||||
|
row.allowDisable = true;
|
||||||
|
});
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -54,7 +54,13 @@ export default {
|
|||||||
devices() {
|
devices() {
|
||||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
return this.$store.getters[`${ inStore }/all`](HCI.USB_DEVICE) || [];
|
const data = this.$store.getters[`${ inStore }/all`](HCI.USB_DEVICE) || [];
|
||||||
|
|
||||||
|
data.forEach((row) => {
|
||||||
|
row.allowDisable = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,10 @@ export default {
|
|||||||
const vGpuDevices = this.$store.getters[`${ inStore }/all`](HCI.VGPU_DEVICE) || [];
|
const vGpuDevices = this.$store.getters[`${ inStore }/all`](HCI.VGPU_DEVICE) || [];
|
||||||
const srioVGpuDevices = this.$store.getters[`${ inStore }/all`](HCI.SR_IOVGPU_DEVICE) || [];
|
const srioVGpuDevices = this.$store.getters[`${ inStore }/all`](HCI.SR_IOVGPU_DEVICE) || [];
|
||||||
|
|
||||||
|
vGpuDevices.forEach((row) => {
|
||||||
|
row.allowDisable = true;
|
||||||
|
});
|
||||||
|
|
||||||
if (this.hasSRIOVGPUSchema) {
|
if (this.hasSRIOVGPUSchema) {
|
||||||
return vGpuDevices.filter((device) => !!srioVGpuDevices.find((s) => s.isEnabled && s.spec?.nodeName === device.spec?.nodeName));
|
return vGpuDevices.filter((device) => !!srioVGpuDevices.find((s) => s.isEnabled && s.spec?.nodeName === device.spec?.nodeName));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
<script>
|
||||||
|
import ResourceTable from '@shell/components/ResourceTable';
|
||||||
|
import Loading from '@shell/components/Loading';
|
||||||
|
import { SCHEMA } from '@shell/config/types';
|
||||||
|
import { HCI } from '../types';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
id: HCI.VMIMPORT_SOURCE_O,
|
||||||
|
type: SCHEMA,
|
||||||
|
attributes: {
|
||||||
|
kind: HCI.VMIMPORT_SOURCE_O,
|
||||||
|
namespaced: true
|
||||||
|
},
|
||||||
|
metadata: { name: HCI.VMIMPORT_SOURCE_O },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HarvesterVMImportSourceO',
|
||||||
|
components: { ResourceTable, Loading },
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
this.rows = await this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VMIMPORT_SOURCE_O });
|
||||||
|
|
||||||
|
const configSchema = this.$store.getters[`${ inStore }/schemaFor`](HCI.VMIMPORT_SOURCE_O);
|
||||||
|
|
||||||
|
if (!configSchema?.collectionMethods.find((x) => x.toLowerCase() === 'post')) {
|
||||||
|
this.$store.dispatch('type-map/configureType', { match: HCI.VMIMPORT_SOURCE_O, isCreatable: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return { rows: [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
schema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
typeDisplay() {
|
||||||
|
return this.$store.getters['type-map/labelFor'](schema, 99);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Loading v-if="$fetchState.pending" />
|
||||||
|
<ResourceTable
|
||||||
|
v-else
|
||||||
|
v-bind="$attrs"
|
||||||
|
:groupable="true"
|
||||||
|
:schema="schema"
|
||||||
|
:rows="rows"
|
||||||
|
key-field="_key"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
<script>
|
||||||
|
import ResourceTable from '@shell/components/ResourceTable';
|
||||||
|
import Loading from '@shell/components/Loading';
|
||||||
|
import { SCHEMA } from '@shell/config/types';
|
||||||
|
import { HCI } from '../types';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
id: HCI.VMIMPORT,
|
||||||
|
type: SCHEMA,
|
||||||
|
attributes: {
|
||||||
|
kind: HCI.VMIMPORT,
|
||||||
|
namespaced: true
|
||||||
|
},
|
||||||
|
metadata: { name: HCI.VMIMPORT },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HarvesterVMImportVirtualMachine',
|
||||||
|
components: { ResourceTable, Loading },
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
this.rows = await this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VMIMPORT });
|
||||||
|
|
||||||
|
const configSchema = this.$store.getters[`${ inStore }/schemaFor`](HCI.VMIMPORT);
|
||||||
|
|
||||||
|
if (!configSchema?.collectionMethods.find((x) => x.toLowerCase() === 'post')) {
|
||||||
|
this.$store.dispatch('type-map/configureType', { match: HCI.VMIMPORT, isCreatable: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return { rows: [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
schema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
typeDisplay() {
|
||||||
|
return this.$store.getters['type-map/labelFor'](schema, 99);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Loading v-if="$fetchState.pending" />
|
||||||
|
<ResourceTable
|
||||||
|
v-else
|
||||||
|
v-bind="$attrs"
|
||||||
|
:groupable="true"
|
||||||
|
:schema="schema"
|
||||||
|
:rows="rows"
|
||||||
|
key-field="_key"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
<script>
|
||||||
|
import ResourceTable from '@shell/components/ResourceTable';
|
||||||
|
import Loading from '@shell/components/Loading';
|
||||||
|
import { SCHEMA } from '@shell/config/types';
|
||||||
|
import { HCI } from '../types';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
id: HCI.VMIMPORT_SOURCE_V,
|
||||||
|
type: SCHEMA,
|
||||||
|
attributes: {
|
||||||
|
kind: HCI.VMIMPORT_SOURCE_V,
|
||||||
|
namespaced: true
|
||||||
|
},
|
||||||
|
metadata: { name: HCI.VMIMPORT_SOURCE_V },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HarvesterVMImportSourceV',
|
||||||
|
components: { ResourceTable, Loading },
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
|
||||||
|
this.rows = await this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VMIMPORT_SOURCE_V });
|
||||||
|
|
||||||
|
const configSchema = this.$store.getters[`${ inStore }/schemaFor`](HCI.VMIMPORT_SOURCE_V);
|
||||||
|
|
||||||
|
if (!configSchema?.collectionMethods.find((x) => x.toLowerCase() === 'post')) {
|
||||||
|
this.$store.dispatch('type-map/configureType', { match: HCI.VMIMPORT_SOURCE_V, isCreatable: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return { rows: [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
schema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
typeDisplay() {
|
||||||
|
return this.$store.getters['type-map/labelFor'](schema, 99);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Loading v-if="$fetchState.pending" />
|
||||||
|
<ResourceTable
|
||||||
|
v-else
|
||||||
|
v-bind="$attrs"
|
||||||
|
:groupable="true"
|
||||||
|
:schema="schema"
|
||||||
|
:rows="rows"
|
||||||
|
key-field="_key"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@ -110,11 +110,12 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasNode: false,
|
hasNode: false,
|
||||||
allVMs: [],
|
allVMs: [],
|
||||||
allVMIs: [],
|
allVMIs: [],
|
||||||
allNodeNetworks: [],
|
allNodeNetworks: [],
|
||||||
allClusterNetworks: [],
|
allClusterNetworks: [],
|
||||||
|
restartNotificationDisplayed: false,
|
||||||
HCI
|
HCI
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -174,6 +175,48 @@ export default {
|
|||||||
this['allVMIs'] = vmis;
|
this['allVMIs'] = vmis;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
beforeUnmount() {
|
||||||
|
// clear restart message before component unmount
|
||||||
|
this.$store.dispatch('growl/clear');
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
allVMs: {
|
||||||
|
handler(neu) {
|
||||||
|
const vmNames = [];
|
||||||
|
|
||||||
|
neu.forEach((vm) => {
|
||||||
|
if (vm.isRestartRequired) {
|
||||||
|
vmNames.push(vm.metadata.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const count = vmNames.length;
|
||||||
|
|
||||||
|
if ( count === 0 && this.restartNotificationDisplayed) {
|
||||||
|
this.restartNotificationDisplayed = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
// clear old notification before showing new one
|
||||||
|
if (this.restartNotificationDisplayed) {
|
||||||
|
this.$store.dispatch('growl/clear');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0 && vmNames.length > 0) {
|
||||||
|
this.$store.dispatch('growl/warning', {
|
||||||
|
title: this.t('harvester.notification.restartRequired.title', { count }),
|
||||||
|
message: this.t('harvester.notification.restartRequired.message', { vmNames: vmNames.join(', ') }),
|
||||||
|
timeout: 10000,
|
||||||
|
}, { root: true });
|
||||||
|
this.restartNotificationDisplayed = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
lockIconTooltipMessage(row) {
|
lockIconTooltipMessage(row) {
|
||||||
const message = '';
|
const message = '';
|
||||||
@ -243,6 +286,12 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.growl-container {
|
||||||
|
z-index: 56 !important; // set to be lower than the vm action menu (z-index: 57)
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.state {
|
.state {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -690,7 +690,6 @@ export default {
|
|||||||
set(this.spec.template.spec, 'domain.memory.maxGuest', this.maxMemory);
|
set(this.spec.template.spec, 'domain.memory.maxGuest', this.maxMemory);
|
||||||
set(this.spec.template.spec, 'domain.resources.limits.memory', this.maxMemory);
|
set(this.spec.template.spec, 'domain.resources.limits.memory', this.maxMemory);
|
||||||
} else {
|
} else {
|
||||||
this.spec.template.spec.domain.cpu.maxSockets = 1;
|
|
||||||
this.spec.template.spec.domain.cpu.sockets = 1;
|
this.spec.template.spec.domain.cpu.sockets = 1;
|
||||||
this.spec.template.spec.domain.cpu.cores = this.cpu;
|
this.spec.template.spec.domain.cpu.cores = this.cpu;
|
||||||
this.spec.template.spec.domain.resources.limits.cpu = this.cpu?.toString();
|
this.spec.template.spec.domain.resources.limits.cpu = this.cpu?.toString();
|
||||||
|
|||||||
@ -144,6 +144,12 @@ export default class PCIDevice extends SteveModel {
|
|||||||
// 'disable' passthrough deletes claim
|
// 'disable' passthrough deletes claim
|
||||||
// backend should return error if device is in use
|
// backend should return error if device is in use
|
||||||
async disablePassthrough() {
|
async disablePassthrough() {
|
||||||
|
if (!this.allowDisable) {
|
||||||
|
this.showDetachWarning();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!this.claimedByMe) {
|
if (!this.claimedByMe) {
|
||||||
throw new Error(this.$rootGetters['i18n/t']('harvester.pci.cantUnclaim', { name: escapeHtml(this.metadata.name) }));
|
throw new Error(this.$rootGetters['i18n/t']('harvester.pci.cantUnclaim', { name: escapeHtml(this.metadata.name) }));
|
||||||
@ -169,4 +175,20 @@ export default class PCIDevice extends SteveModel {
|
|||||||
get groupByDevice() {
|
get groupByDevice() {
|
||||||
return this.status?.description;
|
return this.status?.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showDetachWarning() {
|
||||||
|
this.$dispatch('growl/warning', {
|
||||||
|
title: this.$rootGetters['i18n/t']('harvester.pci.detachWarning.title'),
|
||||||
|
message: this.$rootGetters['i18n/t']('harvester.pci.detachWarning.message'),
|
||||||
|
timeout: 5000
|
||||||
|
}, { root: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
get allowDisable() {
|
||||||
|
return this._allowDisable;
|
||||||
|
}
|
||||||
|
|
||||||
|
set allowDisable(value) {
|
||||||
|
this._allowDisable = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,6 +133,12 @@ export default class USBDevice extends SteveModel {
|
|||||||
// 'disable' passthrough deletes claim
|
// 'disable' passthrough deletes claim
|
||||||
// backend should return error if device is in use
|
// backend should return error if device is in use
|
||||||
async disablePassthrough() {
|
async disablePassthrough() {
|
||||||
|
if (!this.allowDisable) {
|
||||||
|
this.showDetachWarning();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!this.claimedByMe) {
|
if (!this.claimedByMe) {
|
||||||
throw new Error(this.$rootGetters['i18n/t']('harvester.usb.cantUnclaim', { name: escapeHtml(this.metadata.name) }));
|
throw new Error(this.$rootGetters['i18n/t']('harvester.usb.cantUnclaim', { name: escapeHtml(this.metadata.name) }));
|
||||||
@ -158,4 +164,20 @@ export default class USBDevice extends SteveModel {
|
|||||||
get groupByDevice() {
|
get groupByDevice() {
|
||||||
return this.status?.description;
|
return this.status?.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showDetachWarning() {
|
||||||
|
this.$dispatch('growl/warning', {
|
||||||
|
title: this.$rootGetters['i18n/t']('harvester.usb.detachWarning.title'),
|
||||||
|
message: this.$rootGetters['i18n/t']('harvester.usb.detachWarning.message'),
|
||||||
|
timeout: 5000
|
||||||
|
}, { root: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
get allowDisable() {
|
||||||
|
return this._allowDisable;
|
||||||
|
}
|
||||||
|
|
||||||
|
set allowDisable(value) {
|
||||||
|
this._allowDisable = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,6 +100,12 @@ export default class VGpuDevice extends SteveModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async disableVGpu() {
|
async disableVGpu() {
|
||||||
|
if (!this.allowDisable) {
|
||||||
|
this.showDetachWarning();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { vGPUTypeName, enabled } = this.spec;
|
const { vGPUTypeName, enabled } = this.spec;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -126,4 +132,20 @@ export default class VGpuDevice extends SteveModel {
|
|||||||
get vGpuAvailableTypes() {
|
get vGpuAvailableTypes() {
|
||||||
return this.status?.availableTypes ? Object.keys(this.status.availableTypes) : [];
|
return this.status?.availableTypes ? Object.keys(this.status.availableTypes) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showDetachWarning() {
|
||||||
|
this.$dispatch('growl/warning', {
|
||||||
|
title: this.$rootGetters['i18n/t']('harvester.vgpu.detachWarning.title'),
|
||||||
|
message: this.$rootGetters['i18n/t']('harvester.vgpu.detachWarning.message'),
|
||||||
|
timeout: 5000
|
||||||
|
}, { root: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
get allowDisable() {
|
||||||
|
return this._allowDisable;
|
||||||
|
}
|
||||||
|
|
||||||
|
set allowDisable(value) {
|
||||||
|
this._allowDisable = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -354,7 +354,7 @@ export default class HciNode extends HarvesterResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get isCordoned() {
|
get isCordoned() {
|
||||||
return (this.isUnSchedulable && !this.isEtcd) || this.hasAction('uncordon');
|
return this.hasAction('uncordon');
|
||||||
}
|
}
|
||||||
|
|
||||||
get isEtcd() {
|
get isEtcd() {
|
||||||
|
|||||||
@ -318,8 +318,21 @@ export default class HciVmImage extends HarvesterResource {
|
|||||||
get uploadImage() {
|
get uploadImage() {
|
||||||
return async(file, opt = {}) => {
|
return async(file, opt = {}) => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
const backend = this.spec?.backend || 'backingimage';
|
||||||
|
const backendFieldMap = {
|
||||||
|
cdi: 'file',
|
||||||
|
backingimage: 'chunk'
|
||||||
|
};
|
||||||
|
const fieldName = backendFieldMap[backend];
|
||||||
|
|
||||||
formData.append('chunk', file);
|
if (!fieldName) {
|
||||||
|
const error = this.t('harvester.image.errors.unsupportedBackend', { backend });
|
||||||
|
|
||||||
|
this.$ctx.commit('harvester-common/uploadError', { name: this.name, message: error }, { root: true });
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.append(fieldName, file);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.$ctx.commit('harvester-common/uploadStart', this.metadata.name, { root: true });
|
this.$ctx.commit('harvester-common/uploadStart', this.metadata.name, { root: true });
|
||||||
|
|||||||
@ -153,7 +153,7 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: 'takeVMSnapshot',
|
action: 'takeVMSnapshot',
|
||||||
enabled: (!!this.actions?.snapshot || !!this.action?.backup),
|
enabled: (!!this.actions?.snapshot || !!this.actions?.backup),
|
||||||
icon: 'icon icon-snapshot',
|
icon: 'icon icon-snapshot',
|
||||||
label: this.t('harvester.action.vmSnapshot')
|
label: this.t('harvester.action.vmSnapshot')
|
||||||
},
|
},
|
||||||
@ -1180,11 +1180,15 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get stateDescription() {
|
get isRestartRequired() {
|
||||||
const conditions = get(this, 'status.conditions');
|
const conditions = get(this, 'status.conditions');
|
||||||
const restartRequired = findBy(conditions, 'type', 'RestartRequired');
|
const restartRequired = findBy(conditions, 'type', 'RestartRequired');
|
||||||
|
|
||||||
if (restartRequired && restartRequired.status === 'True') {
|
return restartRequired && restartRequired.status === 'True';
|
||||||
|
}
|
||||||
|
|
||||||
|
get stateDescription() {
|
||||||
|
if (this.isRestartRequired) {
|
||||||
return this.t('harvester.virtualMachine.hotplug.restartVMMessage');
|
return this.t('harvester.virtualMachine.hotplug.restartVMMessage');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
"annotations": {
|
"annotations": {
|
||||||
"catalog.cattle.io/display-name": "Harvester",
|
"catalog.cattle.io/display-name": "Harvester",
|
||||||
"catalog.cattle.io/kube-version": ">= 1.16.0-0",
|
"catalog.cattle.io/kube-version": ">= 1.16.0-0",
|
||||||
"catalog.cattle.io/rancher-version": ">= 2.13.0-0",
|
"catalog.cattle.io/rancher-version": ">= 2.14.0-0",
|
||||||
"catalog.cattle.io/ui-extensions-version": ">= 3.0.0 < 4.0.0"
|
"catalog.cattle.io/ui-extensions-version": ">= 3.0.0 < 4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import { PRODUCT_NAME as HARVESTER_PRODUCT } from '../../../../config/harvester'
|
|||||||
import ImagePercentageBar from '@shell/components/formatter/ImagePercentageBar';
|
import ImagePercentageBar from '@shell/components/formatter/ImagePercentageBar';
|
||||||
import { Banner } from '@components/Banner';
|
import { Banner } from '@components/Banner';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import { STORAGE_CLASS } from '@shell/config/types';
|
|
||||||
|
|
||||||
const IMAGE_METHOD = {
|
const IMAGE_METHOD = {
|
||||||
NEW: 'new',
|
NEW: 'new',
|
||||||
@ -33,7 +32,6 @@ export default {
|
|||||||
|
|
||||||
async fetch() {
|
async fetch() {
|
||||||
await this.$store.dispatch('harvester/findAll', { type: HCI.IMAGE });
|
await this.$store.dispatch('harvester/findAll', { type: HCI.IMAGE });
|
||||||
await this.$store.dispatch('harvester/findAll', { type: STORAGE_CLASS });
|
|
||||||
|
|
||||||
const value = await this.$store.dispatch('harvester/create', {
|
const value = await this.$store.dispatch('harvester/create', {
|
||||||
type: HCI.UPGRADE,
|
type: HCI.UPGRADE,
|
||||||
@ -65,7 +63,6 @@ export default {
|
|||||||
sourceType: UPLOAD,
|
sourceType: UPLOAD,
|
||||||
uploadController: null,
|
uploadController: null,
|
||||||
uploadResult: null,
|
uploadResult: null,
|
||||||
storageClassValue: null,
|
|
||||||
imageValue: null,
|
imageValue: null,
|
||||||
enableLogging: true,
|
enableLogging: true,
|
||||||
IMAGE_METHOD,
|
IMAGE_METHOD,
|
||||||
@ -183,38 +180,6 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async createImageStorageClass(imageName = '') {
|
|
||||||
// delete related SC if existed
|
|
||||||
await this.deleteImageStorageClass(imageName);
|
|
||||||
|
|
||||||
const storageClassPayload = {
|
|
||||||
apiVersion: 'storage.k8s.io/v1',
|
|
||||||
type: STORAGE_CLASS,
|
|
||||||
metadata: { name: imageName },
|
|
||||||
volumeBindingMode: 'Immediate',
|
|
||||||
reclaimPolicy: 'Delete',
|
|
||||||
allowVolumeExpansion: true, // must be boolean type
|
|
||||||
provisioner: 'driver.longhorn.io',
|
|
||||||
};
|
|
||||||
|
|
||||||
this.storageClassValue = await this.$store.dispatch('harvester/create', storageClassPayload);
|
|
||||||
|
|
||||||
if (this.storageClassValue && this.storageClassValue.save) {
|
|
||||||
await this.storageClassValue.save();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async deleteImageStorageClass(imageName = '') {
|
|
||||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
||||||
const storageClasses = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS);
|
|
||||||
|
|
||||||
const targetSC = storageClasses.find((sc) => sc.id === imageName);
|
|
||||||
|
|
||||||
if (targetSC && targetSC.remove) {
|
|
||||||
await targetSC.remove();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async initImageValue() {
|
async initImageValue() {
|
||||||
this.imageValue = await this.$store.dispatch('harvester/create', {
|
this.imageValue = await this.$store.dispatch('harvester/create', {
|
||||||
type: HCI.IMAGE,
|
type: HCI.IMAGE,
|
||||||
@ -263,10 +228,8 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create related image storage class first
|
|
||||||
await this.createImageStorageClass(imageDisplayName);
|
|
||||||
this.imageValue.spec.sourceType = DOWNLOAD;
|
this.imageValue.spec.sourceType = DOWNLOAD;
|
||||||
this.imageValue.spec.targetStorageClassName = imageDisplayName;
|
this.imageValue.spec.targetStorageClassName = 'longhorn-static';
|
||||||
|
|
||||||
res = await this.imageValue.save();
|
res = await this.imageValue.save();
|
||||||
|
|
||||||
@ -295,8 +258,6 @@ export default {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errors = [e?.message] || exceptionToErrorsArray(e);
|
this.errors = [e?.message] || exceptionToErrorsArray(e);
|
||||||
buttonCb(false);
|
buttonCb(false);
|
||||||
// if anything failed, delete the created image storage class
|
|
||||||
await this.deleteImageStorageClass(imageDisplayName);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -325,9 +286,7 @@ export default {
|
|||||||
this.imageValue.spec.url = '';
|
this.imageValue.spec.url = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// before uploading image, we need to create related image storage class first
|
this.imageValue.spec.targetStorageClassName = 'longhorn-static';
|
||||||
await this.createImageStorageClass(fileName);
|
|
||||||
this.imageValue.spec.targetStorageClassName = fileName;
|
|
||||||
|
|
||||||
const res = await this.imageValue.save();
|
const res = await this.imageValue.save();
|
||||||
|
|
||||||
@ -345,8 +304,6 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.errors = exceptionToErrorsArray(e);
|
this.errors = exceptionToErrorsArray(e);
|
||||||
}
|
}
|
||||||
// if upload failed, delete the created image storage class
|
|
||||||
await this.deleteImageStorageClass(fileName);
|
|
||||||
this.file = {};
|
this.file = {};
|
||||||
this.uploadImageId = '';
|
this.uploadImageId = '';
|
||||||
}
|
}
|
||||||
@ -367,13 +324,10 @@ export default {
|
|||||||
|
|
||||||
if (image && imageDisplayName) {
|
if (image && imageDisplayName) {
|
||||||
this.$store.dispatch('harvester/promptModal', {
|
this.$store.dispatch('harvester/promptModal', {
|
||||||
resources: [image],
|
resources: [image],
|
||||||
component: 'ConfirmRelatedToRemoveDialog',
|
component: 'ConfirmRelatedToRemoveDialog',
|
||||||
needConfirmation: false,
|
needConfirmation: false,
|
||||||
warningMessage: this.$store.getters['i18n/t']('harvester.modal.osImage.message', { name: imageDisplayName }),
|
warningMessage: this.$store.getters['i18n/t']('harvester.modal.osImage.message', { name: imageDisplayName }),
|
||||||
extraActionAfterRemove: async() => {
|
|
||||||
await this.deleteImageStorageClass(imageDisplayName);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
this.deleteImageId = '';
|
this.deleteImageId = '';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,11 @@ export const HCI = {
|
|||||||
IP_POOL: 'loadbalancer.harvesterhci.io.ippool',
|
IP_POOL: 'loadbalancer.harvesterhci.io.ippool',
|
||||||
HARVESTER_CONFIG: 'rke-machine-config.cattle.io.harvesterconfig',
|
HARVESTER_CONFIG: 'rke-machine-config.cattle.io.harvesterconfig',
|
||||||
LVM_VOLUME_GROUP: 'harvesterhci.io.lvmvolumegroup',
|
LVM_VOLUME_GROUP: 'harvesterhci.io.lvmvolumegroup',
|
||||||
|
VMIMPORT_SOURCE_V: 'migration.harvesterhci.io.vmwaresource',
|
||||||
|
VMIMPORT_SOURCE_O: 'migration.harvesterhci.io.openstacksource',
|
||||||
|
VMIMPORT_SOURCE_OVA: 'migration.harvesterhci.io.ovasource',
|
||||||
|
VMIMPORT: 'migration.harvesterhci.io.virtualmachineimport',
|
||||||
|
MIGRATION: 'migration.harvesterhci.io',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VOLUME_SNAPSHOT = 'snapshot.storage.k8s.io.volumesnapshot';
|
export const VOLUME_SNAPSHOT = 'snapshot.storage.k8s.io.volumesnapshot';
|
||||||
|
|||||||
99
pkg/harvester/utils/dynamic-nav.js
Normal file
99
pkg/harvester/utils/dynamic-nav.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* Dynamically toggles SideNav entries based on the enabled status of a specific Addon.
|
||||||
|
*
|
||||||
|
* @param {Object} store - The Vuex store instance.
|
||||||
|
* @param {String} productName - The product name (e.g. 'harvester').
|
||||||
|
* @param {Object} config - Configuration object.
|
||||||
|
* @param {String} config.addonName - The name of the addon to watch.
|
||||||
|
* @param {String} config.resourceType - The schema ID for addons.
|
||||||
|
* @param {String} config.navGroup - The group name in the side nav.
|
||||||
|
* @param {Array<String>} config.types - Array of Resource IDs to show/hide.
|
||||||
|
*/
|
||||||
|
export function registerAddonSideNav(store, productName, {
|
||||||
|
addonName, resourceType, navGroup, types
|
||||||
|
}) {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forces the SideNav component to re-render by toggling a dummy user preference.
|
||||||
|
// Necessary because the menu component does not automatically detect
|
||||||
|
// changes to the allowed types list.
|
||||||
|
const kickSideNav = () => {
|
||||||
|
const TRIGGER = 'ui.refresh.trigger';
|
||||||
|
|
||||||
|
store.dispatch('type-map/addFavorite', TRIGGER);
|
||||||
|
|
||||||
|
// SideNav component seem to ignore rapid state changes.
|
||||||
|
// Wait 600ms to ensure the toggle event triggers a re-render.
|
||||||
|
setTimeout(() => {
|
||||||
|
store.dispatch('type-map/removeFavorite', TRIGGER);
|
||||||
|
}, 600);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Adds or removes the resource IDs from the product visibility whitelist.
|
||||||
|
const setMenuVisibility = (visible) => {
|
||||||
|
if (visible) {
|
||||||
|
store.commit('type-map/basicType', {
|
||||||
|
product: productName,
|
||||||
|
group: navGroup,
|
||||||
|
types
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Manually delete the keys from the state object to hide them.
|
||||||
|
const basicTypes = store.state['type-map'].basicTypes[productName];
|
||||||
|
|
||||||
|
if (basicTypes) {
|
||||||
|
types.forEach((t) => delete basicTypes[t]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kickSideNav();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start polling to check if the store is ready.
|
||||||
|
let attempts = 0;
|
||||||
|
const MAX_ATTEMPTS = 60;
|
||||||
|
|
||||||
|
const waitForStore = setInterval(() => {
|
||||||
|
attempts++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if the Schema definitions are loaded.
|
||||||
|
const hasSchema = store.getters[`${ productName }/schemaFor`] &&
|
||||||
|
store.getters[`${ productName }/schemaFor`](resourceType);
|
||||||
|
|
||||||
|
// Check if the resource list data is fully loaded to prevent race conditions.
|
||||||
|
const hasData = store.getters[`${ productName }/haveAll`] &&
|
||||||
|
store.getters[`${ productName }/haveAll`](resourceType);
|
||||||
|
|
||||||
|
if (hasSchema && hasData) {
|
||||||
|
// Store is ready. Stop polling.
|
||||||
|
clearInterval(waitForStore);
|
||||||
|
|
||||||
|
// Watch the specific addon resource for changes to its enabled status.
|
||||||
|
store.watch(
|
||||||
|
(state, getters) => {
|
||||||
|
const addons = getters[`${ productName }/all`](resourceType);
|
||||||
|
const addon = addons.find((a) => a.metadata.name === addonName);
|
||||||
|
|
||||||
|
return addon?.spec?.enabled === true;
|
||||||
|
},
|
||||||
|
(isEnabled) => {
|
||||||
|
setMenuVisibility(isEnabled);
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
);
|
||||||
|
} else if (hasSchema && !hasData) {
|
||||||
|
// If the schema is ready but the data is missing, request the list from the API.
|
||||||
|
// Ensures the script does not wait indefinitely if the UI has not loaded the addons yet.
|
||||||
|
store.dispatch(`${ productName }/findAll`, { type: resourceType });
|
||||||
|
} else if (attempts >= MAX_ATTEMPTS) {
|
||||||
|
// Stop checking if the store does not load within the timeout limit.
|
||||||
|
clearInterval(waitForStore);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore errors if the store module is not yet registered and wait for the next attempt.
|
||||||
|
if (attempts >= MAX_ATTEMPTS) clearInterval(waitForStore);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
472
yarn.lock
472
yarn.lock
@ -927,12 +927,12 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/highlight" "^7.10.4"
|
"@babel/highlight" "^7.10.4"
|
||||||
|
|
||||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.7", "@babel/code-frame@^7.27.1", "@babel/code-frame@^7.8.3":
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.7", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.8.3":
|
||||||
version "7.27.1"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7"
|
||||||
integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
|
integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-validator-identifier" "^7.27.1"
|
"@babel/helper-validator-identifier" "^7.28.5"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
picocolors "^1.1.1"
|
picocolors "^1.1.1"
|
||||||
|
|
||||||
@ -941,7 +941,12 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb"
|
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb"
|
||||||
integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==
|
integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==
|
||||||
|
|
||||||
"@babel/core@^7.1.0", "@babel/core@^7.12.16", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0":
|
"@babel/compat-data@^7.28.6":
|
||||||
|
version "7.28.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c"
|
||||||
|
integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==
|
||||||
|
|
||||||
|
"@babel/core@^7.1.0", "@babel/core@^7.12.16", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
|
||||||
version "7.25.2"
|
version "7.25.2"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77"
|
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77"
|
||||||
integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==
|
integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==
|
||||||
@ -962,13 +967,34 @@
|
|||||||
json5 "^2.2.3"
|
json5 "^2.2.3"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/generator@^7.25.0", "@babel/generator@^7.28.3", "@babel/generator@^7.7.2":
|
"@babel/core@^7.23.9":
|
||||||
version "7.28.3"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.3.tgz#9626c1741c650cbac39121694a0f2d7451b8ef3e"
|
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f"
|
||||||
integrity sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==
|
integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/parser" "^7.28.3"
|
"@babel/code-frame" "^7.28.6"
|
||||||
"@babel/types" "^7.28.2"
|
"@babel/generator" "^7.28.6"
|
||||||
|
"@babel/helper-compilation-targets" "^7.28.6"
|
||||||
|
"@babel/helper-module-transforms" "^7.28.6"
|
||||||
|
"@babel/helpers" "^7.28.6"
|
||||||
|
"@babel/parser" "^7.28.6"
|
||||||
|
"@babel/template" "^7.28.6"
|
||||||
|
"@babel/traverse" "^7.28.6"
|
||||||
|
"@babel/types" "^7.28.6"
|
||||||
|
"@jridgewell/remapping" "^2.3.5"
|
||||||
|
convert-source-map "^2.0.0"
|
||||||
|
debug "^4.1.0"
|
||||||
|
gensync "^1.0.0-beta.2"
|
||||||
|
json5 "^2.2.3"
|
||||||
|
semver "^6.3.1"
|
||||||
|
|
||||||
|
"@babel/generator@^7.25.0", "@babel/generator@^7.28.6", "@babel/generator@^7.7.2":
|
||||||
|
version "7.28.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1"
|
||||||
|
integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.28.6"
|
||||||
|
"@babel/types" "^7.28.6"
|
||||||
"@jridgewell/gen-mapping" "^0.3.12"
|
"@jridgewell/gen-mapping" "^0.3.12"
|
||||||
"@jridgewell/trace-mapping" "^0.3.28"
|
"@jridgewell/trace-mapping" "^0.3.28"
|
||||||
jsesc "^3.0.2"
|
jsesc "^3.0.2"
|
||||||
@ -999,17 +1025,28 @@
|
|||||||
lru-cache "^5.1.1"
|
lru-cache "^5.1.1"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.24.7", "@babel/helper-create-class-features-plugin@^7.25.0", "@babel/helper-create-class-features-plugin@^7.25.4", "@babel/helper-create-class-features-plugin@^7.28.3":
|
"@babel/helper-compilation-targets@^7.28.6":
|
||||||
version "7.28.3"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz#3e747434ea007910c320c4d39a6b46f20f371d46"
|
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25"
|
||||||
integrity sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==
|
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-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.24.7", "@babel/helper-create-class-features-plugin@^7.25.0", "@babel/helper-create-class-features-plugin@^7.25.4", "@babel/helper-create-class-features-plugin@^7.28.6":
|
||||||
|
version "7.28.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz#611ff5482da9ef0db6291bcd24303400bca170fb"
|
||||||
|
integrity sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-annotate-as-pure" "^7.27.3"
|
"@babel/helper-annotate-as-pure" "^7.27.3"
|
||||||
"@babel/helper-member-expression-to-functions" "^7.27.1"
|
"@babel/helper-member-expression-to-functions" "^7.28.5"
|
||||||
"@babel/helper-optimise-call-expression" "^7.27.1"
|
"@babel/helper-optimise-call-expression" "^7.27.1"
|
||||||
"@babel/helper-replace-supers" "^7.27.1"
|
"@babel/helper-replace-supers" "^7.28.6"
|
||||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
|
"@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
|
||||||
"@babel/traverse" "^7.28.3"
|
"@babel/traverse" "^7.28.6"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0", "@babel/helper-create-regexp-features-plugin@^7.25.2":
|
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0", "@babel/helper-create-regexp-features-plugin@^7.25.2":
|
||||||
@ -1037,13 +1074,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
|
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
|
||||||
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
|
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
|
||||||
|
|
||||||
"@babel/helper-member-expression-to-functions@^7.27.1":
|
"@babel/helper-member-expression-to-functions@^7.28.5":
|
||||||
version "7.27.1"
|
version "7.28.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44"
|
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz#f3e07a10be37ed7a63461c63e6929575945a6150"
|
||||||
integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==
|
integrity sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/traverse" "^7.27.1"
|
"@babel/traverse" "^7.28.5"
|
||||||
"@babel/types" "^7.27.1"
|
"@babel/types" "^7.28.5"
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.24.7":
|
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.24.7":
|
||||||
version "7.24.7"
|
version "7.24.7"
|
||||||
@ -1053,6 +1090,14 @@
|
|||||||
"@babel/traverse" "^7.24.7"
|
"@babel/traverse" "^7.24.7"
|
||||||
"@babel/types" "^7.24.7"
|
"@babel/types" "^7.24.7"
|
||||||
|
|
||||||
|
"@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.22.15":
|
"@babel/helper-module-imports@~7.22.15":
|
||||||
version "7.22.15"
|
version "7.22.15"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0"
|
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0"
|
||||||
@ -1070,6 +1115,15 @@
|
|||||||
"@babel/helper-validator-identifier" "^7.24.7"
|
"@babel/helper-validator-identifier" "^7.24.7"
|
||||||
"@babel/traverse" "^7.25.2"
|
"@babel/traverse" "^7.25.2"
|
||||||
|
|
||||||
|
"@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-optimise-call-expression@^7.27.1":
|
"@babel/helper-optimise-call-expression@^7.27.1":
|
||||||
version "7.27.1"
|
version "7.27.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200"
|
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200"
|
||||||
@ -1077,10 +1131,10 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.27.1"
|
"@babel/types" "^7.27.1"
|
||||||
|
|
||||||
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
||||||
version "7.27.1"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c"
|
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8"
|
||||||
integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==
|
integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==
|
||||||
|
|
||||||
"@babel/helper-remap-async-to-generator@^7.24.7", "@babel/helper-remap-async-to-generator@^7.25.0":
|
"@babel/helper-remap-async-to-generator@^7.24.7", "@babel/helper-remap-async-to-generator@^7.25.0":
|
||||||
version "7.25.0"
|
version "7.25.0"
|
||||||
@ -1091,14 +1145,14 @@
|
|||||||
"@babel/helper-wrap-function" "^7.25.0"
|
"@babel/helper-wrap-function" "^7.25.0"
|
||||||
"@babel/traverse" "^7.25.0"
|
"@babel/traverse" "^7.25.0"
|
||||||
|
|
||||||
"@babel/helper-replace-supers@^7.24.7", "@babel/helper-replace-supers@^7.25.0", "@babel/helper-replace-supers@^7.27.1":
|
"@babel/helper-replace-supers@^7.24.7", "@babel/helper-replace-supers@^7.25.0", "@babel/helper-replace-supers@^7.28.6":
|
||||||
version "7.27.1"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0"
|
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz#94aa9a1d7423a00aead3f204f78834ce7d53fe44"
|
||||||
integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==
|
integrity sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-member-expression-to-functions" "^7.27.1"
|
"@babel/helper-member-expression-to-functions" "^7.28.5"
|
||||||
"@babel/helper-optimise-call-expression" "^7.27.1"
|
"@babel/helper-optimise-call-expression" "^7.27.1"
|
||||||
"@babel/traverse" "^7.27.1"
|
"@babel/traverse" "^7.28.6"
|
||||||
|
|
||||||
"@babel/helper-simple-access@^7.24.7":
|
"@babel/helper-simple-access@^7.24.7":
|
||||||
version "7.24.7"
|
version "7.24.7"
|
||||||
@ -1121,7 +1175,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
|
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
|
||||||
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
|
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.24.7", "@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5":
|
"@babel/helper-validator-identifier@^7.24.7", "@babel/helper-validator-identifier@^7.28.5":
|
||||||
version "7.28.5"
|
version "7.28.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4"
|
||||||
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
|
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
|
||||||
@ -1131,6 +1185,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d"
|
||||||
integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==
|
integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==
|
||||||
|
|
||||||
|
"@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-wrap-function@^7.25.0":
|
"@babel/helper-wrap-function@^7.25.0":
|
||||||
version "7.25.0"
|
version "7.25.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz#dab12f0f593d6ca48c0062c28bcfb14ebe812f81"
|
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz#dab12f0f593d6ca48c0062c28bcfb14ebe812f81"
|
||||||
@ -1148,6 +1207,14 @@
|
|||||||
"@babel/template" "^7.25.0"
|
"@babel/template" "^7.25.0"
|
||||||
"@babel/types" "^7.25.6"
|
"@babel/types" "^7.25.6"
|
||||||
|
|
||||||
|
"@babel/helpers@^7.28.6":
|
||||||
|
version "7.28.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7"
|
||||||
|
integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/template" "^7.28.6"
|
||||||
|
"@babel/types" "^7.28.6"
|
||||||
|
|
||||||
"@babel/highlight@^7.10.4":
|
"@babel/highlight@^7.10.4":
|
||||||
version "7.24.7"
|
version "7.24.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d"
|
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d"
|
||||||
@ -1158,12 +1225,12 @@
|
|||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.27.2", "@babel/parser@^7.28.0", "@babel/parser@^7.28.3", "@babel/parser@^7.7.0":
|
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.28.0", "@babel/parser@^7.28.6", "@babel/parser@^7.7.0":
|
||||||
version "7.28.5"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.5.tgz#0b0225ee90362f030efd644e8034c99468893b08"
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd"
|
||||||
integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==
|
integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.28.5"
|
"@babel/types" "^7.28.6"
|
||||||
|
|
||||||
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.3":
|
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.3":
|
||||||
version "7.25.3"
|
version "7.25.3"
|
||||||
@ -1456,13 +1523,13 @@
|
|||||||
"@babel/helper-create-class-features-plugin" "^7.25.4"
|
"@babel/helper-create-class-features-plugin" "^7.25.4"
|
||||||
"@babel/helper-plugin-utils" "^7.24.8"
|
"@babel/helper-plugin-utils" "^7.24.8"
|
||||||
|
|
||||||
"@babel/plugin-transform-class-static-block@7.28.3", "@babel/plugin-transform-class-static-block@^7.24.7":
|
"@babel/plugin-transform-class-static-block@7.28.6", "@babel/plugin-transform-class-static-block@^7.24.7":
|
||||||
version "7.28.3"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz#d1b8e69b54c9993bc558203e1f49bfc979bfd852"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz#1257491e8259c6d125ac4d9a6f39f9d2bf3dba70"
|
||||||
integrity sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==
|
integrity sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-create-class-features-plugin" "^7.28.3"
|
"@babel/helper-create-class-features-plugin" "^7.28.6"
|
||||||
"@babel/helper-plugin-utils" "^7.27.1"
|
"@babel/helper-plugin-utils" "^7.28.6"
|
||||||
|
|
||||||
"@babel/plugin-transform-classes@^7.25.4":
|
"@babel/plugin-transform-classes@^7.25.4":
|
||||||
version "7.25.4"
|
version "7.25.4"
|
||||||
@ -1942,32 +2009,32 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.14.0"
|
regenerator-runtime "^0.14.0"
|
||||||
|
|
||||||
"@babel/template@^7.23.9", "@babel/template@^7.24.7", "@babel/template@^7.25.0", "@babel/template@^7.27.2", "@babel/template@^7.3.3":
|
"@babel/template@^7.23.9", "@babel/template@^7.24.7", "@babel/template@^7.25.0", "@babel/template@^7.28.6", "@babel/template@^7.3.3":
|
||||||
version "7.27.2"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57"
|
||||||
integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==
|
integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.27.1"
|
"@babel/code-frame" "^7.28.6"
|
||||||
"@babel/parser" "^7.27.2"
|
"@babel/parser" "^7.28.6"
|
||||||
"@babel/types" "^7.27.1"
|
"@babel/types" "^7.28.6"
|
||||||
|
|
||||||
"@babel/traverse@^7.23.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.4", "@babel/traverse@^7.27.1", "@babel/traverse@^7.28.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2":
|
"@babel/traverse@^7.23.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.4", "@babel/traverse@^7.27.1", "@babel/traverse@^7.28.5", "@babel/traverse@^7.28.6", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2":
|
||||||
version "7.28.3"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.3.tgz#6911a10795d2cce43ec6a28cffc440cca2593434"
|
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e"
|
||||||
integrity sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==
|
integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.27.1"
|
"@babel/code-frame" "^7.28.6"
|
||||||
"@babel/generator" "^7.28.3"
|
"@babel/generator" "^7.28.6"
|
||||||
"@babel/helper-globals" "^7.28.0"
|
"@babel/helper-globals" "^7.28.0"
|
||||||
"@babel/parser" "^7.28.3"
|
"@babel/parser" "^7.28.6"
|
||||||
"@babel/template" "^7.27.2"
|
"@babel/template" "^7.28.6"
|
||||||
"@babel/types" "^7.28.2"
|
"@babel/types" "^7.28.6"
|
||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
|
|
||||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.23.9", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
|
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.23.9", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.5", "@babel/types@^7.28.6", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
|
||||||
version "7.28.5"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b"
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df"
|
||||||
integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==
|
integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-string-parser" "^7.27.1"
|
"@babel/helper-string-parser" "^7.27.1"
|
||||||
"@babel/helper-validator-identifier" "^7.28.5"
|
"@babel/helper-validator-identifier" "^7.28.5"
|
||||||
@ -2269,7 +2336,7 @@
|
|||||||
js-yaml "^3.13.1"
|
js-yaml "^3.13.1"
|
||||||
resolve-from "^5.0.0"
|
resolve-from "^5.0.0"
|
||||||
|
|
||||||
"@istanbuljs/schema@^0.1.2":
|
"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3":
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
|
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
|
||||||
integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
|
integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
|
||||||
@ -2451,6 +2518,14 @@
|
|||||||
"@jridgewell/sourcemap-codec" "^1.5.0"
|
"@jridgewell/sourcemap-codec" "^1.5.0"
|
||||||
"@jridgewell/trace-mapping" "^0.3.24"
|
"@jridgewell/trace-mapping" "^0.3.24"
|
||||||
|
|
||||||
|
"@jridgewell/remapping@^2.3.5":
|
||||||
|
version "2.3.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1"
|
||||||
|
integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/gen-mapping" "^0.3.5"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.24"
|
||||||
|
|
||||||
"@jridgewell/resolve-uri@^3.1.0":
|
"@jridgewell/resolve-uri@^3.1.0":
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
|
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
|
||||||
@ -2634,15 +2709,15 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
||||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||||
|
|
||||||
"@rancher/icons@2.0.53":
|
"@rancher/icons@2.0.54":
|
||||||
version "2.0.53"
|
version "2.0.54"
|
||||||
resolved "https://registry.yarnpkg.com/@rancher/icons/-/icons-2.0.53.tgz#0cbfd0f7d16bd8c99683654d83de99e77d2424c9"
|
resolved "https://registry.yarnpkg.com/@rancher/icons/-/icons-2.0.54.tgz#7e8d4baeac36a483f18f4ce4043809371c4f0117"
|
||||||
integrity sha512-FkJsVZihlbZiaXI5E42W05jQGlV8HRUrWbIK2zg2JkGCLUO3mvratLGL2Yjx8dFz34y37h11DsH9+nFPoHuppA==
|
integrity sha512-Fc5xpT/yuOJJin7ChxAdB6aoG1bREgisktnePUPXpY9nIMHSHYT/Ov8GsC3yLLgoqgpm450nMvPICUO3AYcPdQ==
|
||||||
|
|
||||||
"@rancher/shell@3.0.8-rc.8":
|
"@rancher/shell@3.0.9-rc.1":
|
||||||
version "3.0.8-rc.8"
|
version "3.0.9-rc.1"
|
||||||
resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-3.0.8-rc.8.tgz#19f316cdad1c4d9c828880d908eb4c2273961e24"
|
resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-3.0.9-rc.1.tgz#6dfe7d8a17663d170ddf5f48bec5c7c525c9da86"
|
||||||
integrity sha512-cAIZL755HCjHNjfkIdG8DgresnRqv2TV2KpIkhMTgz6c8wdjozBvnrtz3dMaPfwfKtnGT+wUN+wbN0rjfQ1vug==
|
integrity sha512-X7HKIhprzzLaeZXLhAnWHDjr9Rk1nLko+pno0rEkcK7F9ENQgVuROzVxEgMlFno4bI7RpHXt5tC90rPkXzcsRQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@aws-sdk/client-ec2" "3.863.0"
|
"@aws-sdk/client-ec2" "3.863.0"
|
||||||
"@aws-sdk/client-eks" "3.879.0"
|
"@aws-sdk/client-eks" "3.879.0"
|
||||||
@ -2654,7 +2729,7 @@
|
|||||||
"@babel/preset-typescript" "7.16.7"
|
"@babel/preset-typescript" "7.16.7"
|
||||||
"@novnc/novnc" "1.2.0"
|
"@novnc/novnc" "1.2.0"
|
||||||
"@popperjs/core" "2.11.8"
|
"@popperjs/core" "2.11.8"
|
||||||
"@rancher/icons" "2.0.53"
|
"@rancher/icons" "2.0.54"
|
||||||
"@smithy/fetch-http-handler" "5.1.1"
|
"@smithy/fetch-http-handler" "5.1.1"
|
||||||
"@types/is-url" "1.2.30"
|
"@types/is-url" "1.2.30"
|
||||||
"@types/node" "20.10.8"
|
"@types/node" "20.10.8"
|
||||||
@ -2668,17 +2743,17 @@
|
|||||||
"@vue/vue3-jest" "27.0.0"
|
"@vue/vue3-jest" "27.0.0"
|
||||||
add "2.0.6"
|
add "2.0.6"
|
||||||
ansi_up "5.0.0"
|
ansi_up "5.0.0"
|
||||||
axios "1.12.2"
|
axios "1.13.2"
|
||||||
axios-retry "3.1.9"
|
axios-retry "3.1.9"
|
||||||
babel-eslint "10.1.0"
|
babel-eslint "10.1.0"
|
||||||
babel-plugin-module-resolver "4.0.0"
|
babel-plugin-module-resolver "5.0.2"
|
||||||
babel-preset-vue "2.0.2"
|
babel-preset-vue "2.0.2"
|
||||||
cache-loader "4.1.0"
|
cache-loader "4.1.0"
|
||||||
chart.js "4.4.8"
|
chart.js "4.5.1"
|
||||||
clipboard-polyfill "4.0.1"
|
clipboard-polyfill "4.0.1"
|
||||||
codemirror ">=5.64.0 <6"
|
codemirror ">=5.64.0 <6"
|
||||||
codemirror-editor-vue3 "2.8.0"
|
codemirror-editor-vue3 "2.8.0"
|
||||||
color "4.2.3"
|
color "5.0.3"
|
||||||
cookie "0.7.0"
|
cookie "0.7.0"
|
||||||
cookie-universal "2.2.2"
|
cookie-universal "2.2.2"
|
||||||
core-js "3.45.0"
|
core-js "3.45.0"
|
||||||
@ -2721,7 +2796,7 @@
|
|||||||
jexl "2.3.0"
|
jexl "2.3.0"
|
||||||
jquery "3.5.1"
|
jquery "3.5.1"
|
||||||
js-cookie "3.0.5"
|
js-cookie "3.0.5"
|
||||||
js-yaml "4.1.0"
|
js-yaml "4.1.1"
|
||||||
js-yaml-loader "1.2.2"
|
js-yaml-loader "1.2.2"
|
||||||
jsdiff "1.1.1"
|
jsdiff "1.1.1"
|
||||||
jsonpath-plus "10.3.0"
|
jsonpath-plus "10.3.0"
|
||||||
@ -2731,7 +2806,7 @@
|
|||||||
marked "4.0.17"
|
marked "4.0.17"
|
||||||
node-polyfill-webpack-plugin "3.0.0"
|
node-polyfill-webpack-plugin "3.0.0"
|
||||||
nodemon "2.0.22"
|
nodemon "2.0.22"
|
||||||
nyc "15.1.0"
|
nyc "17.1.0"
|
||||||
papaparse "5.3.0"
|
papaparse "5.3.0"
|
||||||
portal-vue "~3.0.0"
|
portal-vue "~3.0.0"
|
||||||
sass "1.89.2"
|
sass "1.89.2"
|
||||||
@ -2756,7 +2831,7 @@
|
|||||||
vuedraggable "4.1.0"
|
vuedraggable "4.1.0"
|
||||||
vuex "4.1.0"
|
vuex "4.1.0"
|
||||||
webpack-bundle-analyzer "4.10.2"
|
webpack-bundle-analyzer "4.10.2"
|
||||||
webpack-virtual-modules "0.4.3"
|
webpack-virtual-modules "0.6.2"
|
||||||
worker-loader "3.0.8"
|
worker-loader "3.0.8"
|
||||||
xterm "5.2.1"
|
xterm "5.2.1"
|
||||||
xterm-addon-canvas "0.5.0"
|
xterm-addon-canvas "0.5.0"
|
||||||
@ -3430,10 +3505,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||||
|
|
||||||
"@types/lodash@4.17.21":
|
"@types/lodash@4.17.23":
|
||||||
version "4.17.21"
|
version "4.17.23"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.21.tgz#b806831543d696b14f8112db600ea9d3a1df6ea4"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.23.tgz#c1bb06db218acc8fc232da0447473fc2fb9d9841"
|
||||||
integrity sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==
|
integrity sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==
|
||||||
|
|
||||||
"@types/mime@^1":
|
"@types/mime@^1":
|
||||||
version "1.3.5"
|
version "1.3.5"
|
||||||
@ -3453,9 +3528,9 @@
|
|||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/node@*", "@types/node@20.10.8", "@types/node@^14.14.31", "@types/node@~20.19.0":
|
"@types/node@*", "@types/node@20.10.8", "@types/node@^14.14.31", "@types/node@~20.19.0":
|
||||||
version "20.19.27"
|
version "20.19.30"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.27.tgz#d51333f77953a5e4e71d3b5aefa83ec5297fbb80"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.30.tgz#84fa87498ade5cd2b6ba8f8eec01d3b138ca60d0"
|
||||||
integrity sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==
|
integrity sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types "~6.21.0"
|
undici-types "~6.21.0"
|
||||||
|
|
||||||
@ -4680,7 +4755,16 @@ axios-retry@3.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-retry-allowed "^1.1.0"
|
is-retry-allowed "^1.1.0"
|
||||||
|
|
||||||
axios@1.12.2, axios@^1.7.9:
|
axios@1.13.2:
|
||||||
|
version "1.13.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.2.tgz#9ada120b7b5ab24509553ec3e40123521117f687"
|
||||||
|
integrity sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.15.6"
|
||||||
|
form-data "^4.0.4"
|
||||||
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
|
axios@^1.7.9:
|
||||||
version "1.12.2"
|
version "1.12.2"
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.12.2.tgz#6c307390136cf7a2278d09cec63b136dfc6e6da7"
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.12.2.tgz#6c307390136cf7a2278d09cec63b136dfc6e6da7"
|
||||||
integrity sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==
|
integrity sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==
|
||||||
@ -4772,16 +4856,16 @@ babel-plugin-jsx-v-model@^2.0.1:
|
|||||||
html-tags "^2.0.0"
|
html-tags "^2.0.0"
|
||||||
svg-tags "^1.0.0"
|
svg-tags "^1.0.0"
|
||||||
|
|
||||||
babel-plugin-module-resolver@4.0.0:
|
babel-plugin-module-resolver@5.0.2:
|
||||||
version "4.0.0"
|
version "5.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.0.0.tgz#8f3a3d9d48287dc1d3b0d5595113adabd36a847f"
|
resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz#cdeac5d4aaa3b08dd1ac23ddbf516660ed2d293e"
|
||||||
integrity sha512-3pdEq3PXALilSJ6dnC4wMWr0AZixHRM4utpdpBR9g5QG7B7JwWyukQv7a9hVxkbGFl+nQbrHDqqQOIBtTXTP/Q==
|
integrity sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==
|
||||||
dependencies:
|
dependencies:
|
||||||
find-babel-config "^1.2.0"
|
find-babel-config "^2.1.1"
|
||||||
glob "^7.1.6"
|
glob "^9.3.3"
|
||||||
pkg-up "^3.1.0"
|
pkg-up "^3.1.0"
|
||||||
reselect "^4.0.0"
|
reselect "^4.1.7"
|
||||||
resolve "^1.13.1"
|
resolve "^1.22.8"
|
||||||
|
|
||||||
babel-plugin-polyfill-corejs2@^0.4.10:
|
babel-plugin-polyfill-corejs2@^0.4.10:
|
||||||
version "0.4.11"
|
version "0.4.11"
|
||||||
@ -4869,6 +4953,11 @@ base64-js@^1.3.1:
|
|||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
|
baseline-browser-mapping@^2.9.0:
|
||||||
|
version "2.9.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.18.tgz#c8281693035a9261b10d662a5379650a6c2d1ff7"
|
||||||
|
integrity sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA==
|
||||||
|
|
||||||
batch@0.6.1:
|
batch@0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
|
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
|
||||||
@ -5081,6 +5170,17 @@ browserslist@^4.0.0, browserslist@^4.16.3, browserslist@^4.21.10, browserslist@^
|
|||||||
node-releases "^2.0.18"
|
node-releases "^2.0.18"
|
||||||
update-browserslist-db "^1.1.0"
|
update-browserslist-db "^1.1.0"
|
||||||
|
|
||||||
|
browserslist@^4.24.0:
|
||||||
|
version "4.28.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95"
|
||||||
|
integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==
|
||||||
|
dependencies:
|
||||||
|
baseline-browser-mapping "^2.9.0"
|
||||||
|
caniuse-lite "^1.0.30001759"
|
||||||
|
electron-to-chromium "^1.5.263"
|
||||||
|
node-releases "^2.0.27"
|
||||||
|
update-browserslist-db "^1.2.0"
|
||||||
|
|
||||||
bser@2.1.1:
|
bser@2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
|
resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
|
||||||
@ -5242,6 +5342,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646:
|
|||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz#0ce881f5a19a2dcfda2ecd927df4d5c1684b982f"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz#0ce881f5a19a2dcfda2ecd927df4d5c1684b982f"
|
||||||
integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==
|
integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==
|
||||||
|
|
||||||
|
caniuse-lite@^1.0.30001759:
|
||||||
|
version "1.0.30001766"
|
||||||
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz#b6f6b55cb25a2d888d9393104d14751c6a7d6f7a"
|
||||||
|
integrity sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==
|
||||||
|
|
||||||
case-sensitive-paths-webpack-plugin@^2.3.0:
|
case-sensitive-paths-webpack-plugin@^2.3.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
|
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
|
||||||
@ -5287,10 +5392,10 @@ char-regex@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
|
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
|
||||||
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
|
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
|
||||||
|
|
||||||
chart.js@4.4.8:
|
chart.js@4.5.1:
|
||||||
version "4.4.8"
|
version "4.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.4.8.tgz#54645b638e9d585099bc16b892947b5e6cd2a552"
|
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.5.1.tgz#19dd1a9a386a3f6397691672231cb5fc9c052c35"
|
||||||
integrity sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==
|
integrity sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@kurkle/color" "^0.3.0"
|
"@kurkle/color" "^0.3.0"
|
||||||
|
|
||||||
@ -5496,6 +5601,13 @@ color-convert@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-name "~1.1.4"
|
color-name "~1.1.4"
|
||||||
|
|
||||||
|
color-convert@^3.1.3:
|
||||||
|
version "3.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-3.1.3.tgz#db6627b97181cb8facdfce755ae26f97ab0711f1"
|
||||||
|
integrity sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==
|
||||||
|
dependencies:
|
||||||
|
color-name "^2.0.0"
|
||||||
|
|
||||||
color-name@1.1.3:
|
color-name@1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||||
@ -5506,6 +5618,11 @@ color-name@^1.0.0, color-name@~1.1.4:
|
|||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
|
color-name@^2.0.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-2.1.0.tgz#0b677385c1c4b4edfdeaf77e38fa338e3a40b693"
|
||||||
|
integrity sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==
|
||||||
|
|
||||||
color-string@^1.9.0:
|
color-string@^1.9.0:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
|
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
|
||||||
@ -5514,6 +5631,13 @@ color-string@^1.9.0:
|
|||||||
color-name "^1.0.0"
|
color-name "^1.0.0"
|
||||||
simple-swizzle "^0.2.2"
|
simple-swizzle "^0.2.2"
|
||||||
|
|
||||||
|
color-string@^2.1.3:
|
||||||
|
version "2.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/color-string/-/color-string-2.1.4.tgz#9dcf566ff976e23368c8bd673f5c35103ab41058"
|
||||||
|
integrity sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==
|
||||||
|
dependencies:
|
||||||
|
color-name "^2.0.0"
|
||||||
|
|
||||||
color@4.2.3:
|
color@4.2.3:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
|
resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
|
||||||
@ -5522,6 +5646,14 @@ color@4.2.3:
|
|||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
color-string "^1.9.0"
|
color-string "^1.9.0"
|
||||||
|
|
||||||
|
color@5.0.3:
|
||||||
|
version "5.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/color/-/color-5.0.3.tgz#f79390b1b778e222ffbb54304d3dbeaef633f97f"
|
||||||
|
integrity sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==
|
||||||
|
dependencies:
|
||||||
|
color-convert "^3.1.3"
|
||||||
|
color-string "^2.1.3"
|
||||||
|
|
||||||
colord@^2.9.1:
|
colord@^2.9.1:
|
||||||
version "2.9.3"
|
version "2.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
|
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
|
||||||
@ -5854,7 +5986,7 @@ cross-spawn@^6.0.0:
|
|||||||
shebang-command "^1.2.0"
|
shebang-command "^1.2.0"
|
||||||
which "^1.2.9"
|
which "^1.2.9"
|
||||||
|
|
||||||
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
|
||||||
version "7.0.6"
|
version "7.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||||
@ -6741,6 +6873,11 @@ ejs@3.1.10:
|
|||||||
dependencies:
|
dependencies:
|
||||||
jake "^10.8.5"
|
jake "^10.8.5"
|
||||||
|
|
||||||
|
electron-to-chromium@^1.5.263:
|
||||||
|
version "1.5.278"
|
||||||
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.278.tgz#807a5e321f012a41bfd64e653f35993c9af95493"
|
||||||
|
integrity sha512-dQ0tM1svDRQOwxnXxm+twlGTjr9Upvt8UFWAgmLsxEzFQxhbti4VwxmMjsDxVC51Zo84swW7FVCXEV+VAkhuPw==
|
||||||
|
|
||||||
electron-to-chromium@^1.5.4:
|
electron-to-chromium@^1.5.4:
|
||||||
version "1.5.13"
|
version "1.5.13"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6"
|
||||||
@ -6949,7 +7086,7 @@ es6-error@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
|
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
|
||||||
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
|
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
|
||||||
|
|
||||||
escalade@^3.1.1, escalade@^3.1.2:
|
escalade@^3.1.1, escalade@^3.1.2, escalade@^3.2.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
|
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
|
||||||
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
|
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
|
||||||
@ -7620,13 +7757,12 @@ finalhandler@~1.1.2:
|
|||||||
statuses "~1.5.0"
|
statuses "~1.5.0"
|
||||||
unpipe "~1.0.0"
|
unpipe "~1.0.0"
|
||||||
|
|
||||||
find-babel-config@^1.2.0:
|
find-babel-config@^2.1.1:
|
||||||
version "1.2.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.2.tgz#41199b5cb9154dcb2fdc351cbe70eaf9198d5111"
|
resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-2.1.2.tgz#2841b1bfbbbcdb971e1e39df8cbc43dafa901716"
|
||||||
integrity sha512-oK59njMyw2y3yxto1BCfVK7MQp/OYf4FleHu0RgosH3riFJ1aOuo/7naLDLAObfrgn3ueFhw5sAT/cp0QuJI3Q==
|
integrity sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==
|
||||||
dependencies:
|
dependencies:
|
||||||
json5 "^1.0.2"
|
json5 "^2.2.3"
|
||||||
path-exists "^3.0.0"
|
|
||||||
|
|
||||||
find-cache-dir@^3.0.0, find-cache-dir@^3.2.0, find-cache-dir@^3.3.1:
|
find-cache-dir@^3.0.0, find-cache-dir@^3.2.0, find-cache-dir@^3.3.1:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
@ -7722,6 +7858,14 @@ foreground-child@^2.0.0:
|
|||||||
cross-spawn "^7.0.0"
|
cross-spawn "^7.0.0"
|
||||||
signal-exit "^3.0.2"
|
signal-exit "^3.0.2"
|
||||||
|
|
||||||
|
foreground-child@^3.3.0:
|
||||||
|
version "3.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f"
|
||||||
|
integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^7.0.6"
|
||||||
|
signal-exit "^4.0.1"
|
||||||
|
|
||||||
forever-agent@~0.6.1:
|
forever-agent@~0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||||
@ -7970,7 +8114,7 @@ glob-to-regexp@^0.4.1:
|
|||||||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
|
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
|
||||||
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
|
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
|
||||||
|
|
||||||
glob@7.2.3, glob@^10.3.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
|
glob@7.2.3, glob@^10.3.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^9.3.3:
|
||||||
version "7.2.3"
|
version "7.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||||
@ -8225,9 +8369,9 @@ html-tags@^3.3.1:
|
|||||||
integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==
|
integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==
|
||||||
|
|
||||||
html-webpack-plugin@^5.0.0, html-webpack-plugin@^5.1.0:
|
html-webpack-plugin@^5.0.0, html-webpack-plugin@^5.1.0:
|
||||||
version "5.6.5"
|
version "5.6.6"
|
||||||
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.5.tgz#d57defb83cabbf29bf56b2d4bf10b67b650066be"
|
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.6.tgz#5321b9579f4a1949318550ced99c2a4a4e60cbaf"
|
||||||
integrity sha512-4xynFbKNNk+WlzXeQQ+6YYsH2g7mpfPszQZUi3ovKlj+pDmngQ7vRXjrrmGROabmKwyQkcgcX5hqfOwHbFmK5g==
|
integrity sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/html-minifier-terser" "^6.0.0"
|
"@types/html-minifier-terser" "^6.0.0"
|
||||||
html-minifier-terser "^6.0.2"
|
html-minifier-terser "^6.0.2"
|
||||||
@ -8920,16 +9064,6 @@ istanbul-lib-hook@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
append-transform "^2.0.0"
|
append-transform "^2.0.0"
|
||||||
|
|
||||||
istanbul-lib-instrument@^4.0.0:
|
|
||||||
version "4.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d"
|
|
||||||
integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==
|
|
||||||
dependencies:
|
|
||||||
"@babel/core" "^7.7.5"
|
|
||||||
"@istanbuljs/schema" "^0.1.2"
|
|
||||||
istanbul-lib-coverage "^3.0.0"
|
|
||||||
semver "^6.3.0"
|
|
||||||
|
|
||||||
istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0:
|
istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d"
|
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d"
|
||||||
@ -8941,6 +9075,17 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0:
|
|||||||
istanbul-lib-coverage "^3.2.0"
|
istanbul-lib-coverage "^3.2.0"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
|
istanbul-lib-instrument@^6.0.2:
|
||||||
|
version "6.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765"
|
||||||
|
integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==
|
||||||
|
dependencies:
|
||||||
|
"@babel/core" "^7.23.9"
|
||||||
|
"@babel/parser" "^7.23.9"
|
||||||
|
"@istanbuljs/schema" "^0.1.3"
|
||||||
|
istanbul-lib-coverage "^3.2.0"
|
||||||
|
semver "^7.5.4"
|
||||||
|
|
||||||
istanbul-lib-processinfo@^2.0.2:
|
istanbul-lib-processinfo@^2.0.2:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz#366d454cd0dcb7eb6e0e419378e60072c8626169"
|
resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz#366d454cd0dcb7eb6e0e419378e60072c8626169"
|
||||||
@ -9469,10 +9614,10 @@ js-yaml-loader@1.2.2:
|
|||||||
loader-utils "^1.2.3"
|
loader-utils "^1.2.3"
|
||||||
un-eval "^1.2.0"
|
un-eval "^1.2.0"
|
||||||
|
|
||||||
js-yaml@4.1.0, js-yaml@^4.1.0:
|
js-yaml@4.1.1:
|
||||||
version "4.1.0"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b"
|
||||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse "^2.0.1"
|
argparse "^2.0.1"
|
||||||
|
|
||||||
@ -9484,6 +9629,13 @@ js-yaml@^3.13.1:
|
|||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
esprima "^4.0.0"
|
esprima "^4.0.0"
|
||||||
|
|
||||||
|
js-yaml@^4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||||
|
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||||
|
dependencies:
|
||||||
|
argparse "^2.0.1"
|
||||||
|
|
||||||
jsbn@~0.1.0:
|
jsbn@~0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||||
@ -10362,6 +10514,11 @@ node-releases@^2.0.18:
|
|||||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
|
||||||
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
|
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
|
||||||
|
|
||||||
|
node-releases@^2.0.27:
|
||||||
|
version "2.0.27"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e"
|
||||||
|
integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==
|
||||||
|
|
||||||
nodemon@2.0.22:
|
nodemon@2.0.22:
|
||||||
version "2.0.22"
|
version "2.0.22"
|
||||||
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258"
|
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258"
|
||||||
@ -10443,10 +10600,10 @@ nwsapi@^2.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8"
|
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8"
|
||||||
integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==
|
integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==
|
||||||
|
|
||||||
nyc@15.1.0:
|
nyc@17.1.0:
|
||||||
version "15.1.0"
|
version "17.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02"
|
resolved "https://registry.yarnpkg.com/nyc/-/nyc-17.1.0.tgz#b6349a401a62ffeb912bd38ea9a018839fdb6eb1"
|
||||||
integrity sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==
|
integrity sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@istanbuljs/load-nyc-config" "^1.0.0"
|
"@istanbuljs/load-nyc-config" "^1.0.0"
|
||||||
"@istanbuljs/schema" "^0.1.2"
|
"@istanbuljs/schema" "^0.1.2"
|
||||||
@ -10455,12 +10612,12 @@ nyc@15.1.0:
|
|||||||
decamelize "^1.2.0"
|
decamelize "^1.2.0"
|
||||||
find-cache-dir "^3.2.0"
|
find-cache-dir "^3.2.0"
|
||||||
find-up "^4.1.0"
|
find-up "^4.1.0"
|
||||||
foreground-child "^2.0.0"
|
foreground-child "^3.3.0"
|
||||||
get-package-type "^0.1.0"
|
get-package-type "^0.1.0"
|
||||||
glob "^7.1.6"
|
glob "^7.1.6"
|
||||||
istanbul-lib-coverage "^3.0.0"
|
istanbul-lib-coverage "^3.0.0"
|
||||||
istanbul-lib-hook "^3.0.0"
|
istanbul-lib-hook "^3.0.0"
|
||||||
istanbul-lib-instrument "^4.0.0"
|
istanbul-lib-instrument "^6.0.2"
|
||||||
istanbul-lib-processinfo "^2.0.2"
|
istanbul-lib-processinfo "^2.0.2"
|
||||||
istanbul-lib-report "^3.0.0"
|
istanbul-lib-report "^3.0.0"
|
||||||
istanbul-lib-source-maps "^4.0.0"
|
istanbul-lib-source-maps "^4.0.0"
|
||||||
@ -11642,7 +11799,7 @@ requires-port@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||||
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
|
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
|
||||||
|
|
||||||
reselect@^4.0.0:
|
reselect@^4.1.7:
|
||||||
version "4.1.8"
|
version "4.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524"
|
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524"
|
||||||
integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==
|
integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==
|
||||||
@ -11669,7 +11826,7 @@ resolve.exports@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999"
|
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999"
|
||||||
integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==
|
integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==
|
||||||
|
|
||||||
resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.4:
|
resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.4:
|
||||||
version "1.22.8"
|
version "1.22.8"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
|
||||||
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
|
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
|
||||||
@ -11678,6 +11835,15 @@ resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.1
|
|||||||
path-parse "^1.0.7"
|
path-parse "^1.0.7"
|
||||||
supports-preserve-symlinks-flag "^1.0.0"
|
supports-preserve-symlinks-flag "^1.0.0"
|
||||||
|
|
||||||
|
resolve@^1.22.8:
|
||||||
|
version "1.22.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262"
|
||||||
|
integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==
|
||||||
|
dependencies:
|
||||||
|
is-core-module "^2.16.1"
|
||||||
|
path-parse "^1.0.7"
|
||||||
|
supports-preserve-symlinks-flag "^1.0.0"
|
||||||
|
|
||||||
restore-cursor@^2.0.0:
|
restore-cursor@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
||||||
@ -11724,10 +11890,10 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||||||
hash-base "^3.0.0"
|
hash-base "^3.0.0"
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
|
|
||||||
roarr@7.21.2:
|
roarr@7.21.4:
|
||||||
version "7.21.2"
|
version "7.21.4"
|
||||||
resolved "https://registry.yarnpkg.com/roarr/-/roarr-7.21.2.tgz#15ae59a04aad05c8c42508dd55fcd2cd286f1fc0"
|
resolved "https://registry.yarnpkg.com/roarr/-/roarr-7.21.4.tgz#c202c84d0b201ac821591f4bb46a3b28b8affe6b"
|
||||||
integrity sha512-RyXI+aNxwVyfF71a9cqz/jhXWbycnVh7GXnnJUniIBXKTOJQF3rmpNexStXt8TUcKyiXCwyfYzboZLMYUllPDA==
|
integrity sha512-qvfUKCrpPzhWmQ4NxRYnuwhkI5lwmObhBU06BCK/lpj6PID9nL4Hk6XDwek2foKI+TMaV+Yw//XZshGF2Lox/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-printf "^1.6.9"
|
fast-printf "^1.6.9"
|
||||||
safe-stable-stringify "^2.4.3"
|
safe-stable-stringify "^2.4.3"
|
||||||
@ -11877,7 +12043,7 @@ semver-compare@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
||||||
integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==
|
integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==
|
||||||
|
|
||||||
"semver@2 || 3 || 4 || 5", semver@7.7.3, semver@^5.5.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.6.0, semver@^7.6.3, semver@~7.0.0:
|
"semver@2 || 3 || 4 || 5", semver@7.7.3, semver@^5.5.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3, semver@~7.0.0:
|
||||||
version "7.7.3"
|
version "7.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
|
||||||
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
||||||
@ -12115,6 +12281,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||||
|
|
||||||
|
signal-exit@^4.0.1:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
||||||
|
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
|
||||||
|
|
||||||
simple-swizzle@^0.2.2:
|
simple-swizzle@^0.2.2:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
||||||
@ -13052,6 +13223,14 @@ update-browserslist-db@^1.1.0:
|
|||||||
escalade "^3.1.2"
|
escalade "^3.1.2"
|
||||||
picocolors "^1.0.1"
|
picocolors "^1.0.1"
|
||||||
|
|
||||||
|
update-browserslist-db@^1.2.0:
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d"
|
||||||
|
integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==
|
||||||
|
dependencies:
|
||||||
|
escalade "^3.2.0"
|
||||||
|
picocolors "^1.1.1"
|
||||||
|
|
||||||
uri-js@^4.2.2:
|
uri-js@^4.2.2:
|
||||||
version "4.4.1"
|
version "4.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||||
@ -13424,7 +13603,12 @@ webpack-sources@^3.2.3:
|
|||||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
|
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
|
||||||
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
|
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
|
||||||
|
|
||||||
webpack-virtual-modules@0.4.3, webpack-virtual-modules@^0.4.2:
|
webpack-virtual-modules@0.6.2:
|
||||||
|
version "0.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8"
|
||||||
|
integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==
|
||||||
|
|
||||||
|
webpack-virtual-modules@^0.4.2:
|
||||||
version "0.4.3"
|
version "0.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.3.tgz#cd597c6d51d5a5ecb473eea1983a58fa8a17ded9"
|
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.3.tgz#cd597c6d51d5a5ecb473eea1983a58fa8a17ded9"
|
||||||
integrity sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==
|
integrity sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user