mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-10-01 11:46:06 +08:00
Compare commits
70
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d13ea96ed1 | ||
|
|
cd43e61163 | ||
|
|
ca83f9e685 | ||
|
|
cdfdd44346 | ||
|
|
7fe4154ad3 | ||
|
|
fb738dca78 | ||
|
|
4ef7e14033 | ||
|
|
e277e32629 | ||
|
|
692b97e2a7 | ||
|
|
6cfc93280f | ||
|
|
ab4d43cc27 | ||
|
|
7fcf2bbd84 | ||
|
|
ff442b2d2e | ||
|
|
314b75e790 | ||
|
|
71379c563d | ||
|
|
97d09d0f6c | ||
|
|
54c0011fb5 | ||
|
|
0e90637815 | ||
|
|
21bd6405cf | ||
|
|
b8b4ee4c41 | ||
|
|
021d6f673f | ||
|
|
a849671034 | ||
|
|
b98f878c5d | ||
|
|
78482285b3 | ||
|
|
4656976b91 | ||
|
|
aeb3588b83 | ||
|
|
d14b0cb95c | ||
|
|
2f0884d7bd | ||
|
|
037ce6132b | ||
|
|
47b54b4f06 | ||
|
|
9dd8ae479a | ||
|
|
5682bf4c3a | ||
|
|
960df31667 | ||
|
|
63451e7d2b | ||
|
|
55aaa8440d | ||
|
|
da4121da69 | ||
|
|
30e49a6f2c | ||
|
|
2255bd4f69 | ||
|
|
7e5ee04637 | ||
|
|
8863de8874 | ||
|
|
73952a6b4e | ||
|
|
0496fae623 | ||
|
|
d5cd97aafd | ||
|
|
31c6a794be | ||
|
|
9d9383ba90 | ||
|
|
1e02dbffe3 | ||
|
|
b0609020cc | ||
|
|
feca476e36 | ||
|
|
e6e36e94f1 | ||
|
|
54d48ce396 | ||
|
|
404395c7d9 | ||
|
|
dc2437db99 | ||
|
|
e8c8a54b9f | ||
|
|
f3e4a8afe8 | ||
|
|
e73c62739f | ||
|
|
696af4e04f | ||
|
|
009f384a73 | ||
|
|
37766454bd | ||
|
|
7943913ef7 | ||
|
|
56a0fefd40 | ||
|
|
ff1d5925a8 | ||
|
|
63b5b980b7 | ||
|
|
1f7fd1246f | ||
|
|
34a25e9fc8 | ||
|
|
fb8d81d953 | ||
|
|
ba810a52b2 | ||
|
|
3f4f30ba0b | ||
|
|
b428aaecf8 | ||
|
|
6b07a03451 | ||
|
|
2c756582e3 |
@@ -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
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
name: Build Harvester Dashboard and Upload
|
||||
name: Build Harvester Dashboard and Publish
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
@@ -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
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Build and Release Extension Charts
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
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-extension-charts:
|
||||
needs:
|
||||
- lint
|
||||
uses: rancher/dashboard/.github/workflows/build-extension-charts.yml@master
|
||||
permissions:
|
||||
actions: write
|
||||
contents: write
|
||||
deployments: write
|
||||
pages: write
|
||||
with:
|
||||
target_branch: gh-pages
|
||||
tagged_release: ${{ github.ref_name }}
|
||||
@@ -0,0 +1,136 @@
|
||||
name: Build and Release Extension Charts on PR Merge
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'release-harvester-v*'
|
||||
|
||||
jobs:
|
||||
setup-target-branch:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
target_branch: ${{ steps.get-version.outputs.target_branch }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Determine target branch
|
||||
id: get-version
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" =~ ^release-harvester-v([0-9]+\.[0-9]+)$ ]]; then
|
||||
TARGET_BRANCH="v${BASH_REMATCH[1]}-head"
|
||||
echo "target_branch=${TARGET_BRANCH}" >> $GITHUB_ENV
|
||||
echo "target_branch=${TARGET_BRANCH}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Error: invalid branch format." && exit 1
|
||||
fi
|
||||
|
||||
- name: Ensure target branch exists
|
||||
run: |
|
||||
git fetch --all
|
||||
if ! git ls-remote --exit-code --heads origin "${{ env.target_branch }}"; then
|
||||
git checkout gh-pages
|
||||
git checkout -b "${{ env.target_branch }}"
|
||||
git push origin "${{ env.target_branch }}"
|
||||
fi
|
||||
|
||||
extract-version:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.get_version.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract version from package.json
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=$(jq -r '.version' pkg/harvester/package.json)
|
||||
echo "VERSION=${VERSION}" >> $GITHUB_ENV
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
build-extension-charts:
|
||||
needs:
|
||||
- setup-target-branch
|
||||
- extract-version
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
corepack enable
|
||||
yarn install --frozen-lockfile
|
||||
|
||||
- name: Setup Helm
|
||||
uses: azure/setup-helm@v3
|
||||
with:
|
||||
version: v3.8.0
|
||||
|
||||
- name: Build Helm charts
|
||||
run: |
|
||||
yarn publish-pkgs -s ${{ github.repository }} -b ${{ needs.setup-target-branch.outputs.target_branch }} -t harvester-${{ needs.extract-version.outputs.version }}
|
||||
|
||||
- name: Upload charts artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: charts
|
||||
path: tmp
|
||||
|
||||
release:
|
||||
needs:
|
||||
- setup-target-branch
|
||||
- extract-version
|
||||
- build-extension-charts
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout release branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: '${{ github.ref_name }}'
|
||||
|
||||
- name: Get last commit hash
|
||||
id: last_commit
|
||||
run: |
|
||||
LAST_COMMIT=$(git rev-parse HEAD)
|
||||
echo "LAST_COMMIT=${LAST_COMMIT}" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout target branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: '${{ needs.setup-target-branch.outputs.target_branch }}'
|
||||
|
||||
- name: Remove old artifacts
|
||||
run: |
|
||||
rm -rf extensions/harvester/${{ needs.extract-version.outputs.version }}
|
||||
rm -rf charts/harvester/${{ needs.extract-version.outputs.version }}
|
||||
rm -f assets/harvester/harvester-${{ needs.extract-version.outputs.version }}.tgz
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: charts
|
||||
|
||||
- name: Commit and push artifacts
|
||||
run: |
|
||||
git add ./{assets,charts,extensions,index.yaml}
|
||||
git commit -m "CI Build Artifacts (commit: ${{ env.LAST_COMMIT }}, version: ${{ needs.extract-version.outputs.version }})"
|
||||
git push origin ${{ needs.setup-target-branch.outputs.target_branch }}
|
||||
|
||||
- name: Run Helm chart releaser
|
||||
uses: helm/chart-releaser-action@v1.7.0
|
||||
with:
|
||||
charts_dir: ./charts
|
||||
env:
|
||||
CR_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
CR_SKIP_EXISTING: true
|
||||
@@ -0,0 +1,53 @@
|
||||
name: Build and Release Extension Charts on Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
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.event.release.tag_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:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run tests
|
||||
uses: ./.github/actions/lint
|
||||
build-extension-charts:
|
||||
needs:
|
||||
- setup-release-tag
|
||||
- lint
|
||||
uses: rancher/dashboard/.github/workflows/build-extension-charts.yml@master
|
||||
permissions:
|
||||
actions: write
|
||||
contents: write
|
||||
deployments: write
|
||||
pages: write
|
||||
with:
|
||||
target_branch: gh-pages
|
||||
tagged_release: '${{ needs.setup-release-tag.outputs.release_tag }}'
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
name: Build Dashboard (Branch)
|
||||
name: Build Standalone on PR Merge
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -11,16 +11,16 @@ on:
|
||||
- main
|
||||
- 'release-harvester-v*'
|
||||
- '*-dev'
|
||||
types:
|
||||
types:
|
||||
- merged
|
||||
|
||||
jobs:
|
||||
build-validation:
|
||||
name: Build Test
|
||||
uses: ./.github/workflows/test.yaml
|
||||
uses: ./.github/workflows/run-lint.yaml
|
||||
build:
|
||||
name: Build and Upload Package
|
||||
uses: ./.github/workflows/build-and-upload.yaml
|
||||
uses: ./.github/workflows/build-and-publish-standalone.yaml
|
||||
needs:
|
||||
- build-validation
|
||||
permissions:
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
name: Build Dashboard (Release)
|
||||
name: Build Standalone on Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
@@ -7,10 +7,10 @@ on:
|
||||
jobs:
|
||||
build-validation:
|
||||
name: Build Test
|
||||
uses: ./.github/workflows/test.yaml
|
||||
uses: ./.github/workflows/run-lint.yaml
|
||||
build:
|
||||
name: Build and Upload Package
|
||||
uses: ./.github/workflows/build-and-upload.yaml
|
||||
uses: ./.github/workflows/build-and-publish-standalone.yaml
|
||||
needs:
|
||||
- build-validation
|
||||
permissions:
|
||||
+13
-12
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "harvester-ui-extension",
|
||||
"version": "0.1.0",
|
||||
"version": "1.0.6",
|
||||
"private": false,
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@@ -12,24 +12,25 @@
|
||||
"ip": "2.0.1",
|
||||
"node-polyfill-webpack-plugin": "^3.0.0",
|
||||
"vue-draggable-next": "^2.2.1",
|
||||
"yaml": "^2.5.1"
|
||||
"yaml": "^2.5.1",
|
||||
"@babel/plugin-transform-class-static-block": "7.28.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "~20.10.0",
|
||||
"cronstrue": "2.50.0",
|
||||
"@types/node": "~20.19.0",
|
||||
"cronstrue": "2.59.0",
|
||||
"d3-color": "3.1.0",
|
||||
"ejs": "3.1.9",
|
||||
"follow-redirects": "1.15.2",
|
||||
"ejs": "3.1.10",
|
||||
"follow-redirects": "1.15.11",
|
||||
"glob": "7.2.3",
|
||||
"glob-parent": "6.0.2",
|
||||
"json5": "2.2.3",
|
||||
"@types/lodash": "4.17.5",
|
||||
"@types/lodash": "4.17.21",
|
||||
"merge": "2.1.1",
|
||||
"node-forge": "1.3.1",
|
||||
"node-forge": "1.3.3",
|
||||
"nth-check": "2.1.1",
|
||||
"qs": "6.11.1",
|
||||
"roarr": "7.0.4",
|
||||
"semver": "7.5.4",
|
||||
"qs": "6.14.1",
|
||||
"roarr": "7.21.2",
|
||||
"semver": "7.7.3",
|
||||
"@vue/cli-service/html-webpack-plugin": "^5.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -46,4 +47,4 @@
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^7.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,9 @@
|
||||
module.exports = require('@rancher/shell/pkg/babel.config');
|
||||
const baseConfig = require('@rancher/shell/pkg/babel.config');
|
||||
|
||||
module.exports = {
|
||||
...baseConfig,
|
||||
plugins: [
|
||||
...(baseConfig.plugins || []),
|
||||
'@babel/plugin-transform-class-static-block'
|
||||
]
|
||||
};
|
||||
|
||||
@@ -190,6 +190,7 @@ export default {
|
||||
v-clean-tooltip="{
|
||||
placement: 'bottom-left',
|
||||
}"
|
||||
popper-class="upgrade-header-dropdown"
|
||||
class="hand"
|
||||
>
|
||||
<slot name="button-content">
|
||||
@@ -272,7 +273,7 @@ export default {
|
||||
|
||||
<p
|
||||
v-if="overallMessage"
|
||||
class="text-warning mb-20"
|
||||
class="text-error mb-20"
|
||||
>
|
||||
{{ overallMessage }}
|
||||
</p>
|
||||
@@ -300,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>
|
||||
@@ -338,6 +339,12 @@ export default {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.upgrade-header-dropdown .v-popper__arrow-container {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
a {
|
||||
float: right;
|
||||
|
||||
@@ -12,7 +12,7 @@ export default {
|
||||
default: ''
|
||||
},
|
||||
|
||||
precent: {
|
||||
percent: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
@@ -39,16 +39,18 @@ export default {
|
||||
|
||||
<template>
|
||||
<div class="bar-list">
|
||||
<h4>{{ title }} <span class="float-r text-info">{{ precent }}%</span></h4>
|
||||
<h4>{{ title }} <span class="float-r text-info">{{ percent }}%</span></h4>
|
||||
<div>
|
||||
<div>
|
||||
<Collapse v-model:open="open">
|
||||
<template #title>
|
||||
<div class="total-bar">
|
||||
<span class="bar"><PercentageBar
|
||||
:model-value="precent"
|
||||
preferred-direction="MORE"
|
||||
/></span>
|
||||
<span class="bar">
|
||||
<PercentageBar
|
||||
:model-value="percent"
|
||||
preferred-direction="MORE"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="on-off"
|
||||
@click="handleSwitch"
|
||||
@@ -56,28 +58,26 @@ export default {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template>
|
||||
<div class="custom-content">
|
||||
<div
|
||||
v-for="(item, i) in list"
|
||||
:key="i"
|
||||
>
|
||||
<p>
|
||||
{{ item.name }} <span
|
||||
class="status"
|
||||
:class="{ [item.state]: true }"
|
||||
>{{ item.state }}</span>
|
||||
</p>
|
||||
<PercentageBar
|
||||
:model-value="item.percent"
|
||||
preferred-direction="MORE"
|
||||
/>
|
||||
<p class="warning">
|
||||
{{ item.message }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="custom-content">
|
||||
<div
|
||||
v-for="(item, i) in list"
|
||||
:key="i"
|
||||
>
|
||||
<p>
|
||||
{{ item.name }} <span
|
||||
class="status"
|
||||
:class="{ [item.state]: true }"
|
||||
>{{ item.state }}</span>
|
||||
</p>
|
||||
<PercentageBar
|
||||
:model-value="item.percent"
|
||||
preferred-direction="MORE"
|
||||
/>
|
||||
<p class="warning">
|
||||
{{ item.message }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</Collapse>
|
||||
</div>
|
||||
</div>
|
||||
@@ -93,7 +93,7 @@ export default {
|
||||
.total-bar {
|
||||
display: flex;
|
||||
user-select: none;
|
||||
.bar {
|
||||
> .bar {
|
||||
width: 85%;
|
||||
}
|
||||
.on-off {
|
||||
@@ -102,25 +102,22 @@ export default {
|
||||
}
|
||||
}
|
||||
.custom-content {
|
||||
.item {
|
||||
margin-bottom: 14px;
|
||||
p {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.status {
|
||||
float: right;
|
||||
}
|
||||
.Succeeded, .Upgrading, .Pending {
|
||||
color: var(--success);
|
||||
}
|
||||
.failed {
|
||||
color: var(--error)
|
||||
}
|
||||
.warning {
|
||||
color: var(--error);
|
||||
}
|
||||
margin-bottom: 14px;
|
||||
p {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.status {
|
||||
float: right;
|
||||
}
|
||||
.Succeeded, .Upgrading, .Pending {
|
||||
color: var(--success);
|
||||
}
|
||||
.failed {
|
||||
color: var(--error)
|
||||
}
|
||||
.warning {
|
||||
color: var(--error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -6,6 +6,7 @@ import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||
import { HCI_SETTING } from '../../config/settings';
|
||||
import UnitInput from '@shell/components/form/UnitInput';
|
||||
|
||||
const DEFAULT_TYPE = 's3';
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
name: 'HarvesterEditBackupTarget',
|
||||
|
||||
components: {
|
||||
LabeledInput, LabeledSelect, Tip, Password, MessageLink
|
||||
LabeledInput, LabeledSelect, Tip, Password, MessageLink, UnitInput
|
||||
},
|
||||
|
||||
mixins: [CreateEditView],
|
||||
@@ -24,7 +25,9 @@ export default {
|
||||
try {
|
||||
parseDefaultValue = JSON.parse(this.value.value);
|
||||
} catch (error) {
|
||||
parseDefaultValue = { type: '', endpoint: '' };
|
||||
parseDefaultValue = {
|
||||
type: '', endpoint: '', refreshIntervalInSeconds: 0
|
||||
};
|
||||
}
|
||||
|
||||
// set default type to s3
|
||||
@@ -62,6 +65,10 @@ export default {
|
||||
}];
|
||||
},
|
||||
|
||||
refreshIntervalInSecondEnabled() {
|
||||
return this.$store.getters['harvester-common/getFeatureEnabled']('refreshIntervalInSecond');
|
||||
},
|
||||
|
||||
isS3() {
|
||||
return this.parseDefaultValue.type === DEFAULT_TYPE;
|
||||
},
|
||||
@@ -83,7 +90,9 @@ export default {
|
||||
try {
|
||||
parseDefaultValue = JSON.parse(neu.value);
|
||||
} catch (err) {
|
||||
parseDefaultValue = { type: '', endpoint: '' };
|
||||
parseDefaultValue = {
|
||||
type: '', endpoint: '', refreshIntervalInSeconds: 0
|
||||
};
|
||||
}
|
||||
|
||||
this['parseDefaultValue'] = parseDefaultValue;
|
||||
@@ -111,7 +120,6 @@ export default {
|
||||
if (this.isS3 && !this.parseDefaultValue.virtualHostedStyle) {
|
||||
this.parseDefaultValue.virtualHostedStyle = false;
|
||||
}
|
||||
|
||||
if (!this.parseDefaultValue.type) {
|
||||
delete this.value['value'];
|
||||
} else {
|
||||
@@ -120,7 +128,9 @@ export default {
|
||||
},
|
||||
|
||||
useDefault() {
|
||||
this['parseDefaultValue'] = { type: '', endpoint: '' };
|
||||
this['parseDefaultValue'] = {
|
||||
type: '', endpoint: '', refreshIntervalInSeconds: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -139,6 +149,23 @@ export default {
|
||||
:options="typeOption"
|
||||
@update:value="update"
|
||||
/>
|
||||
<UnitInput
|
||||
v-if="refreshIntervalInSecondEnabled"
|
||||
v-model:value="parseDefaultValue.refreshIntervalInSeconds"
|
||||
:suffix="parseDefaultValue.refreshIntervalInSeconds <= 1 ? 'Second' : 'Seconds'"
|
||||
:label="t('harvester.backup.refreshInterval.label')"
|
||||
:mode="mode"
|
||||
:positive="true"
|
||||
class="mb-5"
|
||||
required
|
||||
@update:value="update"
|
||||
/>
|
||||
<Tip
|
||||
v-if="refreshIntervalInSecondEnabled"
|
||||
class="mb-20"
|
||||
icon="icon icon-info"
|
||||
:text="t('harvester.backup.refreshInterval.tip')"
|
||||
/>
|
||||
<LabeledInput
|
||||
v-model:value="parseDefaultValue.endpoint"
|
||||
class="mb-5"
|
||||
|
||||
@@ -75,7 +75,11 @@ export default {
|
||||
const csiDrivers = this.$store.getters[`${ inStore }/all`](CSI_DRIVER) || [];
|
||||
|
||||
return this.configArr.length >= csiDrivers.length;
|
||||
}
|
||||
},
|
||||
|
||||
allowEmptySnapshotClassNameFeatureEnabled() {
|
||||
return this.$store.getters['harvester-common/getFeatureEnabled']('allowEmptySnapshotClassName');
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -139,7 +143,7 @@ export default {
|
||||
errors.push(this.t('validation.required', { key: this.t('harvester.setting.csiDriverConfig.volumeSnapshotClassName') }, true));
|
||||
}
|
||||
|
||||
if (!config.value.backupVolumeSnapshotClassName) {
|
||||
if (!this.allowEmptySnapshotClassNameFeatureEnabled && !config.value.backupVolumeSnapshotClassName) {
|
||||
errors.push(this.t('validation.required', { key: this.t('harvester.setting.csiDriverConfig.backupVolumeSnapshotClassName') }, true));
|
||||
}
|
||||
});
|
||||
@@ -158,10 +162,22 @@ export default {
|
||||
this.configArr.splice(idx, 1);
|
||||
},
|
||||
|
||||
isBackupVolumeSnapshotRequired(driver) {
|
||||
return driver === LONGHORN_DRIVER;
|
||||
},
|
||||
|
||||
disableEdit(driver) {
|
||||
return driver === LONGHORN_DRIVER;
|
||||
},
|
||||
|
||||
isBackupVolumeSnapshotClassNameDisabled(driver) {
|
||||
return driver === LONGHORN_DRIVER || this.allowEmptySnapshotClassNameFeatureEnabled;
|
||||
},
|
||||
|
||||
isBackupVolumeSnapshotClassNameSelectable(driver) {
|
||||
return driver === LONGHORN_DRIVER;
|
||||
},
|
||||
|
||||
add() {
|
||||
this.configArr.push({
|
||||
key: '',
|
||||
@@ -184,6 +200,7 @@ export default {
|
||||
<InfoBox
|
||||
v-for="(driver, idx) in configArr"
|
||||
:key="idx"
|
||||
class="box"
|
||||
>
|
||||
<button
|
||||
:disabled="disableEdit(driver.key)"
|
||||
@@ -226,10 +243,11 @@ export default {
|
||||
<LabeledSelect
|
||||
v-model:value="driver.value.backupVolumeSnapshotClassName"
|
||||
:mode="mode"
|
||||
required
|
||||
:disabled="disableEdit(driver.key)"
|
||||
: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"
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script>
|
||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
|
||||
import { Banner } from '@components/Banner';
|
||||
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||
|
||||
@@ -62,7 +61,7 @@ export default {
|
||||
|
||||
<div
|
||||
class="row"
|
||||
@update:value="update"
|
||||
@input="update"
|
||||
>
|
||||
<div class="col span-12">
|
||||
<LabeledInput
|
||||
|
||||
@@ -59,7 +59,7 @@ export default {
|
||||
name="model"
|
||||
:options="[true,false]"
|
||||
:labels="[t('generic.enabled'), t('generic.disabled')]"
|
||||
@input="update"
|
||||
@update:value="update"
|
||||
/>
|
||||
|
||||
<LabeledInput
|
||||
|
||||
@@ -35,15 +35,26 @@ const featuresV140 = [
|
||||
'improveMaintenanceMode',
|
||||
];
|
||||
|
||||
// TODO: add v1.4.1 official release note
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.1-rc1
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.1
|
||||
const featuresV141 = [
|
||||
...featuresV140
|
||||
];
|
||||
|
||||
// TODO: add v1.5.0 official release note
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.2
|
||||
const featuresV142 = [
|
||||
...featuresV141,
|
||||
'refreshIntervalInSecond',
|
||||
'allowEmptySnapshotClassName'
|
||||
];
|
||||
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.3-rc1
|
||||
const featuresV143 = [
|
||||
...featuresV142,
|
||||
];
|
||||
|
||||
// https://github.com/harvester/harvester-ui-extension/releases/tag/v1.5.0
|
||||
const featuresV150 = [
|
||||
...featuresV141
|
||||
...featuresV142
|
||||
];
|
||||
|
||||
export const RELEASE_FEATURES = {
|
||||
@@ -53,5 +64,7 @@ export const RELEASE_FEATURES = {
|
||||
'v1.3.3': featuresV133,
|
||||
'v1.4.0': featuresV140,
|
||||
'v1.4.1': featuresV141,
|
||||
'v1.4.2': featuresV142,
|
||||
'v1.4.3': featuresV143,
|
||||
'v1.5.0': featuresV150
|
||||
};
|
||||
|
||||
@@ -166,6 +166,8 @@ export default {
|
||||
<Banner
|
||||
v-for="(error, i) in errors"
|
||||
:key="i"
|
||||
:label="error"
|
||||
color="error"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -137,6 +137,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 +162,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>
|
||||
|
||||
@@ -164,6 +164,12 @@ export default {
|
||||
class="mt-20"
|
||||
required
|
||||
/>
|
||||
<Banner
|
||||
v-for="(err, i) in errors"
|
||||
:key="i"
|
||||
color="error"
|
||||
:label="err"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
@@ -182,11 +188,6 @@ export default {
|
||||
@click="save"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Banner
|
||||
v-for="(err, i) in errors"
|
||||
:key="i"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -95,6 +95,12 @@ export default {
|
||||
suffix="GiB"
|
||||
class="mb-20"
|
||||
/>
|
||||
<Banner
|
||||
v-for="(err, i) in errors"
|
||||
:key="i"
|
||||
color="error"
|
||||
:label="err"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
@@ -108,12 +114,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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -233,7 +233,7 @@ export default {
|
||||
:disabled="isEdit || isView"
|
||||
:mode="mode"
|
||||
row
|
||||
@input="onTypeChange"
|
||||
@update:value="onTypeChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="row mb-30">
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { randomStr } from '@shell/utils/string';
|
||||
|
||||
import { clone } from '@shell/utils/object';
|
||||
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||
import ModalWithCard from '@shell/components/ModalWithCard';
|
||||
|
||||
import { clone } from '@shell/utils/object';
|
||||
import { _VIEW } from '@shell/config/query-params';
|
||||
|
||||
import { NAMESPACE } from '@shell/config/types';
|
||||
import { HCI } from '../../types';
|
||||
|
||||
@@ -126,10 +123,10 @@ export default {
|
||||
this.checkedSsh = neu;
|
||||
},
|
||||
|
||||
checkedSsh(val, old) {
|
||||
if ( val.includes(_NEW)) {
|
||||
this['checkedSsh'] = old;
|
||||
this.update();
|
||||
checkedSsh(val) {
|
||||
// if click on Create a New...
|
||||
if (val.includes(_NEW)) {
|
||||
this.checkedSsh = this.checkedSsh.filter((key) => key !== _NEW);
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
@@ -175,6 +172,7 @@ export default {
|
||||
|
||||
if (res.id) {
|
||||
this.checkedSsh.push(`${ this.namespace }/${ this.sshName }`);
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -243,7 +241,7 @@ export default {
|
||||
<LabeledSelect
|
||||
v-model:value="checkedSsh"
|
||||
:label="t('harvester.virtualMachine.input.sshKey')"
|
||||
:taggable="true"
|
||||
:taggable="!disabled"
|
||||
:mode="mode"
|
||||
:multiple="true"
|
||||
:searchable="searchable"
|
||||
|
||||
@@ -46,10 +46,13 @@ export default {
|
||||
this[key] = res[key];
|
||||
}
|
||||
|
||||
uniq([
|
||||
const vGpus = this.vm.isOff ? [
|
||||
...(this.value?.domain?.devices?.gpus || []).map(({ name }) => name),
|
||||
] : [
|
||||
...Object.values(this.vm?.provisionedVGpus).reduce((acc, gpus) => [...acc, ...gpus], [])
|
||||
]).forEach((name) => {
|
||||
];
|
||||
|
||||
uniq(vGpus).forEach((name) => {
|
||||
if (this.enabledDevices.find((device) => device?.metadata?.name === name)) {
|
||||
this.selectedDevices.push(name);
|
||||
}
|
||||
|
||||
@@ -579,7 +579,7 @@ export default {
|
||||
:create-namespace="true"
|
||||
:namespace="value.metadata.namespace"
|
||||
:mode="mode"
|
||||
:disabled="isWindows"
|
||||
:disabled="isWindows || isEdit"
|
||||
@update:sshKey="updateSSHKey"
|
||||
@register-after-hook="registerAfterHook"
|
||||
/>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
const rows = (this.value || []).map((row) => {
|
||||
let type = 'cidr';
|
||||
|
||||
if (row.rangeStart && row.rangeEnd) {
|
||||
if (row.rangeStart || row.rangeEnd) {
|
||||
type = 'range';
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ export default {
|
||||
:labels="[t('generic.disabled'),t('generic.enabled')]"
|
||||
:options="[false, true]"
|
||||
:disabled="disabled"
|
||||
@input="onToggle"
|
||||
@update:value="onToggle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -58,7 +58,7 @@ export default {
|
||||
const out = [];
|
||||
|
||||
blockDevices.map((b) => {
|
||||
if (b.metadata.state.error) {
|
||||
if (b?.metadata?.state?.error) {
|
||||
out.push(b.metadata.state.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import harvesterCommonStore from './store/harvester-common';
|
||||
import harvesterStore from './store/harvester-store';
|
||||
import customValidators from './validators';
|
||||
import { PRODUCT_NAME } from './config/harvester';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
// Init the package
|
||||
export default function (plugin: IPlugin) {
|
||||
@@ -20,7 +21,7 @@ export default function (plugin: IPlugin) {
|
||||
|
||||
// Built-in icon
|
||||
plugin.metadata.icon = require('./icon.svg');
|
||||
|
||||
|
||||
plugin.addProduct(require('./config/harvester-cluster'));
|
||||
|
||||
plugin.addDashboardStore(harvesterCommonStore.config.namespace, harvesterCommonStore.specifics, harvesterCommonStore.config);
|
||||
@@ -28,4 +29,8 @@ export default function (plugin: IPlugin) {
|
||||
plugin.validators = customValidators;
|
||||
|
||||
plugin.addRoutes(extensionRoutes);
|
||||
|
||||
plugin.register('component', 'NavHeaderRight', defineAsyncComponent(() =>
|
||||
import('./components/HarvesterUpgradeHeader.vue')
|
||||
));
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ asyncButton:
|
||||
waiting: Restarting…
|
||||
|
||||
harvester:
|
||||
branding:
|
||||
logos:
|
||||
tip: 'Upload a logo to replace the Harvester logo in the top-level navigation header. Image height should be 21 pixels with a max width of 200 pixels. Max file size is 20KB. Accepted formats: JPEG, PNG, SVG.'
|
||||
favicon:
|
||||
tip: 'Upload an icon to replace the Harvester favicon in the browser tab. Max file size is 20KB'
|
||||
productLabel: 'Harvester'
|
||||
modal:
|
||||
backup:
|
||||
@@ -897,6 +902,9 @@ harvester:
|
||||
label: Virtual Machine Backups
|
||||
createText: Restore Backup
|
||||
title: Restore Virtual Machine
|
||||
refreshInterval:
|
||||
label: Refresh Interval
|
||||
tip: The interval for the backup target to sync data to harvester cluster. Set to 0 to disable refresh mechanism.
|
||||
backupTargetTip: The endpoint used to access the backupstore. NFS and S3 are supported.
|
||||
message:
|
||||
noSetting:
|
||||
@@ -1497,6 +1505,14 @@ harvester:
|
||||
pollingInterval:
|
||||
label: Polling Interval
|
||||
|
||||
typeDescription:
|
||||
# Map of
|
||||
# type: Description to be shown on the top of list view describing the type.
|
||||
# Should fit on one line.
|
||||
# If you link to anything external, it MUST have
|
||||
# target="_blank" rel="noopener noreferrer nofollow"
|
||||
harvester: "Branding allows administrators to globally re-brand the UI by customizing the Harvester product name, logos and color scheme."
|
||||
|
||||
advancedSettings:
|
||||
experimental: 'Experimental features allow users to test and evaluate early-access functionality prior to official supported releases'
|
||||
descriptions:
|
||||
|
||||
@@ -101,7 +101,7 @@ export default {
|
||||
v-bind="$attrs"
|
||||
:headers="headers"
|
||||
:sub-rows="true"
|
||||
:groupable="false"
|
||||
:groupable="true"
|
||||
:rows="rows"
|
||||
:group-title-by="groupTitleBy"
|
||||
:group-by="groupBy"
|
||||
|
||||
@@ -894,8 +894,8 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate user data yaml which is decide by the "Install guest agent",
|
||||
* "OS type", "SSH Keys" and user input.
|
||||
* Generate user data yaml which is decided by the
|
||||
* "Install guest agent", "OS type", "SSH keys" and user input.
|
||||
* @param config
|
||||
*/
|
||||
getUserData(config) {
|
||||
@@ -919,7 +919,9 @@ export default {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return userDataYaml;
|
||||
const hasCloudComment = this.hasCloudConfigComment(userDataYaml);
|
||||
|
||||
return hasCloudComment ? userDataYaml : `#cloud-config\n${ userDataYaml }`;
|
||||
} catch (e) {
|
||||
console.error('Error: Unable to parse yaml document', e); // eslint-disable-line no-console
|
||||
|
||||
@@ -1212,7 +1214,6 @@ export default {
|
||||
|
||||
let secret = this.getSecret(vm.spec);
|
||||
|
||||
// const userData = this.getUserData({ osType: this.osType, installAgent: this.installAgent });
|
||||
if (!secret && this.isEdit && this.secretRef) {
|
||||
// When editing the vm, if the userData and networkData are deleted, we also need to clean up the secret values
|
||||
secret = this.secretRef;
|
||||
@@ -1431,7 +1432,6 @@ export default {
|
||||
sshAuthorizedKeys.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
const userDataJson = this.convertToJson(this.userScript);
|
||||
|
||||
userDataJson.ssh_authorized_keys = sshAuthorizedKeys;
|
||||
@@ -1553,19 +1553,9 @@ export default {
|
||||
*/
|
||||
handler(neu) {
|
||||
if (this.deleteAgent) {
|
||||
let out = this.getUserData({
|
||||
this['userScript'] = this.getUserData({
|
||||
installAgent: neu, osType: this.osType, deletePackage: this.deletePackage
|
||||
});
|
||||
|
||||
if (neu) {
|
||||
const hasCloudComment = this.hasCloudConfigComment(out);
|
||||
|
||||
if (!hasCloudComment) {
|
||||
out = `#cloud-config\n${ out }`;
|
||||
}
|
||||
}
|
||||
|
||||
this['userScript'] = out;
|
||||
this.refreshYamlEditor();
|
||||
}
|
||||
this.deleteAgent = true;
|
||||
@@ -1592,9 +1582,14 @@ export default {
|
||||
sshKey(neu, old) {
|
||||
const _diff = difference(old, neu);
|
||||
|
||||
if (_diff.length && this.isEdit) {
|
||||
// delete removed ssh key in userdata if needed
|
||||
if (_diff.length > 0 && this.isCreate) {
|
||||
this.deleteSSHFromUserData(_diff);
|
||||
}
|
||||
|
||||
// refresh yaml editor to get the latest userScript
|
||||
this.userScript = this.getUserData({ installAgent: this.installAgent, osType: this.osType });
|
||||
this.refreshYamlEditor();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import SteveModel from '@shell/plugins/steve/steve-class';
|
||||
|
||||
/**
|
||||
* Class representing PCI Device Claim resource.
|
||||
* @extends SteveModal
|
||||
*/
|
||||
export default class PCIDeviceClaim extends SteveModel {
|
||||
cleanForSave(data, _forNew) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import SteveModel from '@shell/plugins/steve/steve-class';
|
||||
|
||||
/**
|
||||
* Class representing USB Device Claim resource.
|
||||
* @extends SteveModal
|
||||
*/
|
||||
export default class USBDeviceClaim extends SteveModel {
|
||||
cleanForSave(data, _forNew) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -66,4 +66,8 @@ export default class HarvesterResource extends SteveModel {
|
||||
return this.hasLink('self') && this.$rootGetters['prefs/get'](DEV);
|
||||
}
|
||||
}
|
||||
|
||||
cleanForSave(data, _forNew) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ export default class HciPv extends HarvesterResource {
|
||||
}
|
||||
|
||||
get isEncrypted() {
|
||||
return this.relatedPV?.spec.csi.volumeAttributes.encrypted === 'true';
|
||||
return this.relatedPV?.spec?.csi?.volumeAttributes?.encrypted === 'true';
|
||||
}
|
||||
|
||||
get longhornVolume() {
|
||||
|
||||
@@ -3,4 +3,4 @@ import SteveSchema from '@shell/models/steve-schema';
|
||||
/**
|
||||
* This is the steve schema that's used for the harvester store
|
||||
*/
|
||||
export default class HarvesterStoreSchema extends SteveSchema { }
|
||||
export default class HarvesterStoreSchema extends SteveSchema {}
|
||||
@@ -64,4 +64,10 @@ export default class HciBlockDevice extends HarvesterResource {
|
||||
// spec.fileSystem.provisioned is deprecated
|
||||
return this.spec?.fileSystem?.provisioned || this.spec?.provision;
|
||||
}
|
||||
|
||||
// Overwrite cleanForSave() in shell/plugins/steve/steve-class.js as it deleted status object in harvesterhci.io.blockdevice CRD
|
||||
// but /v1/harvester/harvesterhci.io.blockdevices/longhorn-system/{id} API requires status object
|
||||
cleanForSave(data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "harvester",
|
||||
"description": "Rancher UI Extension for Harvester",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.6",
|
||||
"private": false,
|
||||
"rancher": {
|
||||
"annotations": {
|
||||
|
||||
@@ -164,7 +164,7 @@ export default {
|
||||
<h1 class="mb-20">
|
||||
{{ t('branding.label') }}
|
||||
</h1>
|
||||
<TypeDescription resource="branding" />
|
||||
<TypeDescription resource="harvester" />
|
||||
<div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
@@ -180,7 +180,7 @@ export default {
|
||||
{{ t('branding.logos.label') }}
|
||||
</h3>
|
||||
<label class="text-label">
|
||||
{{ t('branding.logos.tip', {}, true) }}
|
||||
{{ t('harvester.branding.logos.tip', {}, true) }}
|
||||
</label>
|
||||
<div class="row mt-10 mb-20">
|
||||
<Checkbox
|
||||
@@ -244,7 +244,7 @@ export default {
|
||||
{{ t('branding.favicon.label') }}
|
||||
</h3>
|
||||
<label class="text-label">
|
||||
{{ t('branding.favicon.tip', {}, true) }}
|
||||
{{ t('harvester.branding.favicon.tip', {}, true) }}
|
||||
</label>
|
||||
<div class="row mt-10 mb-20">
|
||||
<Checkbox
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"skipLibCheck": true,
|
||||
"useDefineForClassFields": false,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
|
||||
Reference in New Issue
Block a user