Compare commits

...
30 Commits
Author SHA1 Message Date
mergify[bot]andAndy Lee f2e8cce29f fix unable to detach PCI & USB device in VM edit page (#247) (#249)
* fix unable to detach PCI & USB device in VM edit page

Signed-off-by: Andy Lee <andy.lee@suse.com>

* refactor based on comment

Signed-off-by: Andy Lee <andy.lee@suse.com>

* using set from shell/utils/object

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 2993ddb82c)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-16 16:13:12 +08:00
mergify[bot]andAndy Lee 31682dd165 bump to 1.5.0-rc5 (#245) (#246)
(cherry picked from commit a5d4604dce)
Signed-off-by: Andy Lee <andy.lee@suse.com>

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-16 14:44:54 +08:00
mergify[bot]andAndy Lee 9fac43d5e5 pass showYaml prop to prevent double generate secret (#243) (#244)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit daa6d6942b)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-15 16:08:09 +08:00
mergify[bot]andAndy Lee cd6ea6e402 Add logic to block import harvester version lower than 1.3.0 (#241) (#242)
* add logic to block import harvester version lower than 1.3.0

Signed-off-by: Andy Lee <andy.lee@suse.com>

* refactor console.error message

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit eb92642b3b)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-10 16:24:22 +08:00
mergify[bot]andAndy Lee 3bfe57dc54 filter golden image volume in hot plug volume modal (#239) (#240)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 78234b9e1e)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-10 13:27:23 +08:00
mergify[bot]andAndy Lee 089573f193 bump to 1.5.0-rc4 (#235) (#238)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 3dc6dda1ca)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-09 14:19:19 +08:00
mergify[bot]andAndy Lee 5d0c4f0c5a hide usb device tab in v1.3.x (#236) (#237)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit fca05d8489)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-09 14:04:30 +08:00
mergify[bot]andAndy Lee 57bb1e8562 Fix undefined error in VM edit as yaml page (#233) (#234)
* fix undefined error whenclick save in  edit as yaml

Signed-off-by: Andy Lee <andy.lee@suse.com>

* fix VM isEqual logic and fix undefined error

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 238c660796)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-07 15:33:36 +08:00
mergify[bot]andAndy Lee 30ff129691 fix secret name is different when edit as yaml (#230) (#232)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 19bea97106)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-07 10:56:49 +08:00
mergify[bot]andJack Yu 9175f16bfc chore: use default imag repo name (#212) (#231)
Signed-off-by: Jack Yu <jack.yu@suse.com>
(cherry picked from commit de4edbbf3b)

Co-authored-by: Jack Yu <jack.yu@suse.com>
2025-04-07 10:41:41 +08:00
mergify[bot]andAndy Lee 7c5e0f93d1 Bump ui-ext to 1.5.0-rc3 (#228) (#229)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 9256391627)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-04-02 16:03:13 +08:00
mergify[bot]andAndy Lee 8a7d3dffbe Fix error banner position in all dialogs (#226) (#227)
* fix error banner position in all dialogs

Signed-off-by: Andy Lee <andy.lee@suse.com>

* update HarvesterImageDownloader.vue

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 25439aee65)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-31 17:02:06 +08:00
b7810c5970 change longhorn v2 access mode to RWX (#223) (#225)
(cherry picked from commit f2fe1f5bd6)

Co-authored-by: Andy Lee <andy.lee@suse.com>
Co-authored-by: Yiya Chen <yiya.chen@suse.com>
2025-03-28 15:16:45 +08:00
mergify[bot]andAndy Lee 72dedd46d1 update to take VM snapshot logic (#222) (#224)
(cherry picked from commit f8d5aa1a21)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-28 15:13:46 +08:00
mergify[bot]andAndy Lee 24f716ab20 use harvester translation key forhost page CPU and memory (#220) (#221)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 38cf667830)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-27 15:05:41 +08:00
mergify[bot]andAndy Lee 38ad0fe1a7 upgrade ui-ext version to 1.5.0-rc2 (#208) (#218)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 18667836c2)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-25 11:44:26 +08:00
mergify[bot]andAndy Lee c84d262099 fix volume won't be dismiss after deleting (#216) (#217)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 2940f25fe0)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-24 15:33:20 +08:00
mergify[bot]andAndy Lee dbb53eae00 fix image.repo to image.repository (#214) (#215)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit a24d01717a)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-21 17:43:13 +08:00
mergify[bot]andAndy Lee 4afacd754a fix the doneOverride path for harvesterhci.io.virtualmachinetemplate (#211) (#213)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 22a032e56c)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-20 17:13:45 +08:00
mergify[bot]andAndy Lee 10d159e2c7 Add volum mode options in create VM volume tab (#209) (#210)
* add volume mode option for non-longhorn volume

Signed-off-by: Andy Lee <andy.lee@suse.com>

* fix default storage class in create VM page

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 9343813ace)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-19 17:44:58 +08:00
mergify[bot]andAndy Lee de755a662a upgrade rancher/shell to 3.0.2-rc6 (#206) (#207)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 2dff7b0a93)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-14 16:50:13 +08:00
mergify[bot]andJack Yu f1200f4508 chore: add building catalog GA (#181) (#204)
* chore: add building catalog GA

Signed-off-by: Jack Yu <jack.yu@suse.com>

* feat: should include prerelease

Signed-off-by: Jack Yu <jack.yu@suse.com>

---------

Signed-off-by: Jack Yu <jack.yu@suse.com>
(cherry picked from commit 1880043a80)

Co-authored-by: Jack Yu <jack.yu@suse.com>
2025-03-14 15:04:39 +08:00
mergify[bot]andAndy Lee 0ca2b0591a Bring status object in harvesterhci.io.upgrade dismiss PUT API (#201) (#202)
* bring status object in PUT dismiss API

Signed-off-by: Andy Lee <andy.lee@suse.com>

* add cleanForSave in harvester model

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit d8bee7f4f5)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-13 14:15:59 +08:00
mergify[bot]andAndy Lee 44f003309c Add volumeMode dropdown for third-party storage (#197) (#200)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 90c923b480)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-12 14:29:40 +08:00
mergify[bot]andAndy Lee 7c1596c965 replace tag format v1.5.0 to harvester-1.5.0 (#190) (#199)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 374b904191)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-12 12:35:01 +08:00
mergify[bot]andAndy Lee a5130986a8 fix percent typo (#198)
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 487f9abc10)

Co-authored-by: Andy Lee <andy.lee@suse.com>
2025-03-11 17:24:23 +08:00
Andy Lee e4ae7cec5e Merge pull request #194 from harvester/mergify/bp/release-harvester-v1.5/pr-191
Fix missing remove button in Infobox (backport #191)
2025-03-11 12:02:41 +08:00
Andy Lee 2c7b59daed Fix infobox style
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 4e831cbc5f)
2025-03-11 03:58:53 +00:00
Andy Lee 224e34315b Merge pull request #193 from harvester/mergify/bp/release-harvester-v1.5/pr-192
remove require dot for non-longhorn v1 (backport #192)
2025-03-11 11:37:06 +08:00
Andy Lee 9f56f9eccc remove require dot for non-longhorn v1
Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit b939df9b7d)
2025-03-11 03:35:42 +00:00
49 changed files with 507 additions and 187 deletions
@@ -0,0 +1,35 @@
name: Build Harvester Catalog Image and Publish on Release
on:
workflow_dispatch:
release:
types: [published]
defaults:
run:
shell: bash
working-directory: ./
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run tests
uses: ./.github/actions/lint
build-and-push-extension-catalog:
needs: lint
uses: ./.github/workflows/build-extension-catalog.yml
permissions:
actions: write
contents: read
packages: write
id-token: write
with:
registry_target: docker.io
registry_user: rancher
secrets: inherit
@@ -0,0 +1,70 @@
name: Build and release Extension Catalog Image to registry
on:
workflow_call:
inputs:
registry_target:
required: true
type: string
registry_user:
required: true
type: string
outputs:
build-extension-catalog-job-status:
value: ${{ jobs.build-extension-catalog.outputs.build-status }}
jobs:
build-and-push-extension-catalog:
name: Build container image
if: github.ref_type == 'tag' || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')
runs-on: ubuntu-latest
permissions:
actions: write
contents: read
packages: write
id-token: write
outputs:
build-status: ${{ job.status }}
steps:
- name: Read Secrets
uses: rancher-eio/read-vault-secrets@main
with:
secrets: |
secret/data/github/repo/${{ github.repository }}/dockerhub/rancher/credentials username | DOCKER_USERNAME ;
secret/data/github/repo/${{ github.repository }}/dockerhub/rancher/credentials password | DOCKER_PASSWORD ;
- name: Checkout repository (normal flow)
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Configure Git
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ env.DOCKER_USERNAME }}
password: ${{ env.DOCKER_PASSWORD }}
- name: Setup Helm
uses: azure/setup-helm@v3
with:
version: v3.8.0
- name: Setup Nodejs with yarn caching
uses: actions/setup-node@v4
with:
node-version: '20'
cache: yarn
- name: Install dependencies
run: yarn
- name: Build and push UI image
run: |
publish="yarn publish-pkgs -cp -r ${{ inputs.registry_target }} -o ${{ inputs.registry_user }}"
$publish
@@ -11,6 +11,24 @@ defaults:
working-directory: ./
jobs:
setup-release-tag:
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.determine_tag.outputs.release_tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Determine release tag
id: determine_tag
run: |
if [[ "${{ github.ref_name }}" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
RELEASE_TAG="harvester-${BASH_REMATCH[1]}"
echo "${RELEASE_TAG}"
echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT
else
echo "Error: invalid tag format." && exit 1
fi
lint:
runs-on: ubuntu-latest
steps:
@@ -22,6 +40,7 @@ jobs:
uses: ./.github/actions/lint
build-extension-charts:
needs:
- setup-release-tag
- lint
uses: rancher/dashboard/.github/workflows/build-extension-charts.yml@master
permissions:
@@ -31,4 +50,4 @@ jobs:
pages: write
with:
target_branch: gh-pages
tagged_release: ${{ github.ref_name }}
tagged_release: '${{ needs.setup-release-tag.outputs.release_tag }}'
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "harvester-ui-extension",
"version": "1.5.0-rc1",
"version": "1.5.0-rc5",
"private": false,
"engines": {
"node": ">=20.0.0"
},
"dependencies": {
"@rancher/shell": "3.0.2-rc.3",
"@rancher/shell": "3.0.2-rc.6",
"cache-loader": "^4.1.0",
"color": "4.2.3",
"ip": "2.0.1",
@@ -301,14 +301,14 @@ export default {
<ProgressBarList
:title="t('harvester.upgradePage.upgradeNode')"
:precent="nodesPercent"
:percent="nodesPercent"
:list="nodesStatus"
/>
<p class="bordered-section"></p>
<ProgressBarList
:title="t('harvester.upgradePage.upgradeSysService')"
:precent="sysServiceTotal"
:percent="sysServiceTotal"
:list="sysServiceUpgradeMessage"
/>
</div>
@@ -162,6 +162,10 @@ export default {
this.configArr.splice(idx, 1);
},
isBackupVolumeSnapshotRequired(driver) {
return driver === LONGHORN_DRIVER;
},
disableEdit(driver) {
return driver === LONGHORN_DRIVER;
},
@@ -170,10 +174,6 @@ export default {
return driver === LONGHORN_DRIVER || this.allowEmptySnapshotClassNameFeatureEnabled;
},
isBackupVolumeSnapshotClassNameSelectable(driver) {
return driver === LONGHORN_DRIVER;
},
add() {
this.configArr.push({
key: '',
@@ -196,6 +196,7 @@ export default {
<InfoBox
v-for="(driver, idx) in configArr"
:key="idx"
class="box"
>
<button
:disabled="disableEdit(driver.key)"
@@ -238,11 +239,10 @@ export default {
<LabeledSelect
v-model:value="driver.value.backupVolumeSnapshotClassName"
:mode="mode"
required
:disabled="isBackupVolumeSnapshotClassNameDisabled(driver.key)"
:options="getVolumeSnapshotOptions(driver.key)"
:required="isBackupVolumeSnapshotRequired(driver.key)"
:label="t('harvester.setting.csiDriverConfig.backupVolumeSnapshotClassName')"
@selectable="isBackupVolumeSnapshotClassNameSelectable(driver.key)"
@keydown.native.enter.prevent="()=>{}"
@update:value="update"
/>
@@ -50,6 +50,7 @@ export const HCI = {
STORAGE_NETWORK: 'storage-network.settings.harvesterhci.io',
ADDON_EXPERIMENTAL: 'addon.harvesterhci.io/experimental',
VOLUME_ERROR: 'longhorn.io/volume-scheduling-error',
VOLUME_FOR_VM: 'harvesterhci.io/volumeForVirtualMachine',
KVM_AMD_CPU: 'cpu-feature.node.kubevirt.io/svm',
KVM_INTEL_CPU: 'cpu-feature.node.kubevirt.io/vmx',
NODE_MANUFACTURER: 'manufacturer',
+5
View File
@@ -7,3 +7,8 @@ export const NETWORK_TYPE = {
L2VLAN: 'L2VlanNetwork',
UNTAGGED: 'UntaggedNetwork'
};
export const VOLUME_MODE = {
BLOCK: 'Block',
FILE_SYSTEM: 'Filesystem'
};
@@ -138,6 +138,8 @@ export default {
<Banner
v-for="(error, i) in errors"
:key="i"
:label="error"
color="error"
/>
</div>
</template>
@@ -166,6 +166,8 @@ export default {
<Banner
v-for="(error, i) in errors"
:key="i"
:label="error"
color="error"
/>
</div>
</template>
+6 -7
View File
@@ -106,6 +106,12 @@ export default {
:label="t('harvester.modal.cloneVM.name')"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
:label="err"
color="error"
/>
</template>
<template #actions>
@@ -125,13 +131,6 @@ export default {
@click="create"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</div>
</template>
</Card>
@@ -57,6 +57,10 @@ export default {
if (!!pvc.metadata?.annotations?.[HCI_ANNOTATIONS.IMAGE_ID]) {
return false;
}
// we won't show golden image volume in the hot plug volume modal
if (pvc.isGoldenImageVolume) {
return false;
}
return !pvc.attachVM;
})
@@ -137,6 +141,12 @@ export default {
class="mt-20"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
:label="err"
color="error"
/>
</template>
<template #actions>
@@ -156,11 +166,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
@@ -103,6 +103,12 @@ export default {
:label="t('generic.name')"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -121,13 +127,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</div>
</template>
</Card>
@@ -120,6 +120,12 @@ export default {
v-model:value="description"
:label="t('harvester.modal.createTemplate.description')"
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -138,11 +144,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
@@ -128,6 +128,12 @@ export default {
<Banner color="warning">
<span>{{ t('harvester.modal.ejectCDROM.warnTip') }}</span>
</Banner>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -147,13 +153,6 @@ export default {
@click="remove"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</div>
</template>
</Card>
@@ -187,6 +187,12 @@ export default {
class="mt-20"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -205,11 +211,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
@@ -122,16 +122,15 @@ export default {
</Banner>
{{ t('harvester.modal.downloadImage.startMessage') }}
<br /><br />
</template>
<template #actions>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
>
{{ err }}
</Banner>
:label="err"
/>
</template>
<template #actions>
<div class="actions">
<div class="buttons">
<button
@@ -161,6 +161,12 @@ export default {
:placeholder="t('harvester.modal.migration.fields.nodeName.placeholder')"
:options="nodeNameList"
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template
@@ -181,12 +187,6 @@ export default {
@click="apply"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
</Card>
</template>
@@ -96,6 +96,12 @@ export default {
:suffix="GIBIBYTE"
class="mb-20"
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -109,12 +115,6 @@ export default {
</button>
<AsyncButton @click="save" />
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</div>
</template>
</Card>
@@ -136,6 +136,12 @@ export default {
:options="backupOption"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -154,11 +160,6 @@ export default {
@click="saveRestore"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
@@ -90,6 +90,12 @@ export default {
v-clean-html="t('harvester.virtualMachine.unplug.title', { name: diskName })"
class="text-default-text"
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -111,13 +117,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</div>
</template>
</Card>
@@ -132,6 +132,12 @@ export default {
:label="t('generic.name')"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -150,11 +156,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
@@ -107,6 +107,12 @@ export default {
:placeholder="t('harvester.harvesterVlanConfigMigrateDialog.targetClusterNetwork.placeholder')"
:options="clusterNetworks"
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -125,11 +131,6 @@ export default {
@click="apply"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
+6 -6
View File
@@ -70,16 +70,16 @@ export default {
v-clean-html="t('harvester.modal.restart.tip')"
class="pl-10 pr-10"
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
<div class="bottom">
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
<div class="buttons">
<button
class="btn role-secondary mr-10"
@@ -145,6 +145,12 @@ export default {
class="mt-20"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -162,10 +168,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
+6 -6
View File
@@ -79,6 +79,12 @@ export default {
:label="t('harvester.modal.snapshot.name')"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -96,12 +102,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</div>
</template>
</Card>
+6 -4
View File
@@ -98,6 +98,12 @@ export default {
:label="t('harvester.modal.volumeClone.name')"
required
/>
<Banner
v-for="(err, i) in errors"
:key="i"
color="error"
:label="err"
/>
</template>
<template #actions>
@@ -115,10 +121,6 @@ export default {
@click="save"
/>
</div>
<Banner
v-for="(err, i) in errors"
:key="i"
/>
</div>
</template>
</Card>
@@ -10,7 +10,7 @@ import { Banner } from '@components/Banner';
import CreateEditView from '@shell/mixins/create-edit-view';
const DEFAULT_VALUE = { image: { repo: 'rancher/harvester-nvidia-driver-toolkit' } };
const DEFAULT_VALUE = { image: { repository: 'rancher/harvester-nvidia-driver-toolkit' } };
export default {
name: 'EditAddonNvidiaDriverToolkit',
@@ -122,7 +122,7 @@ export default {
>
<div class="col span-6">
<LabeledInput
v-model:value="valuesContentJson.image.repo"
v-model:value="valuesContentJson.image.repository"
:mode="mode"
:required="true"
label-key="harvester.addons.nvidiaDriverToolkit.image.repository"
+77 -4
View File
@@ -22,6 +22,7 @@ import { HCI, VOLUME_SNAPSHOT } from '../types';
import { LVM_DRIVER } from '../models/harvester/storage.k8s.io.storageclass';
import { DATA_ENGINE_V2 } from '../models/harvester/persistentvolumeclaim';
import { GIBIBYTE } from '../utils/unit';
import { VOLUME_MODE } from '@pkg/harvester/config/types';
export default {
name: 'HarvesterVolume',
@@ -73,7 +74,8 @@ export default {
data() {
if (this.mode === _CREATE) {
this.value.spec.volumeMode = 'Block';
// default volumeMode to Block
this.value.spec.volumeMode = VOLUME_MODE.BLOCK;
this.value.spec.accessModes = ['ReadWriteMany'];
}
@@ -126,6 +128,10 @@ export default {
return InterfaceOption;
},
volumeModeOptions() {
return Object.values(VOLUME_MODE);
},
imageOption() {
return sortBy(
this.images
@@ -179,6 +185,25 @@ export default {
return this.$store.getters[`${ inStore }/all`](STORAGE_CLASS);
},
isLonghornStorageClass() {
const selectedSC = this.storageClasses.find((sc) => sc.name === this.value?.spec?.storageClassName) || {};
return selectedSC && selectedSC.isLonghorn;
},
showVolumeMode() {
// we won't let user choose volumeMode if source = vmimage
if (!this.value.thirdPartyStorageFeatureEnabled || this.isVMImage || !!this.value?.spec?.storageClassName === false) {
return false;
}
if (this.isLonghornStorageClass) {
return false;
}
return true;
},
storageClassOptions() {
return this.storageClasses.filter((s) => !s.parameters?.backingImage).map((s) => {
const label = s.isDefault ? `${ s.name } (${ this.t('generic.default') })` : s.name;
@@ -237,7 +262,43 @@ export default {
}
},
watch: {
'source'(neu) {
if (neu === 'url') {
this.setBlockVolumeMode();
this.deleteVolumeForVmAnnotation();
}
},
'value.spec.storageClassName'() {
if (this.isLonghornStorageClass) {
this.setBlockVolumeMode();
this.deleteVolumeForVmAnnotation();
}
},
'value.spec.volumeMode'(neu) {
if (neu === VOLUME_MODE.FILE_SYSTEM) {
this.setVolumeForVmAnnotation();
} else if (neu === VOLUME_MODE.BLOCK ) {
this.deleteVolumeForVmAnnotation();
}
}
},
methods: {
setBlockVolumeMode() {
this.value.spec.volumeMode = VOLUME_MODE.BLOCK;
},
setVolumeForVmAnnotation() {
this.value.setAnnotation(HCI_ANNOTATIONS.VOLUME_FOR_VM, 'true');
},
deleteVolumeForVmAnnotation() {
if (this.value?.metadata?.annotations?.[HCI_ANNOTATIONS.VOLUME_FOR_VM]) {
delete this.value.metadata.annotations[HCI_ANNOTATIONS.VOLUME_FOR_VM];
}
},
getAccessMode() {
if (!this.longhornV2LVMSupport) {
return ['ReadWriteMany'];
@@ -246,10 +307,10 @@ export default {
const storageClassName = this.value.spec.storageClassName;
const storageClass = this.storageClasses.find((sc) => sc.name === storageClassName);
let readWriteOnce = this.value.isLvm || this.value.isLonghornV2;
let readWriteOnce = this.value.isLvm || (!this.value.thirdPartyStorageFeatureEnabled && this.value.isLonghornV2);
if (storageClass) {
readWriteOnce = storageClass.provisioner === LVM_DRIVER || storageClass.parameters?.dataEngine === DATA_ENGINE_V2;
readWriteOnce = storageClass.provisioner === LVM_DRIVER || (!this.value.thirdPartyStorageFeatureEnabled && storageClass.parameters?.dataEngine === DATA_ENGINE_V2);
}
return readWriteOnce ? ['ReadWriteOnce'] : ['ReadWriteMany'];
@@ -359,7 +420,7 @@ export default {
/>
<LabeledSelect
v-if="source === 'blank'"
v-if="isBlank"
v-model:value="value.spec.storageClassName"
:options="storageClassOptions"
:label="t('harvester.storage.storageClass.label')"
@@ -369,6 +430,18 @@ export default {
@update:value="update"
/>
<LabeledSelect
v-if="showVolumeMode"
v-model:value="value.spec.volumeMode"
:label="t('harvester.volume.volumeMode')"
:options="volumeModeOptions"
required
:disabled="!isCreate"
:mode="mode"
class="mb-20"
@update:value="update"
/>
<UnitInput
v-model:value="storage"
:label="t('harvester.volume.size')"
@@ -97,7 +97,7 @@ export default {
});
const devices = [
...this.otherDevices(this.value.domain.devices.hostDevices || []),
...this.otherDevices(this.value?.domain?.devices?.hostDevices || []),
...formatted,
];
@@ -121,7 +121,9 @@ export default {
return inUse;
}
vm.hostDevices.forEach((device) => {
const hostDevices = vm?.hostDevices || [];
hostDevices.forEach((device) => {
inUse[device.name] = { usedBy: [vm.metadata.name] };
});
@@ -80,7 +80,7 @@ export default {
});
const devices = [
...this.otherDevices(this.value.domain.devices.hostDevices || []),
...this.otherDevices(this.value?.domain?.devices?.hostDevices || []),
...formatted,
];
@@ -121,7 +121,9 @@ export default {
return inUse;
}
vm.hostDevices.forEach((device) => {
const hostDevices = vm?.hostDevices || [];
hostDevices.forEach((device) => {
inUse[device.name] = { usedBy: [vm.metadata.name] };
});
@@ -7,8 +7,7 @@ import UnitInput from '@shell/components/form/UnitInput';
import { LabeledInput } from '@components/Form/LabeledInput';
import LabeledSelect from '@shell/components/form/LabeledSelect';
import ModalWithCard from '@shell/components/ModalWithCard';
import { PVC } from '@shell/config/types';
import { PVC, STORAGE_CLASS } from '@shell/config/types';
import { clone } from '@shell/utils/object';
import { ucFirst, randomStr } from '@shell/utils/string';
import { removeObject } from '@shell/utils/array';
@@ -17,6 +16,7 @@ import { PLUGIN_DEVELOPER, DEV } from '@shell/store/prefs';
import { SOURCE_TYPE } from '../../../config/harvester-map';
import { PRODUCT_NAME as HARVESTER_PRODUCT } from '../../../config/harvester';
import { HCI } from '../../../types';
import { VOLUME_MODE } from '@pkg/harvester/config/types';
export default {
emits: ['update:value'],
@@ -62,7 +62,7 @@ export default {
customVolumeMode: {
type: String,
default: 'Block'
default: VOLUME_MODE.Block
},
customAccessMode: {
@@ -116,6 +116,12 @@ export default {
return this.mode === _CREATE;
},
defaultStorageClass() {
const defaultStorage = this.$store.getters['harvester/all'](STORAGE_CLASS).find((sc) => sc.isDefault);
return defaultStorage;
},
showVolumeTip() {
const imageName = this.getImageDisplayName(this.rows[0]?.image);
@@ -111,7 +111,7 @@ export default {
return false;
}
if (pvc.metadata?.annotations?.[HCI_ANNOTATIONS.GOLDEN_IMAGE] === 'true') {
if (pvc.isGoldenImageVolume) {
return false;
}
@@ -13,6 +13,7 @@ import { ucFirst } from '@shell/utils/string';
import { LVM_DRIVER } from '../../../../models/harvester/storage.k8s.io.storageclass';
import { DATA_ENGINE_V2 } from '../../../../models/harvester/persistentvolumeclaim';
import { GIBIBYTE } from '../../../../utils/unit';
import { VOLUME_MODE } from '@pkg/harvester/config/types';
export default {
name: 'HarvesterEditVolume',
@@ -71,6 +72,10 @@ export default {
return this.$store.getters['harvester-common/getFeatureEnabled']('longhornV2LVMSupport');
},
thirdPartyStorageClassEnabled() {
return this.$store.getters['harvester-common/getFeatureEnabled']('thirdPartyStorage');
},
encryptionValue() {
return ucFirst(String(this.value.isEncrypted));
},
@@ -91,6 +96,18 @@ export default {
return allPVCs.find((P) => P.id === `${ this.namespace }/${ this.value.volumeName }`);
},
showVolumeMode() {
if (!this.thirdPartyStorageClassEnabled || !!this.value?.storageClassName === false) {
return false;
}
if (this.isLonghornStorageClass) {
return false;
}
return true;
},
isDisabled() {
return !this.value.newCreateId && this.isEdit && this.isVirtualType;
},
@@ -112,7 +129,17 @@ export default {
isLonghornV2() {
return this.value.pvc?.isLonghornV2 || this.value.pvc?.storageClass?.isLonghornV2;
}
},
isLonghornStorageClass() {
const selectedSC = this.storageClasses.find((sc) => sc.name === this.value?.storageClassName) || {};
return selectedSC && selectedSC.isLonghorn;
},
volumeModeOptions() {
return Object.values(VOLUME_MODE);
},
},
watch: {
@@ -120,6 +147,8 @@ export default {
immediate: true,
handler(neu) {
this.value.accessMode = this.getAccessMode(neu);
this.value.volumeMode = this.getVolumeMode(neu, this.value.volumeMode);
this.update();
}
},
@@ -151,6 +180,20 @@ export default {
},
methods: {
getVolumeMode(storageClassName, originalVolumeMode) {
if (!this.thirdPartyStorageClassEnabled) {
return VOLUME_MODE.BLOCK;
}
const storageClass = this.storageClasses.find((sc) => sc.name === storageClassName);
// longhorn v1, v2 use block volumeMode
if (storageClass && storageClass.isLonghorn) {
return VOLUME_MODE.BLOCK;
}
return originalVolumeMode;
},
getAccessMode(storageClassName) {
if (!this.longhornV2LVMSupport) {
return 'ReadWriteMany';
@@ -158,10 +201,10 @@ export default {
const storageClass = this.storageClasses.find((sc) => sc.name === storageClassName);
let readWriteOnce = this.value.pvc?.isLvm || this.value.pvc?.isLonghornV2;
let readWriteOnce = this.value.pvc?.isLvm || (!this.thirdPartyStorageClassEnabled && this.value.pvc?.isLonghornV2);
if (storageClass) {
readWriteOnce = storageClass.provisioner === LVM_DRIVER || storageClass.parameters?.dataEngine === DATA_ENGINE_V2;
readWriteOnce = storageClass.provisioner === LVM_DRIVER || (!this.thirdPartyStorageClassEnabled && storageClass.parameters?.dataEngine === DATA_ENGINE_V2);
}
return readWriteOnce ? 'ReadWriteOnce' : 'ReadWriteMany';
@@ -286,6 +329,29 @@ export default {
/>
</InputOrDisplay>
</div>
<div
v-if="showVolumeMode"
data-testid="input-volume-mode"
class="col span-6"
>
<InputOrDisplay
:name="t('harvester.volume.volumeMode')"
:value="value.volumeMode"
:mode="mode"
>
<LabeledSelect
v-model:value="value.volumeMode"
:label="t('harvester.volume.volumeMode')"
:mode="mode"
:options="volumeModeOptions"
:disabled="isEdit"
required
@update:value="update"
/>
</InputOrDisplay>
</div>
</div>
<div class="row mb-20">
<div
v-if="value.volumeEncryptionFeatureEnabled && isView"
class="col span-6"
@@ -295,11 +361,9 @@ export default {
:value="encryptionValue"
/>
</div>
</div>
<div class="row mb-20">
<div
v-if="value.volumeBackups && isView"
class="col span-3"
class="col span-6"
>
<LabelValue
:name="t('harvester.virtualMachine.volume.readyToUse')"
@@ -2,6 +2,7 @@
import { isEqual } from 'lodash';
import { mapGetters } from 'vuex';
import Tabbed from '@shell/components/Tabbed';
import { clone, set } from '@shell/utils/object';
import Tab from '@shell/components/Tabbed/Tab';
import { Checkbox } from '@components/Form/Checkbox';
import CruResource from '@shell/components/CruResource';
@@ -15,9 +16,7 @@ import PodAffinity from '@shell/components/form/PodAffinity';
import VGpuDevices from './VirtualMachineVGpuDevices/index';
import UsbDevices from './VirtualMachineUSBDevices/index';
import KeyValue from '@shell/components/form/KeyValue';
import { clear } from '@shell/utils/array';
import { clone } from '@shell/utils/object';
import { saferDump } from '@shell/utils/create-yaml';
import { exceptionToErrorsArray } from '@shell/utils/error';
import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations';
@@ -212,7 +211,10 @@ export default {
}
return false;
}
},
usbPassthroughEnabled() {
return this.$store.getters['harvester-common/getFeatureEnabled']('usbPassthrough');
},
},
watch: {
@@ -409,13 +411,26 @@ export default {
}
const cloneDeepNewVM = clone(this.value);
// new VM
delete cloneDeepNewVM?.metadata;
delete cloneDeepNewVM?.__clone;
// old VM
delete this.cloneVM?.metadata;
delete this.cloneVM?.__clone;
// add empty hostDevices to old VM as CRD does not have it.
const devicesObj = this.cloneVM?.spec?.template?.spec?.domain?.devices;
if (devicesObj && devicesObj.hostDevices === undefined) {
set(devicesObj, 'hostDevices', []);
}
const oldVM = JSON.parse(JSON.stringify(this.cloneVM));
const newVM = JSON.parse(JSON.stringify(cloneDeepNewVM));
// we won't show restart dialog in yaml page as we don't have a way to detect change in yaml editor.
// only check VM is changed in form page.
if (isEqual(oldVM, newVM)) {
return;
}
@@ -424,7 +439,11 @@ export default {
this.isOpen = true;
this.$nextTick(() => {
this.$refs.restartDialog.resolve = resolve;
if (this?.$refs?.restartDialog) {
this.$refs.restartDialog.resolve = resolve;
} else {
return resolve();
}
});
});
},
@@ -474,6 +493,7 @@ export default {
},
generateYaml() {
this.showYaml = this?.$refs?.vmCruResource?.showYaml || false;
this.parseVM();
const out = saferDump(this.value);
@@ -487,6 +507,7 @@ export default {
<CruResource
v-if="spec"
id="vm"
ref="vmCruResource"
:done-route="doneRoute"
:resource="value"
:cancel-event="true"
@@ -674,7 +695,7 @@ export default {
</Tab>
<Tab
v-if="enabledPCI"
v-if="enabledPCI && usbPassthroughEnabled"
:label="t('harvester.tab.usbDevices')"
name="usbDevices"
:weight="-7"
+1
View File
@@ -791,6 +791,7 @@ harvester:
datasource: Data Source
details: Details
size: Size
volumeMode: Volume Mode
source: Source
kind: Kind
sourceOptions:
+2 -2
View File
@@ -101,14 +101,14 @@ export default {
const metricCol = [
{
name: 'cpu',
labelKey: 'node.detail.glance.consumptionGauge.cpu',
labelKey: 'harvester.dashboard.hardwareResourceGauge.cpu',
value: 'id',
formatter: 'HarvesterCPUUsed',
formatterOpts: { showUsed: true },
},
{
name: 'memory',
labelKey: 'node.detail.glance.consumptionGauge.memory',
labelKey: 'harvester.dashboard.hardwareResourceGauge.memory',
value: 'id',
formatter: 'HarvesterMemoryUsed',
formatterOpts: { showUsed: true },
@@ -6,10 +6,8 @@ import {
} from '@shell/config/types';
import { STATE, AGE, NAME, NAMESPACE } from '@shell/config/table-headers';
import HarvesterVolumeState from '../formatters/HarvesterVolumeState';
import { allSettled } from '../utils/promise';
import { HCI, VOLUME_SNAPSHOT } from '../types';
import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations';
const schema = {
id: HCI.VOLUME,
@@ -59,10 +57,7 @@ export default {
if (!pvcSchema?.collectionMethods.find((x) => x.toLowerCase() === 'post')) {
this.$store.dispatch('type-map/configureType', { match: HCI.VOLUME, isCreatable: false });
}
// we only show the non golden image PVCs in the list
const pvcs = hash.pvcs.filter((pvc) => pvc?.metadata?.annotations?.[HCI_ANNOTATIONS.GOLDEN_IMAGE] !== 'true');
this.rows = pvcs;
this.rows = hash.pvcs;
},
data() {
@@ -73,7 +68,10 @@ export default {
schema() {
return schema;
},
filterRows() {
// we only show the non golden image PVCs in the list
return this.rows.filter((pvc) => !pvc?.isGoldenImageVolume);
},
headers() {
return [
STATE,
@@ -150,7 +148,7 @@ export default {
:groupable="true"
default-sort-by="age"
:namespaced="true"
:rows="rows"
:rows="filterRows"
:schema="schema"
key-field="_key"
>
+8 -12
View File
@@ -26,6 +26,7 @@ import { HCI } from '../../types';
import { parseVolumeClaimTemplates } from '../../utils/vm';
import impl, { QGA_JSON, USB_TABLET } from './impl';
import { GIBIBYTE } from '../../utils/unit';
import { VOLUME_MODE } from '@pkg/harvester/config/types';
const LONGHORN_V2_DATA_ENGINE = 'longhorn-system/v2-data-engine';
@@ -139,6 +140,7 @@ export default {
return {
OS,
isClone,
showYaml: false,
spec: null,
osType: 'linux',
sshKey: [],
@@ -244,12 +246,6 @@ export default {
});
},
defaultStorageClass() {
const defaultStorage = this.$store.getters[`${ this.inStore }/all`](STORAGE_CLASS).find( (O) => O.isDefault);
return defaultStorage;
},
storageClassSetting() {
try {
const storageClassValue = this.$store.getters[`${ this.inStore }/all`](HCI.SETTING).find( (O) => O.id === HCI_SETTING.DEFAULT_STORAGE_CLASS)?.value;
@@ -261,7 +257,7 @@ export default {
},
customVolumeMode() {
return this.storageClassSetting.volumeMode || 'Block';
return this.storageClassSetting.volumeMode || VOLUME_MODE.BLOCK;
},
customAccessMode() {
@@ -274,7 +270,7 @@ export default {
needNewSecret() {
// When creating a template it is always necessary to create a new secret.
return this.resourceType === HCI.VM_VERSION || this.isCreate;
return this.showYaml ? false : this.resourceType === HCI.VM_VERSION || this.isCreate;
},
defaultTerminationSetting() {
@@ -463,7 +459,7 @@ export default {
type,
storageClassName: '',
image: this.imageId,
volumeMode: 'Block',
volumeMode: VOLUME_MODE.BLOCK,
isEncrypted,
volumeBackups,
});
@@ -522,7 +518,7 @@ export default {
accessMode = pvcResource?.spec?.accessModes?.[0] || 'ReadWriteMany';
size = pvcResource?.spec?.resources?.requests?.storage || '10Gi';
storageClassName = pvcResource?.spec?.storageClassName;
volumeMode = pvcResource?.spec?.volumeMode || 'Block';
volumeMode = pvcResource?.spec?.volumeMode || VOLUME_MODE.BLOCK;
volumeName = pvcResource?.metadata?.name || '';
}
@@ -674,7 +670,7 @@ export default {
}
});
if (!this.secretName || this.needNewSecret) {
if (this.needNewSecret || !this.secretName) {
this.secretName = this.generateSecretName(this.secretNamePrefix);
}
@@ -876,7 +872,7 @@ export default {
}
}
if (out.length === 0 && !!this.spec.template.spec.accessCredentials) {
if (out.length === 0 && !!this.spec.template.spec.accessCredentials === false) {
delete this.spec.template.spec.accessCredentials;
} else {
this.spec.template.spec.accessCredentials = out;
+4
View File
@@ -66,4 +66,8 @@ export default class HarvesterResource extends SteveModel {
return this.hasLink('self') && this.$rootGetters['prefs/get'](DEV);
}
}
cleanForSave(data, _forNew) {
return data;
}
}
@@ -344,6 +344,10 @@ export default class HciPv extends HarvesterResource {
return this.dataEngine === DATA_ENGINE_V2;
}
get isGoldenImageVolume() {
return this?.metadata?.annotations?.[HCI_ANNOTATIONS.GOLDEN_IMAGE] === 'true';
}
get thirdPartyStorageFeatureEnabled() {
return this.$rootGetters['harvester-common/getFeatureEnabled']('thirdPartyStorage');
}
@@ -62,6 +62,10 @@ export default class HciStorageClass extends StorageClass {
return this.parameters?.encrypted === 'true';
}
get isLonghorn() {
return this.provisioner === LONGHORN_DRIVER;
}
get isLonghornV1() {
return this.provisioner === LONGHORN_DRIVER && this.longhornVersion === DATA_ENGINE_V1;
}
@@ -61,6 +61,10 @@ export default class HciUpgrade extends HarvesterResource {
return this?.status?.imageID;
}
cleanForSave(data, _forNew) {
return data;
}
get upgradeMessage() {
const upgradeMessage = [];
const nodeStatuses = this?.status?.nodeStatuses || {};
@@ -2,6 +2,7 @@ import { MODE, _CREATE } from '@shell/config/query-params';
import { HCI } from '../types';
import { PRODUCT_NAME as HARVESTER_PRODUCT } from '../config/harvester';
import HarvesterResource from './harvester';
import { clone } from '@shell/utils/object';
export default class HciVmTemplate extends HarvesterResource {
get availableActions() {
@@ -71,4 +72,12 @@ export default class HciVmTemplate extends HarvesterResource {
get defaultVersion() {
return this.status?.defaultVersion;
}
get doneOverride() {
const detailLocation = clone(this.listLocation);
detailLocation.params.resource = HCI.VM_VERSION;
return detailLocation;
}
}
@@ -158,7 +158,7 @@ export default class VirtVm extends HarvesterResource {
},
{
action: 'takeVMSnapshot',
enabled: !!this.actions?.backup && !this.longhornV2Volumes.length,
enabled: (!!this.actions?.snapshot || !!this.action?.backup) && !this.longhornV2Volumes.length,
icon: 'icon icon-snapshot',
label: this.t('harvester.action.vmSnapshot')
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "harvester",
"description": "Rancher UI Extension for Harvester",
"version": "1.5.0-rc1",
"version": "1.5.0-rc5",
"private": false,
"rancher": {
"annotations": {
@@ -16,14 +16,12 @@ export default {
return [];
}
},
names: {
type: Array,
default: () => {
return [];
}
},
type: {
type: String,
required: true
@@ -69,12 +67,6 @@ export default {
return out;
},
plusMore() {
const remaining = this.toRemove.length - this.names.length;
return this.t('promptRemove.andOthers', { count: remaining });
},
},
watch: {
@@ -143,7 +135,7 @@ export default {
<div>
<div class="mt-10">
{{ t('promptRemove.attemptingToRemove', {type}) }}
<span v-clean-html="resourceNames(names, plusMore, t)"></span>
<span v-clean-html="resourceNames(names, t)"></span>
<div class="mt-10">
{{ t('harvester.virtualMachine.promptRemove.title') }}
+10
View File
@@ -35,7 +35,17 @@ function latestMinorVersion(v) {
}
export const featureEnabled = (featureKey, serverVersion) => {
const minSupportedVersion = '1.3.0';
const version = getVersion(serverVersion);
if (semver.lt(version.replace('v', ''), minSupportedVersion)) {
// eslint-disable-next-line no-console
console.error(`Harvester UI extension only supports Harvester cluster version >= ${ minSupportedVersion }. Current version: ${ version }`);
return false;
}
let releasedFeatures = RELEASE_FEATURES[version];
if (!releasedFeatures) {
+9 -22
View File
@@ -3200,10 +3200,10 @@
resolved "https://registry.yarnpkg.com/@rancher/icons/-/icons-2.0.29.tgz#6546d69768c706bebd66bfa73b36aef3d105987a"
integrity sha512-qBBqfazS9y5VjV7fJDPNXmxd9AP/2uiE05mKFWP41kpbO+tEb62RnUBXCm14XLeScDZQcOuiAKVHMmvCFzF0BA==
"@rancher/shell@3.0.2-rc.3":
version "3.0.2-rc.3"
resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-3.0.2-rc.3.tgz#745d4970425ba0bddf1a8003ff7f82d408566da8"
integrity sha512-K5jCaNfyltjCSTQUgzFFntmO5HT1Uu+vM1aJsMCjiwiyrNPBsf0Z3ic9Is6HSvOs9DB+W5j7jvHwouuq0sxUlw==
"@rancher/shell@3.0.2-rc.6":
version "3.0.2-rc.6"
resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-3.0.2-rc.6.tgz#bde65a3da391c4aa0352e2adf8180900a2575000"
integrity sha512-UpNCv0iZH16nlo+x/4xVisIX20v1JrQC47GUUtXcGDw9pde6HnnBPxpN0cF32r+Kg7F0QRp4Yvjoljmpp1HS7g==
dependencies:
"@aws-sdk/client-ec2" "3.658.1"
"@aws-sdk/client-eks" "3.1.0"
@@ -3258,7 +3258,7 @@
entities "4.5.0"
eslint "7.32.0"
eslint-config-standard "16.0.3"
eslint-import-resolver-node "0.3.4"
eslint-import-resolver-node "0.3.9"
eslint-module-utils "2.6.1"
eslint-plugin-cypress "2.12.1"
eslint-plugin-import "2.31.0"
@@ -3279,7 +3279,7 @@
jest-serializer-vue "2.0.2"
jexl "2.3.0"
jquery "3.5.1"
js-cookie "2.2.1"
js-cookie "3.0.5"
js-yaml "4.1.0"
js-yaml-loader "1.2.2"
jsdiff "1.1.1"
@@ -6999,7 +6999,7 @@ debounce@^1.2.1:
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
debug@2.6.9, debug@^2.6.9:
debug@2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -7672,15 +7672,7 @@ eslint-config-standard@16.0.3:
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz#6c8761e544e96c531ff92642eeb87842b8488516"
integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==
eslint-import-resolver-node@0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
dependencies:
debug "^2.6.9"
resolve "^1.13.1"
eslint-import-resolver-node@^0.3.9:
eslint-import-resolver-node@0.3.9, eslint-import-resolver-node@^0.3.9:
version "0.3.9"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac"
integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==
@@ -10275,12 +10267,7 @@ js-beautify@^1.14.9, js-beautify@^1.6.12:
js-cookie "^3.0.5"
nopt "^7.2.0"
js-cookie@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
js-cookie@^3.0.5:
js-cookie@3.0.5, js-cookie@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==