mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-10-01 03:36:04 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
404395c7d9 | ||
|
|
dc2437db99 | ||
|
|
e8c8a54b9f | ||
|
|
f3e4a8afe8 | ||
|
|
e73c62739f | ||
|
|
696af4e04f | ||
|
|
009f384a73 | ||
|
|
37766454bd | ||
|
|
7943913ef7 | ||
|
|
56a0fefd40 | ||
|
|
ff1d5925a8 | ||
|
|
63b5b980b7 | ||
|
|
1f7fd1246f | ||
|
|
34a25e9fc8 | ||
|
|
fb8d81d953 | ||
|
|
ba810a52b2 | ||
|
|
3f4f30ba0b | ||
|
|
b428aaecf8 | ||
|
|
6b07a03451 | ||
|
|
2c756582e3 | ||
|
|
1c15ed8003 | ||
|
|
9f3e689727 | ||
|
|
6644651fe5 | ||
|
|
2d6bc65b26 | ||
|
|
7b6efa624f | ||
|
|
d9db1263d1 | ||
|
|
10a8f18784 | ||
|
|
1098ef8f6a | ||
|
|
4480dbdeed | ||
|
|
a7b4366d7c | ||
|
|
d72857f374 | ||
|
|
57ab9e2830 | ||
|
|
8116358011 | ||
|
|
5bd8ad2a93 | ||
|
|
345fe636ec | ||
|
|
7e32ea453b | ||
|
|
8f3b5265de | ||
|
|
4ca6caefb9 | ||
|
|
fb7d604ed6 | ||
|
|
9a60a621de | ||
|
|
7645d6161f | ||
|
|
c3f2665912 | ||
|
|
2a58745550 | ||
|
|
69d7046bc7 | ||
|
|
692c775b51 | ||
|
|
8b43c200b2 | ||
|
|
ab71cb377c | ||
|
|
814d296d75 | ||
|
|
eb667fd56b | ||
|
|
e4b3f84905 | ||
|
|
ea68b95c26 | ||
|
|
da77762b7f | ||
|
|
161adde1da | ||
|
|
28ece801d5 | ||
|
|
a8cf6f5947 | ||
|
|
28e4991bd0 | ||
|
|
0d94e66b8f | ||
|
|
871ad2e88d | ||
|
|
03d1174d8e | ||
|
|
e236ab2d5f | ||
|
|
0b6569ff64 | ||
|
|
259988f230 | ||
|
|
bbbdd1a881 | ||
|
|
83edd23ada | ||
|
|
a6f2301498 | ||
|
|
0171f70b36 | ||
|
|
578fb72cbb | ||
|
|
45773987f3 | ||
|
|
f2b98b851d | ||
|
|
42d793b50e | ||
|
|
e2474ebf8d | ||
|
|
ad37d502f7 | ||
|
|
666fe7b3b8 | ||
|
|
81f1a56434 | ||
|
|
d6bf6f1b55 | ||
|
|
2774b1c30c | ||
|
|
8b35ea1eaa | ||
|
|
e86df77224 | ||
|
|
6d0ed11057 | ||
|
|
7d17baf774 | ||
|
|
69e257d41c | ||
|
|
e5d4d0556d | ||
|
|
e2773f8c69 | ||
|
|
b7b259c699 | ||
|
|
687943ae92 | ||
|
|
4d48e75447 | ||
|
|
94429d6b64 | ||
|
|
990c06ba98 | ||
|
|
a207ec078b | ||
|
|
8d4524c4c6 | ||
|
|
f04c0c6c9b | ||
|
|
ab77b21aa8 | ||
|
|
c86b4b0466 | ||
|
|
59aec78631 | ||
|
|
e42610ca6d | ||
|
|
e33cc457e9 | ||
|
|
0208a65052 | ||
|
|
b5af90e475 | ||
|
|
a0e81cffff | ||
|
|
d774b323d1 | ||
|
|
fe0dc396dc | ||
|
|
fbd384d923 | ||
|
|
9a89f45a2a | ||
|
|
b8a1403655 | ||
|
|
5b0202a13b | ||
|
|
3d5a8556f2 | ||
|
|
6782edf7b0 | ||
|
|
b8a132c998 | ||
|
|
bc761e0747 | ||
|
|
ce2ead4426 | ||
|
|
4fe5c2e740 | ||
|
|
8a5f425b74 | ||
|
|
a7bb16636f | ||
|
|
63994c1896 | ||
|
|
7745f9805c | ||
|
|
36dd2b4541 | ||
|
|
4a19223afe | ||
|
|
4f44be4826 | ||
|
|
8b226980f3 | ||
|
|
51cf301d18 | ||
|
|
264eadb7dd | ||
|
|
c3cf1eb9a4 | ||
|
|
de10007dcc | ||
|
|
5bb40649e9 | ||
|
|
dd04d405f0 |
@@ -13,3 +13,4 @@ dist-pkg
|
||||
.DS_Store
|
||||
pkg/harvester/index.ts
|
||||
pkg/harvester/store/*
|
||||
scripts/pkgfile.js
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
pull_request_rules:
|
||||
- name: Automatically open backport PR to release-harvester-v1.5
|
||||
conditions:
|
||||
- base=main
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- "release-harvester-v1.5"
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
labels:
|
||||
- "v1.5 backport PR"
|
||||
|
||||
- name: Ask to resolve conflict
|
||||
conditions:
|
||||
- conflict
|
||||
actions:
|
||||
comment:
|
||||
message: This pull request is now in conflict. Could you fix it @{{author}}? 🙏
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Build Dashboard (Branch)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'release-harvester-v*'
|
||||
- '*-dev'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- 'release-harvester-v*'
|
||||
- '*-dev'
|
||||
types:
|
||||
- merged
|
||||
|
||||
jobs:
|
||||
build-validation:
|
||||
name: Build Test
|
||||
uses: ./.github/workflows/test.yaml
|
||||
build:
|
||||
name: Build and Upload Package
|
||||
uses: ./.github/workflows/build-and-upload.yaml
|
||||
needs:
|
||||
- build-validation
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
with:
|
||||
CI_BRANCH: ${{github.ref_name}}
|
||||
@@ -0,0 +1,21 @@
|
||||
name: Build Dashboard (Release)
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v[1-9].*
|
||||
|
||||
jobs:
|
||||
build-validation:
|
||||
name: Build Test
|
||||
uses: ./.github/workflows/test.yaml
|
||||
build:
|
||||
name: Build and Upload Package
|
||||
uses: ./.github/workflows/build-and-upload.yaml
|
||||
needs:
|
||||
- build-validation
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
with:
|
||||
CI_BUILD_TAG: ${{github.ref_name}}
|
||||
@@ -0,0 +1,165 @@
|
||||
name: Build Harvester Dashboard and Upload
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
CI_BRANCH:
|
||||
required: false
|
||||
type: string
|
||||
CI_BUILD_TAG:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
env:
|
||||
GOOGLE_AUTH: ''
|
||||
DOCKER_USERNAME: ''
|
||||
DOCKER_PASSWORD: ''
|
||||
CI_BUILD_TAG: ${{inputs.CI_BUILD_TAG}}
|
||||
CI_BRANCH: ${{inputs.CI_BRANCH}}
|
||||
GIT_REPO: ${{github.repository}}
|
||||
GIT_COMMIT: ${{github.sha}}
|
||||
REPO: ${{github.event.repository.name || ''}}
|
||||
|
||||
jobs:
|
||||
build-and-upload-hosted:
|
||||
name: Build & Upload Hosted
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
# Note - Cannot use the setup action here as it uses a different yarn install arg
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
# Build a directory containing the dashboard that can be used with ui-dashboard-index
|
||||
- id: build-hosted
|
||||
name: Build Hosted
|
||||
run: ./scripts/build-hosted
|
||||
|
||||
- id: upload-gate
|
||||
name: Upload Gate (superseded by a newer build?)
|
||||
run: ./scripts/build-upload-gate
|
||||
|
||||
- name: Get gcs auth
|
||||
uses: rancher-eio/read-vault-secrets@main
|
||||
with:
|
||||
secrets: |
|
||||
secret/data/github/repo/${{ github.repository }}/google-auth/harvester/credentials token | GOOGLE_AUTH ;
|
||||
|
||||
- name: Apply gcs auth
|
||||
# https://github.com/google-github-actions/auth
|
||||
uses: 'google-github-actions/auth@v2'
|
||||
with:
|
||||
credentials_json: "${{ env.GOOGLE_AUTH }}"
|
||||
|
||||
- name: Upload build
|
||||
uses: 'google-github-actions/upload-cloud-storage@v2'
|
||||
# https://github.com/google-github-actions/upload-cloud-storage
|
||||
with:
|
||||
path: ${{steps.build-hosted.outputs.BUILD_HOSTED_DIR}}
|
||||
destination: releases.rancher.com/harvester-ui/dashboard/${{ steps.build-hosted.outputs.BUILD_HOSTED_LOCATION }}
|
||||
parent: false
|
||||
headers: |-
|
||||
cache-control: no-cache,must-revalidate
|
||||
process_gcloudignore: false
|
||||
|
||||
build-and-upload-embedded:
|
||||
name: Build & Upload Embedded
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
# Note - Cannot use the setup action here as it uses a different yarn install arg
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
# Build a tar that will be picked up by rancher builds and embedded into it
|
||||
- id: build-embedded
|
||||
name: Build Embedded
|
||||
run: ./scripts/build-embedded
|
||||
env:
|
||||
DISABLED_EMBED_PKG: https://releases.rancher.com/harvester-ui/plugin/harvester-1.0.3.tar.gz
|
||||
|
||||
- name: Get gcs auth
|
||||
uses: rancher-eio/read-vault-secrets@main
|
||||
with:
|
||||
secrets: |
|
||||
secret/data/github/repo/${{ github.repository }}/google-auth/harvester/credentials token | GOOGLE_AUTH ;
|
||||
|
||||
- name: Apply gcs auth
|
||||
# https://github.com/google-github-actions/auth
|
||||
uses: 'google-github-actions/auth@v2'
|
||||
with:
|
||||
credentials_json: "${{ env.GOOGLE_AUTH }}"
|
||||
|
||||
- name: Upload tar
|
||||
uses: 'google-github-actions/upload-cloud-storage@v2'
|
||||
with:
|
||||
path: ${{steps.build-embedded.outputs.BUILD_EMBEDED_TGZ}}
|
||||
destination: releases.rancher.com/harvester-ui/dashboard
|
||||
parent: false
|
||||
headers: |-
|
||||
cache-control: no-cache,must-revalidate
|
||||
process_gcloudignore: false
|
||||
|
||||
build-and-upload-harvester-plugin:
|
||||
name: Build & Upload Plugin
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
# Note - Cannot use the setup action here as it uses a different yarn install arg
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
|
||||
- id: ci-build-pkg
|
||||
name: Build pkg
|
||||
run: ./scripts/ci-build-pkg.sh harvester
|
||||
|
||||
- id: upload-gate
|
||||
name: Upload Gate
|
||||
run: ./scripts/build-upload-gate
|
||||
|
||||
- name: Get gcs auth
|
||||
uses: rancher-eio/read-vault-secrets@main
|
||||
with:
|
||||
secrets: |
|
||||
secret/data/github/repo/${{ github.repository }}/google-auth/harvester/credentials token | GOOGLE_AUTH ;
|
||||
|
||||
- name: Apply gcs auth
|
||||
# https://github.com/google-github-actions/auth
|
||||
uses: 'google-github-actions/auth@v2'
|
||||
with:
|
||||
credentials_json: "${{ env.GOOGLE_AUTH }}"
|
||||
|
||||
- name: Upload plugin tar
|
||||
uses: 'google-github-actions/upload-cloud-storage@v2'
|
||||
with:
|
||||
path: dist-pkg/${{steps.ci-build-pkg.outputs.PKG_TARBALL}}
|
||||
destination: releases.rancher.com/harvester-ui/plugin
|
||||
parent: false
|
||||
headers: |-
|
||||
cache-control: no-cache,must-revalidate
|
||||
process_gcloudignore: false
|
||||
|
||||
- name: Upload plugin directory
|
||||
uses: 'google-github-actions/upload-cloud-storage@v2'
|
||||
with:
|
||||
path: dist-pkg/${{steps.ci-build-pkg.outputs.PKG_NAME}}
|
||||
destination: releases.rancher.com/harvester-ui/plugin/${{steps.ci-build-pkg.outputs.PKG_NAME}}
|
||||
parent: false
|
||||
headers: |-
|
||||
cache-control: no-cache,must-revalidate
|
||||
process_gcloudignore: false
|
||||
@@ -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 }}'
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
workflow_call: # This tells GH that the workflow is reusable
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
@@ -2,10 +2,36 @@
|
||||
|
||||
Rancher Extension used in [rancher/dashboard](https://github.com/rancher/dashboard) for [Harvester](https://harvesterhci.io) Dashboard UI.
|
||||
|
||||
`
|
||||
From Rancher 2.10.0, Harvester integration is provided by this new Harvester UI Extension.
|
||||
`
|
||||
|
||||
## Installation
|
||||
|
||||
To install the Harvester UI Extension in Rancher 2.10.0 and newer:
|
||||
|
||||
- Go to 'Extensions' in the Rancher UI (click on the jigsaw icon in the side bar)
|
||||
- From the three-dots menu in the upper right of the page, open the menu and select 'Manage Repositories'
|
||||
- From the Repositories page, click 'Create'
|
||||
- For name, enter 'harvester-ui-extension'
|
||||
- For Target, choose 'Git repository'
|
||||
- For Git Repo URL, enter `https://github.com/harvester/harvester-ui-extension`
|
||||
- For Git Branch, enter `gh-pages`
|
||||
- Click 'Create`
|
||||
- From the Repositories list, wait until the new Repository added updates to the 'Active' state
|
||||
- Go back to 'Extensions'
|
||||
- Click on the 'Available' tab if not already selected
|
||||
- Click on 'Install' for the Harvester UI Extension
|
||||
|
||||
## Running for Development
|
||||
|
||||
This is what you probably want to get started.
|
||||
|
||||
### Prerequisite
|
||||
|
||||
Nodejs version >= 20
|
||||
|
||||
|
||||
### Standalone Mode
|
||||
|
||||
For development, serve with hot reload at https://localhost:8005
|
||||
@@ -27,16 +53,15 @@ RANCHER_ENV=harvester VUE_APP_SERVER_VERSION=your-harvester-server-version API=h
|
||||
RANCHER_ENV=harvester VUE_APP_SERVER_VERSION=v1.4.0 API=https://192.168.1.123 yarn dev
|
||||
```
|
||||
|
||||
### Integration Mode
|
||||
### Rancher Integration Mode
|
||||
|
||||
In this mode, you need to have Rancher and import Harvester, more detail in [Harvester Integration | Rancher](https://ranchermanager.docs.rancher.com/v2.6/integrations-in-rancher/harvester).
|
||||
In this mode, you need to have Rancher and run Harvester UI Extension as Rancher extension, see more detail in [Rancher UI extension](https://extensions.rancher.io/extensions/next/extensions-getting-started#running-the-app).
|
||||
|
||||
```bash
|
||||
# build harvester plugin
|
||||
yarn build-pkg harvester && yarn serve-pkgs
|
||||
API=https://your-rancher-ip yarn dev
|
||||
|
||||
# Open another terminal window
|
||||
HARVESTER_PKG_URL=http://127.0.0.1:4500/harvester-${version}/harvester-${version}.umd.min.js API=https://your-rancher-ip RANCHER_ENV=harvester yarn mem-dev
|
||||
# Example
|
||||
API=https://192.168.1.123 yarn dev
|
||||
```
|
||||
|
||||
## Contributing
|
||||
@@ -57,4 +82,4 @@ Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
limitations under the License.
|
||||
|
||||
+6
-5
@@ -1,18 +1,19 @@
|
||||
{
|
||||
"name": "harvester-ui-extension",
|
||||
"version": "0.1.0",
|
||||
"version": "1.0.5",
|
||||
"private": false,
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rancher/shell": "3.0.1-rc.1",
|
||||
"@rancher/shell": "3.0.1-rc.4",
|
||||
"cache-loader": "^4.1.0",
|
||||
"color": "4.2.3",
|
||||
"ip": "2.0.1",
|
||||
"node-polyfill-webpack-plugin": "^3.0.0",
|
||||
"sortablejs-vue3": "^1.2.11",
|
||||
"yaml": "^2.5.1"
|
||||
"vue-draggable-next": "^2.2.1",
|
||||
"yaml": "^2.5.1",
|
||||
"@babel/plugin-transform-class-static-block": "7.26.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "~20.10.0",
|
||||
@@ -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'
|
||||
]
|
||||
};
|
||||
|
||||
@@ -81,8 +81,10 @@ export default {
|
||||
</span>
|
||||
|
||||
<v-dropdown
|
||||
popper-class="filter-parent-sriov"
|
||||
trigger="click"
|
||||
placement="bottom-end"
|
||||
:distance="20"
|
||||
>
|
||||
<slot name="header">
|
||||
<button
|
||||
@@ -142,4 +144,11 @@ export default {
|
||||
.required {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.filter-parent-sriov .v-popper__arrow-container {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -25,6 +25,9 @@ export default {
|
||||
|
||||
return Array.from(new Set(options));
|
||||
},
|
||||
enableFilterButton() {
|
||||
return this.rows.some((r) => r.sourceSchedule !== undefined);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -63,27 +66,30 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vm-schedule-filter">
|
||||
<template>
|
||||
<span
|
||||
v-if="selected"
|
||||
class="banner-item bg-warning"
|
||||
>
|
||||
{{ t('harvester.tableHeaders.vmSchedule') }}{{ selected ? ` = ${selected}`: '' }}<i
|
||||
class="icon icon-close ml-5"
|
||||
@click="remove"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<div
|
||||
class="vm-schedule-filter"
|
||||
>
|
||||
<span
|
||||
v-if="selected"
|
||||
class="banner-item bg-warning"
|
||||
>
|
||||
{{ t('harvester.tableHeaders.vmSchedule') }}{{ selected ? ` = ${selected}`: '' }}
|
||||
<i
|
||||
class="icon icon-close ml-5"
|
||||
@click="remove"
|
||||
/>
|
||||
</span>
|
||||
<v-dropdown
|
||||
popper-class="vm-schedule-dropdown"
|
||||
:triggers="scheduleOptions.length ? ['click'] : []"
|
||||
placement="bottom-end"
|
||||
offset="1"
|
||||
:distance="20"
|
||||
>
|
||||
<button
|
||||
ref="actionDropDown"
|
||||
class="btn bg-primary mr-10"
|
||||
:disabled="!enableFilterButton"
|
||||
>
|
||||
<slot name="title">
|
||||
{{ t('harvester.fields.filterSchedule') }}
|
||||
@@ -98,7 +104,7 @@ export default {
|
||||
name="model"
|
||||
:options="scheduleOptions"
|
||||
:labels="scheduleOptions"
|
||||
@input="onSelect"
|
||||
@update:value="onSelect"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -106,6 +112,12 @@ export default {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.vm-schedule-dropdown .v-popper__arrow-container {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vm-schedule-filter {
|
||||
display: inline-block;
|
||||
|
||||
@@ -60,7 +60,8 @@ export default {
|
||||
});
|
||||
|
||||
this.queue = [];
|
||||
}, 5)
|
||||
}, 10),
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -192,7 +192,8 @@ export default {
|
||||
|
||||
<div v-if="openVlan">
|
||||
<LabeledInput
|
||||
v-model.number="parsedDefaultValue.vlan"
|
||||
v-model:value.number="parsedDefaultValue.vlan"
|
||||
type="number"
|
||||
class="mb-20"
|
||||
:mode="mode"
|
||||
required
|
||||
|
||||
@@ -17,12 +17,13 @@ const featuresV132 = [
|
||||
'improveMaintenanceMode',
|
||||
];
|
||||
|
||||
// TODO: change to https://github.com/harvester/dashboard/releases/tag/v1.4.0 after v1.4.0 release
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.0-rc5
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.0-rc4
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.0-rc3
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.0-rc2
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.0-rc1
|
||||
// TODO: add v1.3.3 official release note
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.3.3-dev-20250105
|
||||
const featuresV133 = [
|
||||
...featuresV132,
|
||||
];
|
||||
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.0
|
||||
const featuresV140 = [
|
||||
...featuresV132,
|
||||
'cpuPinning',
|
||||
@@ -34,9 +35,29 @@ const featuresV140 = [
|
||||
'improveMaintenanceMode',
|
||||
];
|
||||
|
||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.1
|
||||
const featuresV141 = [
|
||||
...featuresV140
|
||||
];
|
||||
|
||||
const featuresV142 = [
|
||||
...featuresV141,
|
||||
'refreshIntervalInSecond',
|
||||
'allowEmptySnapshotClassName'
|
||||
];
|
||||
|
||||
// TODO: add v1.5.0 official release note
|
||||
const featuresV150 = [
|
||||
...featuresV142
|
||||
];
|
||||
|
||||
export const RELEASE_FEATURES = {
|
||||
'v1.3.0': featuresV130,
|
||||
'v1.3.1': featuresV131,
|
||||
'v1.3.2': featuresV132,
|
||||
'v1.3.3': featuresV133,
|
||||
'v1.4.0': featuresV140,
|
||||
'v1.4.1': featuresV141,
|
||||
'v1.4.2': featuresV142,
|
||||
'v1.5.0': featuresV150
|
||||
};
|
||||
|
||||
@@ -724,7 +724,7 @@ export function init($plugin, store) {
|
||||
configureType(HCI.PCI_DEVICE, {
|
||||
isCreatable: false,
|
||||
hiddenNamespaceGroupButton: true,
|
||||
canYaml: false,
|
||||
canYaml: true,
|
||||
listGroups: [
|
||||
{
|
||||
icon: 'icon-list-grouped',
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { HCI, MANAGEMENT, CAPI } from '@shell/config/types';
|
||||
import { HARVESTER, MULTI_CLUSTER } from '@shell/store/features';
|
||||
import { allHash } from '@shell/utils/promise';
|
||||
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
||||
|
||||
export const PRODUCT_NAME = 'harvester-manager';
|
||||
|
||||
export const NAME = 'harvesterManager';
|
||||
|
||||
const harvesterClustersLocation = {
|
||||
name: 'c-cluster-product-resource',
|
||||
params: {
|
||||
cluster: BLANK_CLUSTER,
|
||||
product: NAME,
|
||||
resource: HCI.CLUSTER
|
||||
}
|
||||
};
|
||||
|
||||
export function init($plugin, store) {
|
||||
const {
|
||||
product,
|
||||
basicType,
|
||||
spoofedType,
|
||||
configureType
|
||||
} = $plugin.DSL(store, NAME);
|
||||
|
||||
product({
|
||||
ifHaveType: CAPI.RANCHER_CLUSTER,
|
||||
ifFeature: [MULTI_CLUSTER, HARVESTER],
|
||||
inStore: 'management',
|
||||
icon: 'harvester',
|
||||
removable: false,
|
||||
showClusterSwitcher: false,
|
||||
weight: 100,
|
||||
to: harvesterClustersLocation,
|
||||
category: 'hci',
|
||||
});
|
||||
|
||||
configureType(HCI.CLUSTER, { showListMasthead: false });
|
||||
|
||||
basicType([HCI.CLUSTER]);
|
||||
spoofedType({
|
||||
labelKey: 'harvesterManager.cluster.label',
|
||||
name: HCI.CLUSTER,
|
||||
type: HCI.CLUSTER,
|
||||
namespaced: false,
|
||||
weight: -1,
|
||||
route: {
|
||||
name: 'c-cluster-product-resource',
|
||||
params: {
|
||||
product: NAME,
|
||||
resource: HCI.CLUSTER,
|
||||
}
|
||||
},
|
||||
exact: false,
|
||||
schemas: [
|
||||
{
|
||||
id: HCI.CLUSTER,
|
||||
type: 'schema',
|
||||
collectionMethods: [],
|
||||
resourceFields: {},
|
||||
attributes: { namespaced: true },
|
||||
},
|
||||
],
|
||||
group: 'Root',
|
||||
getInstances: async() => {
|
||||
const hash = {
|
||||
rancherClusters: store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER }),
|
||||
clusters: store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }),
|
||||
};
|
||||
|
||||
if (store.getters['management/schemaFor'](MANAGEMENT.NODE)) {
|
||||
hash.nodes = store.dispatch('management/findAll', { type: MANAGEMENT.NODE });
|
||||
}
|
||||
|
||||
const res = await allHash(hash);
|
||||
|
||||
return res.rancherClusters.map((c) => {
|
||||
return {
|
||||
...c,
|
||||
type: HCI.CLUSTER,
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -24,35 +24,24 @@ export default {
|
||||
},
|
||||
|
||||
async fetch() {
|
||||
const hash = await allHash({
|
||||
await allHash({
|
||||
vms: this.$store.dispatch('harvester/findAll', { type: HCI.VM }),
|
||||
vmis: this.$store.dispatch('harvester/findAll', { type: HCI.VMI }),
|
||||
allClusterNetwork: this.$store.dispatch('harvester/findAll', { type: HCI.CLUSTER_NETWORK }),
|
||||
});
|
||||
const instanceMap = {};
|
||||
|
||||
(hash.vmis || []).forEach((vmi) => {
|
||||
const vmiUID = vmi?.metadata?.ownerReferences?.[0]?.uid;
|
||||
|
||||
if (vmiUID) {
|
||||
instanceMap[vmiUID] = vmi;
|
||||
}
|
||||
});
|
||||
|
||||
this.allClusterNetwork = hash.allClusterNetwork;
|
||||
this.rows = hash.vms.filter((row) => {
|
||||
return instanceMap[row.metadata?.uid]?.status?.nodeName === this.node?.metadata?.labels?.[HOSTNAME];
|
||||
});
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
rows: [],
|
||||
allClusterNetwork: []
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
allClusterNetwork() {
|
||||
return this.$store.getters['harvester/all'](HCI.CLUSTER_NETWORK);
|
||||
},
|
||||
|
||||
rows() {
|
||||
const vms = this.$store.getters['harvester/all'](HCI.VM);
|
||||
|
||||
return vms.filter((vm) => vm.vmi?.status?.nodeName === this.node?.metadata?.labels?.[HOSTNAME]);
|
||||
},
|
||||
|
||||
headers() {
|
||||
return [
|
||||
STATE,
|
||||
@@ -87,8 +76,6 @@ export default {
|
||||
];
|
||||
},
|
||||
},
|
||||
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -93,7 +93,10 @@ export default {
|
||||
</template>
|
||||
|
||||
<template #body>
|
||||
{{ t('harvester.usb.enablePassthroughWarning') }}
|
||||
<t
|
||||
k="harvester.usb.enablePassthroughWarning"
|
||||
:raw="true"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
<script>
|
||||
import merge from 'lodash/merge';
|
||||
import jsyaml from 'js-yaml';
|
||||
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||
import Tabbed from '@shell/components/Tabbed';
|
||||
import Tab from '@shell/components/Tabbed/Tab';
|
||||
import { RadioGroup } from '@components/Form/Radio';
|
||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||
|
||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
|
||||
import { STORAGE_CLASS } from '@shell/config/types';
|
||||
import { allHash } from '@shell/utils/promise';
|
||||
import { set, get, clone } from '@shell/utils/object';
|
||||
|
||||
const VALUES_YAML_KEYS = [
|
||||
'resources.requests.cpu',
|
||||
'resources.requests.memory',
|
||||
'resources.limits.cpu',
|
||||
'resources.limits.memory',
|
||||
'pvcClaim.enabled',
|
||||
'pvcClaim.size',
|
||||
'pvcClaim.storageClassName',
|
||||
];
|
||||
|
||||
const DEFAULT_VALUES = {
|
||||
'resources.requests.cpu': '0.5',
|
||||
'resources.requests.memory': '2Gi',
|
||||
'resources.limits.cpu': '2',
|
||||
'resources.limits.memory': '4Gi',
|
||||
'pvcClaim.enabled': false,
|
||||
'pvcClaim.size': '200Gi',
|
||||
'pvcClaim.storageClassName': '',
|
||||
resources: {
|
||||
requests: {
|
||||
cpu: '0.5',
|
||||
memory: '2Gi'
|
||||
},
|
||||
limits: {
|
||||
cpu: '2',
|
||||
memory: '4Gi'
|
||||
}
|
||||
},
|
||||
pvcClaim: {
|
||||
enabled: false,
|
||||
size: '200Gi',
|
||||
storageClassName: ''
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
@@ -64,19 +61,7 @@ export default {
|
||||
},
|
||||
|
||||
data() {
|
||||
let valuesObj = {};
|
||||
|
||||
try {
|
||||
valuesObj = JSON.parse(this.value?.spec?.valuesContent || '{}');
|
||||
} catch (err) {}
|
||||
|
||||
const valuesContent = clone(valuesObj);
|
||||
|
||||
VALUES_YAML_KEYS.map((key) => {
|
||||
if (!get(valuesObj, key)) {
|
||||
set(valuesContent, key, DEFAULT_VALUES[key]);
|
||||
}
|
||||
});
|
||||
const valuesContent = this.parseValuesContent();
|
||||
|
||||
return { valuesContent };
|
||||
},
|
||||
@@ -100,8 +85,21 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
parseValuesContent() {
|
||||
try {
|
||||
return merge({}, DEFAULT_VALUES, jsyaml.load(this.value.spec.valuesContent));
|
||||
} catch (err) {
|
||||
this.$store.dispatch('growl/fromError', {
|
||||
title: this.$store.getters['i18n/t']('generic.notification.title.error'),
|
||||
err: err.data || err,
|
||||
}, { root: true });
|
||||
|
||||
return DEFAULT_VALUES;
|
||||
}
|
||||
},
|
||||
|
||||
update() {
|
||||
set(this.value, 'spec.valuesContent', JSON.stringify(this.valuesContent));
|
||||
this.value.spec.valuesContent = jsyaml.dump(this.valuesContent);
|
||||
},
|
||||
|
||||
setDefaultClassName() {
|
||||
|
||||
@@ -74,7 +74,6 @@ export default {
|
||||
if (this.isCreate) {
|
||||
this.value.metadata.namespace = 'default';
|
||||
}
|
||||
|
||||
set(this.value, 'spec', this.value.spec || {});
|
||||
|
||||
const providers = PROVIDERS.map((provider) => ({
|
||||
@@ -83,14 +82,6 @@ export default {
|
||||
label: this.t(provider.labelKey)
|
||||
}));
|
||||
|
||||
if (this.mode !== _VIEW) {
|
||||
this.value['spec'] = this.value.spec || {};
|
||||
|
||||
providers.forEach((provider) => {
|
||||
this.value.spec[provider.name] = this.value.spec[provider.name] || clone(provider.default);
|
||||
});
|
||||
}
|
||||
|
||||
const selectedProviders = providers.filter((provider) => {
|
||||
const specProvider = this.value.spec[provider.name];
|
||||
const correctedSpecProvider = provider.name === 'forward' ? specProvider?.servers?.[0] || {} : specProvider;
|
||||
@@ -98,7 +89,12 @@ export default {
|
||||
return !isEmpty(correctedSpecProvider) && !isEqual(correctedSpecProvider, provider.default);
|
||||
});
|
||||
|
||||
const selectedProvider = selectedProviders?.[0]?.value || providers[0].value;
|
||||
const selectedProvider = selectedProviders?.[0]?.value || providers[0].value; // selected provider name
|
||||
const selectedProviderDefault = providers.find((p) => p.name === selectedProvider)?.default || providers[0].default;
|
||||
|
||||
if (this.mode !== _VIEW) {
|
||||
set(this.value.spec, selectedProvider, this.value.spec[selectedProvider] || clone(selectedProviderDefault));
|
||||
}
|
||||
|
||||
return {
|
||||
bufferYaml: '',
|
||||
@@ -129,6 +125,18 @@ export default {
|
||||
outputTypeOptions() {
|
||||
return OUTPUT_TYPE;
|
||||
},
|
||||
outputProvider: {
|
||||
get() {
|
||||
return this.selectedProvider;
|
||||
},
|
||||
|
||||
set(newProvider) {
|
||||
this.selectedProvider = newProvider;
|
||||
const providerDefaultSpec = this.providers.find((p) => p.name === newProvider)?.default || {};
|
||||
|
||||
this.value.spec = { [newProvider]: this.value.spec[newProvider] || clone(providerDefaultSpec) };
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
@@ -142,8 +150,6 @@ export default {
|
||||
this.$refs.tabbed.select(provider.name);
|
||||
},
|
||||
willSave() {
|
||||
this.value.spec = { [this.selectedProvider]: this.value.spec[this.selectedProvider] };
|
||||
|
||||
const bufferJson = jsyaml.load(this.bufferYaml);
|
||||
|
||||
if (!isEmpty(bufferJson)) {
|
||||
@@ -236,7 +242,7 @@ export default {
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<LabeledSelect
|
||||
v-model:value="selectedProvider"
|
||||
v-model:value="outputProvider"
|
||||
label="Output"
|
||||
:options="providers"
|
||||
:mode="mode"
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
<script>
|
||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||
import CruResource from '@shell/components/CruResource';
|
||||
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
||||
import Tab from '@shell/components/Tabbed/Tab';
|
||||
import Tabbed from '@shell/components/Tabbed';
|
||||
import { HCI, SCHEMA, CAPI, VIRTUAL_HARVESTER_PROVIDER } from '@shell/config/types';
|
||||
import ClusterMembershipEditor from '@shell/components/form/Members/ClusterMembershipEditor';
|
||||
import { Banner } from '@components/Banner';
|
||||
import Labels from '@shell/edit/provisioning.cattle.io.cluster/Labels';
|
||||
import AgentEnv from '@shell/edit/provisioning.cattle.io.cluster/AgentEnv';
|
||||
import { set, get, clone } from '@shell/utils/object';
|
||||
import { CAPI as CAPI_LABEL } from '@shell/config/labels-annotations';
|
||||
|
||||
import { createYaml } from '@shell/utils/create-yaml';
|
||||
|
||||
const REAL_TYPE = CAPI.RANCHER_CLUSTER;
|
||||
|
||||
export default {
|
||||
emits: ['input'],
|
||||
|
||||
components: {
|
||||
Banner,
|
||||
ClusterMembershipEditor,
|
||||
NameNsDescription,
|
||||
CruResource,
|
||||
Tab,
|
||||
Tabbed,
|
||||
Labels,
|
||||
AgentEnv
|
||||
},
|
||||
|
||||
mixins: [CreateEditView],
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return { membershipUpdate: {} };
|
||||
},
|
||||
|
||||
computed: {
|
||||
generateYaml() {
|
||||
return () => {
|
||||
const resource = this.value;
|
||||
|
||||
const inStore = this.$store.getters['currentStore'](resource);
|
||||
const schemas = this.$store.getters[`${ inStore }/all`](SCHEMA);
|
||||
const clonedResource = clone(resource);
|
||||
|
||||
delete clonedResource.isSpoofed;
|
||||
|
||||
const out = createYaml(schemas, REAL_TYPE, clonedResource);
|
||||
|
||||
return out;
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
done() {
|
||||
return this.$router.replace({
|
||||
name: 'c-cluster-product-resource-namespace-id',
|
||||
params: {
|
||||
resource: HCI.CLUSTER,
|
||||
namespace: this.value.metadata.namespace,
|
||||
id: this.value.metadata.name,
|
||||
},
|
||||
});
|
||||
},
|
||||
async saveOverride() {
|
||||
set(this.value, 'metadata.labels', {
|
||||
...(get(this.value, 'metadata.labels') || {}),
|
||||
[CAPI_LABEL.PROVIDER]: VIRTUAL_HARVESTER_PROVIDER,
|
||||
});
|
||||
|
||||
set(this.value, 'type', REAL_TYPE);
|
||||
|
||||
await this.save(...arguments);
|
||||
|
||||
this.value.waitForMgmt().then(() => {
|
||||
if (this.membershipUpdate.save) {
|
||||
this.membershipUpdate.save(this.value.mgmt.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
onMembershipUpdate(update) {
|
||||
this['membershipUpdate'] = update;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CruResource
|
||||
:mode="mode"
|
||||
:resource="value"
|
||||
:errors="errors"
|
||||
:validation-passed="true"
|
||||
:done-route="doneRoute"
|
||||
:generate-yaml="generateYaml"
|
||||
@finish="saveOverride"
|
||||
@error="e=>errors = e"
|
||||
>
|
||||
<Banner
|
||||
v-if="isCreate"
|
||||
color="warning"
|
||||
>
|
||||
{{ t('harvesterManager.cluster.supportMessage') }}
|
||||
</Banner>
|
||||
<div class="mt-20">
|
||||
<NameNsDescription
|
||||
v-if="!isView"
|
||||
:value="value"
|
||||
:mode="mode"
|
||||
:namespaced="false"
|
||||
name-label="cluster.name.label"
|
||||
name-placeholder="cluster.name.placeholder"
|
||||
description-label="cluster.description.label"
|
||||
description-placeholder="cluster.description.placeholder"
|
||||
@update:value="$emit('input', $event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Tabbed :side-tabs="true">
|
||||
<Tab
|
||||
name="memberRoles"
|
||||
label-key="cluster.tabs.memberRoles"
|
||||
:weight="3"
|
||||
>
|
||||
<Banner
|
||||
v-if="isEdit"
|
||||
color="info"
|
||||
>
|
||||
{{ t('cluster.memberRoles.removeMessage') }}
|
||||
</Banner>
|
||||
<ClusterMembershipEditor
|
||||
:mode="mode"
|
||||
:parent-id="value.mgmt ? value.mgmt.id : null"
|
||||
@membership-update="onMembershipUpdate"
|
||||
/>
|
||||
</Tab>
|
||||
<AgentEnv
|
||||
:value="value"
|
||||
:mode="mode"
|
||||
@update:value="$emit('input', $event)"
|
||||
/>
|
||||
<Labels
|
||||
:value="value"
|
||||
:mode="mode"
|
||||
@update:value="$emit('input', $event)"
|
||||
/>
|
||||
</Tabbed>
|
||||
</CruResource>
|
||||
</template>
|
||||
@@ -10,17 +10,6 @@ import { clone } from '@shell/utils/object';
|
||||
import { uniq } from '@shell/utils/array';
|
||||
import { DATA_ENGINE_V1 } from '../../../models/harvester/persistentvolumeclaim';
|
||||
|
||||
// UI components for Longhorn storage class parameters
|
||||
const DEFAULT_PARAMETERS = [
|
||||
'numberOfReplicas',
|
||||
'staleReplicaTimeout',
|
||||
'diskSelector',
|
||||
'nodeSelector',
|
||||
'migratable',
|
||||
'encrypted',
|
||||
'dataEngine',
|
||||
];
|
||||
|
||||
const {
|
||||
CSI_PROVISIONER_SECRET_NAME,
|
||||
CSI_PROVISIONER_SECRET_NAMESPACE,
|
||||
@@ -141,11 +130,17 @@ export default {
|
||||
get() {
|
||||
const parameters = clone(this.value?.parameters) || {};
|
||||
|
||||
DEFAULT_PARAMETERS.forEach((key) => {
|
||||
delete parameters[key];
|
||||
});
|
||||
// UI components for Longhorn storage class parameters
|
||||
const defaultParameters = [
|
||||
'numberOfReplicas',
|
||||
'staleReplicaTimeout',
|
||||
'diskSelector',
|
||||
'nodeSelector',
|
||||
'migratable',
|
||||
...(this.value.volumeEncryptionFeatureEnabled ? ['encrypted', 'dataEngine'] : []),
|
||||
];
|
||||
|
||||
Object.values(CSI_SECRETS).forEach((key) => {
|
||||
[...defaultParameters, ...Object.values(CSI_SECRETS)].forEach((key) => {
|
||||
delete parameters[key];
|
||||
});
|
||||
|
||||
@@ -311,16 +306,16 @@ export default {
|
||||
</LabeledSelect>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-20">
|
||||
<RadioGroup
|
||||
v-model:value="value.parameters.migratable"
|
||||
name="layer3NetworkMode"
|
||||
:label="t('harvester.storage.parameters.migratable.label')"
|
||||
:mode="mode"
|
||||
:options="migratableOptions"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="value.volumeEncryptionFeatureEnabled">
|
||||
<div class="row mt-20">
|
||||
<RadioGroup
|
||||
v-model:value="value.parameters.migratable"
|
||||
name="layer3NetworkMode"
|
||||
:label="t('harvester.storage.parameters.migratable.label')"
|
||||
:mode="mode"
|
||||
:options="migratableOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="row mt-20">
|
||||
<RadioGroup
|
||||
v-model:value="volumeEncryption"
|
||||
|
||||
@@ -245,6 +245,8 @@ export default {
|
||||
async saveImage(buttonCb) {
|
||||
this.value.spec.displayName = (this.value.spec.displayName || '').trim();
|
||||
|
||||
if (this.isEdit) return await this.handleEditImage(buttonCb);
|
||||
|
||||
if (this.value.spec.sourceType === UPLOAD && this.isCreate) {
|
||||
try {
|
||||
this.value.spec.url = '';
|
||||
@@ -269,6 +271,23 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
async handleEditImage(buttonCb) {
|
||||
try {
|
||||
const data = [{
|
||||
op: 'replace', path: '/metadata/labels', value: this.value.metadata.labels
|
||||
}, {
|
||||
op: 'replace', path: '/metadata/annotations', value: this.value.metadata.annotations
|
||||
}];
|
||||
|
||||
await this.value.patch(data);
|
||||
buttonCb(true);
|
||||
this.done();
|
||||
} catch (e) {
|
||||
this.errors = exceptionToErrorsArray(e);
|
||||
buttonCb(false);
|
||||
}
|
||||
},
|
||||
|
||||
setImageLabels(str) {
|
||||
const suffixName = str?.split('/')?.pop() || str;
|
||||
|
||||
@@ -530,6 +549,7 @@ export default {
|
||||
:mode="mode"
|
||||
:pad-left="false"
|
||||
:read-allowed="false"
|
||||
:value-can-be-empty="true"
|
||||
@focusKey="focusKey"
|
||||
@update:value="value.setLabels($event)"
|
||||
>
|
||||
@@ -552,7 +572,7 @@ export default {
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
spellcheck="false"
|
||||
@update:value="queueUpdate"
|
||||
@input="queueUpdate"
|
||||
/>
|
||||
</template>
|
||||
</KeyValue>
|
||||
|
||||
@@ -29,7 +29,7 @@ import SSHKey from './kubevirt.io.virtualmachine/VirtualMachineSSHKey';
|
||||
export default {
|
||||
name: 'HarvesterEditVMTemplate',
|
||||
|
||||
emits: ['update:value'],
|
||||
emits: ['update:templateValue'],
|
||||
|
||||
components: {
|
||||
Tab,
|
||||
@@ -205,7 +205,7 @@ export default {
|
||||
if (tab.name === 'advanced') {
|
||||
this.$refs.yamlEditor?.refresh();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -222,11 +222,11 @@ export default {
|
||||
@finish="saveVMT"
|
||||
>
|
||||
<NameNsDescription
|
||||
:value="value"
|
||||
:value="templateValue"
|
||||
:mode="realTemplateMode"
|
||||
name-label="harvester.vmTemplate.nameNsDescription.name"
|
||||
:namespaced="true"
|
||||
@update:value="$emit('update:value', $event)"
|
||||
@update:value="$emit('update:templateValue', $event)"
|
||||
/>
|
||||
|
||||
<Checkbox
|
||||
|
||||
+5
-1
@@ -95,7 +95,11 @@ export default {
|
||||
devices: {
|
||||
handler(v) {
|
||||
this.rows = v;
|
||||
this.filterRows = this.rows;
|
||||
if (this.parentSriov) {
|
||||
this.filterRows = this.rows.filter((row) => row.labels[this.parentSriovLabel] === this.parentSriov);
|
||||
} else {
|
||||
this.filterRows = this.rows;
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { Sortable } from 'sortablejs-vue3';
|
||||
import { VueDraggableNext } from 'vue-draggable-next';
|
||||
import InfoBox from '@shell/components/InfoBox';
|
||||
import { Banner } from '@components/Banner';
|
||||
import BadgeStateFormatter from '@shell/components/formatter/BadgeStateFormatter';
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
emits: ['update:value'],
|
||||
|
||||
components: {
|
||||
Banner, BadgeStateFormatter, Sortable, InfoBox, LabeledInput, UnitInput, LabeledSelect, ModalWithCard
|
||||
Banner, BadgeStateFormatter, VueDraggableNext, InfoBox, LabeledInput, UnitInput, LabeledSelect, ModalWithCard
|
||||
},
|
||||
|
||||
props: {
|
||||
@@ -272,129 +272,130 @@ export default {
|
||||
color="info"
|
||||
label-key="harvester.virtualMachine.volume.dragTip"
|
||||
/>
|
||||
<Sortable
|
||||
<VueDraggableNext
|
||||
:list="rows"
|
||||
:options="{disabled: isView}"
|
||||
:disabled="isView"
|
||||
item-key="id"
|
||||
@end="update"
|
||||
>
|
||||
<template #item="{element: volume, index: i}">
|
||||
<div :key="volume.name">
|
||||
<InfoBox class="box">
|
||||
<button
|
||||
<div
|
||||
v-for="(volume, i) in rows"
|
||||
:key="volume.id"
|
||||
>
|
||||
<InfoBox class="box">
|
||||
<button
|
||||
v-if="!isView"
|
||||
type="button"
|
||||
class="role-link btn btn-sm remove"
|
||||
@click="removeVolume(volume)"
|
||||
>
|
||||
<i class="icon icon-x" />
|
||||
</button>
|
||||
<button
|
||||
v-if="volume.hotpluggable && isView"
|
||||
type="button"
|
||||
class="role-link btn remove"
|
||||
@click="unplugVolume(volume)"
|
||||
>
|
||||
{{ t('harvester.virtualMachine.unplug.detachVolume') }}
|
||||
</button>
|
||||
<h3>
|
||||
<span
|
||||
v-if="volume.to && isVirtualType"
|
||||
class="title"
|
||||
>
|
||||
<router-link :to="volume.to">
|
||||
{{ t('harvester.virtualMachine.volume.edit') }} {{ headerFor(volume.source) }}
|
||||
</router-link>
|
||||
|
||||
<BadgeStateFormatter
|
||||
v-if="volume.pvc"
|
||||
class="ml-10 state"
|
||||
:arbitrary="true"
|
||||
:row="volume.pvc"
|
||||
:value="volume.pvc.state"
|
||||
/>
|
||||
<a
|
||||
v-if="dev && !!volume.pvc && !!volume.pvc.resourceExternalLink"
|
||||
v-clean-tooltip="t(volume.pvc.resourceExternalLink.tipsKey || 'generic.resourceExternalLinkTips')"
|
||||
class="ml-5 resource-external"
|
||||
rel="nofollow noopener noreferrer"
|
||||
target="_blank"
|
||||
:href="volume.pvc.resourceExternalLink.url"
|
||||
>
|
||||
<i class="icon icon-external-link" />
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
{{ headerFor(volume.source, !!volume?.volumeBackups) }}
|
||||
</span>
|
||||
</h3>
|
||||
<div>
|
||||
<component
|
||||
:is="componentFor(volume.source)"
|
||||
:value="rows[i]"
|
||||
:rows="rows"
|
||||
:namespace="namespace"
|
||||
:is-create="isCreate"
|
||||
:is-edit="isEdit"
|
||||
:is-view="isView"
|
||||
:is-virtual-type="isVirtualType"
|
||||
:mode="mode"
|
||||
:idx="i"
|
||||
:validate-required="validateRequired"
|
||||
@update="update"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="bootOrder">
|
||||
<div
|
||||
v-if="!isView"
|
||||
type="button"
|
||||
class="role-link btn btn-sm remove"
|
||||
@click="removeVolume(volume)"
|
||||
class="mr-15"
|
||||
>
|
||||
<i class="icon icon-x" />
|
||||
</button>
|
||||
<button
|
||||
v-if="volume.hotpluggable && isView"
|
||||
type="button"
|
||||
class="role-link btn remove"
|
||||
@click="unplugVolume(volume)"
|
||||
>
|
||||
{{ t('harvester.virtualMachine.unplug.detachVolume') }}
|
||||
</button>
|
||||
<h3>
|
||||
<span
|
||||
v-if="volume.to && isVirtualType"
|
||||
class="title"
|
||||
<button
|
||||
:disabled="i === 0"
|
||||
class="btn btn-sm role-primary"
|
||||
@click.prevent="changeSort(i, false)"
|
||||
>
|
||||
<router-link :to="volume.to">
|
||||
{{ t('harvester.virtualMachine.volume.edit') }} {{ headerFor(volume.source) }}
|
||||
</router-link>
|
||||
<i class="icon icon-lg icon-chevron-up"></i>
|
||||
</button>
|
||||
|
||||
<BadgeStateFormatter
|
||||
v-if="volume.pvc"
|
||||
class="ml-10 state"
|
||||
:arbitrary="true"
|
||||
:row="volume.pvc"
|
||||
:value="volume.pvc.state"
|
||||
/>
|
||||
<a
|
||||
v-if="dev && !!volume.pvc && !!volume.pvc.resourceExternalLink"
|
||||
v-clean-tooltip="t(volume.pvc.resourceExternalLink.tipsKey || 'generic.resourceExternalLinkTips')"
|
||||
class="ml-5 resource-external"
|
||||
rel="nofollow noopener noreferrer"
|
||||
target="_blank"
|
||||
:href="volume.pvc.resourceExternalLink.url"
|
||||
>
|
||||
<i class="icon icon-external-link" />
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
{{ headerFor(volume.source, !!volume?.volumeBackups) }}
|
||||
</span>
|
||||
</h3>
|
||||
<div>
|
||||
<component
|
||||
:is="componentFor(volume.source)"
|
||||
:value="rows[i]"
|
||||
:rows="rows"
|
||||
:namespace="namespace"
|
||||
:is-create="isCreate"
|
||||
:is-edit="isEdit"
|
||||
:is-view="isView"
|
||||
:is-virtual-type="isVirtualType"
|
||||
:mode="mode"
|
||||
:idx="i"
|
||||
:validate-required="validateRequired"
|
||||
@update="update"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="bootOrder">
|
||||
<div
|
||||
v-if="!isView"
|
||||
class="mr-15"
|
||||
<button
|
||||
:disabled="i === rows.length -1"
|
||||
class="btn btn-sm role-primary"
|
||||
@click.prevent="changeSort(i, true)"
|
||||
>
|
||||
<button
|
||||
:disabled="i === 0"
|
||||
class="btn btn-sm role-primary"
|
||||
@click.prevent="changeSort(i, false)"
|
||||
>
|
||||
<i class="icon icon-lg icon-chevron-up"></i>
|
||||
</button>
|
||||
|
||||
<button
|
||||
:disabled="i === rows.length -1"
|
||||
class="btn btn-sm role-primary"
|
||||
@click.prevent="changeSort(i, true)"
|
||||
>
|
||||
<i class="icon icon-lg icon-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-muted">
|
||||
bootOrder: {{ i + 1 }}
|
||||
</div>
|
||||
<i class="icon icon-lg icon-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-15">
|
||||
<Banner
|
||||
v-if="volume.volumeStatus && !isCreate"
|
||||
class="volume-status"
|
||||
color="warning"
|
||||
:label="ucFirst(volume.volumeStatus)"
|
||||
/>
|
||||
<Banner
|
||||
v-if="value.volumeBackups && value.volumeBackups.error && value.volumeBackups.error.message"
|
||||
color="error"
|
||||
:label="ucFirst(value.volumeBackups.error.message)"
|
||||
/>
|
||||
<Banner
|
||||
v-if="isLonghornV2(volume) && !isView"
|
||||
color="warning"
|
||||
:label="t('harvester.volume.longhorn.disableResize')"
|
||||
/>
|
||||
<div class="text-muted">
|
||||
bootOrder: {{ i + 1 }}
|
||||
</div>
|
||||
</InfoBox>
|
||||
</div>
|
||||
</template>
|
||||
</Sortable>
|
||||
</div>
|
||||
|
||||
<div class="mt-15">
|
||||
<Banner
|
||||
v-if="volume.volumeStatus && !isCreate"
|
||||
class="volume-status"
|
||||
color="warning"
|
||||
:label="ucFirst(volume.volumeStatus)"
|
||||
/>
|
||||
<Banner
|
||||
v-if="value.volumeBackups && value.volumeBackups.error && value.volumeBackups.error.message"
|
||||
color="error"
|
||||
:label="ucFirst(value.volumeBackups.error.message)"
|
||||
/>
|
||||
<Banner
|
||||
v-if="isLonghornV2(volume) && !isView"
|
||||
color="warning"
|
||||
:label="t('harvester.volume.longhorn.disableResize')"
|
||||
/>
|
||||
</div>
|
||||
</InfoBox>
|
||||
</div>
|
||||
</VueDraggableNext>
|
||||
<Banner
|
||||
v-if="showVolumeTip"
|
||||
color="warning"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -72,17 +72,23 @@ export default {
|
||||
return stats;
|
||||
},
|
||||
|
||||
units() {
|
||||
allocatedUnits() {
|
||||
const exponent = exponentNeeded(this.storageStats.total, 1024);
|
||||
|
||||
return `${ UNITS[exponent] }iB`;
|
||||
},
|
||||
|
||||
usedUnits() {
|
||||
const exponent = exponentNeeded(this.storageStats.maximum, 1024);
|
||||
|
||||
return `${ UNITS[exponent] }iB`;
|
||||
},
|
||||
|
||||
used() {
|
||||
formatUsed() {
|
||||
let out = this.formatter(this.storageStats.used);
|
||||
|
||||
if (!Number.parseFloat(out) > 0) {
|
||||
out = this.formatter(this.storageStats.used, { canRoundToZero: false });
|
||||
out = this.formatter(this.storageStats.used, { canRoundToZero: true });
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -92,7 +98,7 @@ export default {
|
||||
let out = this.formatter(this.storageStats.scheduled);
|
||||
|
||||
if (!Number.parseFloat(out) > 0) {
|
||||
out = this.formatter(this.storageStats.scheduled, { canRoundToZero: false });
|
||||
out = this.formatter(this.storageStats.scheduled, { canRoundToZero: true });
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -100,9 +106,9 @@ export default {
|
||||
|
||||
usedAmountTemplateValues() {
|
||||
return {
|
||||
used: this.used,
|
||||
used: this.formatUsed,
|
||||
total: this.formatter(this.storageStats.maximum),
|
||||
unit: this.units,
|
||||
unit: this.usedUnits,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -110,7 +116,7 @@ export default {
|
||||
return {
|
||||
used: this.formatAllocated,
|
||||
total: this.formatter(this.storageStats.total),
|
||||
unit: this.units,
|
||||
unit: this.allocatedUnits,
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -141,7 +147,7 @@ export default {
|
||||
<ConsumptionGauge
|
||||
:capacity="storageStats.total"
|
||||
:used="storageStats.scheduled"
|
||||
:units="units"
|
||||
:units="allocatedUnits"
|
||||
:number-formatter="formatter"
|
||||
:resource-name="resourceName"
|
||||
>
|
||||
@@ -161,7 +167,7 @@ export default {
|
||||
<ConsumptionGauge
|
||||
:capacity="storageStats.maximum"
|
||||
:used="storageStats.used"
|
||||
:units="units"
|
||||
:units="usedUnits"
|
||||
:number-formatter="formatter"
|
||||
:resource-name="showAllocated ? '' : resourceName"
|
||||
:class="{
|
||||
|
||||
@@ -20,10 +20,6 @@ export default function (plugin: IPlugin) {
|
||||
|
||||
// Built-in icon
|
||||
plugin.metadata.icon = require('./icon.svg');
|
||||
|
||||
if (isDev && !isSingleVirtualCluster) {
|
||||
plugin.addProduct(require('./config/harvester-manager'));
|
||||
}
|
||||
|
||||
plugin.addProduct(require('./config/harvester-cluster'));
|
||||
|
||||
|
||||
@@ -1,34 +1,3 @@
|
||||
harvesterManager:
|
||||
manage: Manage
|
||||
tableHeaders:
|
||||
kubernetesVersion: Kubernetes Version
|
||||
harvesterVersion: Harvester Version
|
||||
cluster:
|
||||
label: Harvester Clusters
|
||||
none: There are no Harvester Clusters
|
||||
learnMore: Learn more about Harvester from the <a target="_blank" href="https://harvesterhci.io/" rel="noopener noreferrer nofollow">Harvester Web Site</a> or read the the <a target="_blank" href="https://docs.harvesterhci.io/" rel="noopener noreferrer nofollow">Harvester Docs</a>
|
||||
description: Harvester is a modern Hyperconverged infrastructure (HCI) solution built for bare metal servers using enterprise-grade open source technologies including Kubernetes, Kubevirt and Longhorn.
|
||||
supportMessage: Harvester ui extension only supports Harvester cluster version greater or equal to 1.3.0
|
||||
plugins:
|
||||
loadError: Error loading harvester plugin
|
||||
rke:
|
||||
templateError: Incorrect template format
|
||||
affinity:
|
||||
thisPodNamespace: This VM's namespace
|
||||
matchExpressions:
|
||||
inNamespaces: "Workloads in these namespaces"
|
||||
vmAffinityTitle: VM Scheduling
|
||||
namespaces:
|
||||
placeholder: e.g. default,system,base
|
||||
label: Namespaces
|
||||
addLabel: Add Workload Selector
|
||||
topologyKey:
|
||||
placeholder: 'topology.kubernetes.io/zone'
|
||||
vGpu:
|
||||
title: VGPUs
|
||||
label: VGPU type
|
||||
placeholder: 'Please select a VGPU'
|
||||
|
||||
generic:
|
||||
tip: Tip
|
||||
resourceExternalLinkTips: 'External Link'
|
||||
@@ -39,6 +8,11 @@ generic:
|
||||
basic: Basic
|
||||
loading: Loading...
|
||||
|
||||
unsupported:
|
||||
serverVersion: 'Current version: <code>{serverVersion}</code>'
|
||||
description: Harvester ui only supports Harvester cluster version greater or equal to 1.3.0.
|
||||
learnMore: Learn more about Harvester from the <a target="_blank" href="https://harvesterhci.io/" rel="noopener noreferrer nofollow">Harvester Web Site</a> or read the <a target="_blank" href="https://docs.harvesterhci.io/" rel="noopener noreferrer nofollow">Harvester Docs</a>
|
||||
|
||||
nav:
|
||||
group:
|
||||
networks: Networks
|
||||
@@ -65,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:
|
||||
@@ -768,6 +747,9 @@ harvester:
|
||||
terminationGracePeriodSeconds:
|
||||
label: Termination Grace Period
|
||||
affinity:
|
||||
addLabel: Add Workload Selector
|
||||
topologyKey:
|
||||
placeholder: 'topology.kubernetes.io/zone'
|
||||
thisPodNamespace: This virtual machine's namespace
|
||||
matchExpressions:
|
||||
inNamespaces: "Workloads in these namespaces"
|
||||
@@ -920,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:
|
||||
@@ -1520,17 +1505,13 @@ harvester:
|
||||
pollingInterval:
|
||||
label: Polling Interval
|
||||
|
||||
affinity:
|
||||
thisPodNamespace: This virtual machine's namespace
|
||||
matchExpressions:
|
||||
inNamespaces: "Workloads in these namespaces"
|
||||
vmAffinityTitle: Virtual Machine Scheduling
|
||||
namespaces:
|
||||
placeholder: e.g. default,system,base
|
||||
label: Namespaces
|
||||
addLabel: Add Workload Selector
|
||||
topologyKey:
|
||||
placeholder: 'topology.kubernetes.io/zone'
|
||||
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'
|
||||
|
||||
@@ -12,6 +12,8 @@ import { HCI } from '../types';
|
||||
export default {
|
||||
name: 'ListSriovGpuDevices',
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
components: {
|
||||
Banner,
|
||||
Loading,
|
||||
|
||||
@@ -10,6 +10,8 @@ import DeviceList from '../edit/kubevirt.io.virtualmachine/VirtualMachineUSBDevi
|
||||
export default {
|
||||
name: 'ListUsbDevicePage',
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
components: {
|
||||
Banner,
|
||||
DeviceList,
|
||||
|
||||
@@ -10,6 +10,8 @@ import { ADD_ONS } from '../config/harvester-map';
|
||||
export default {
|
||||
name: 'ListVGpuDevices',
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
components: {
|
||||
Banner,
|
||||
Loading,
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
<script>
|
||||
import BrandImage from '@shell/components/BrandImage';
|
||||
import TypeDescription from '@shell/components/TypeDescription';
|
||||
import ResourceTable from '@shell/components/ResourceTable';
|
||||
import Masthead from '@shell/components/ResourceList/Masthead';
|
||||
import Loading from '@shell/components/Loading';
|
||||
import { HARVESTER_NAME as VIRTUAL } from '@shell/config/features';
|
||||
import { CAPI, HCI, MANAGEMENT } from '@shell/config/types';
|
||||
import { isHarvesterCluster } from '@shell/utils/cluster';
|
||||
import { allHash } from '@shell/utils/promise';
|
||||
import { STATE, NAME as NAME_COL, AGE, VERSION } from '@shell/config/table-headers';
|
||||
import { MACHINE_POOLS } from '../config/table-headers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BrandImage,
|
||||
ResourceTable,
|
||||
Masthead,
|
||||
TypeDescription,
|
||||
Loading
|
||||
},
|
||||
|
||||
props: {
|
||||
schema: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
useQueryParamsForSimpleFiltering: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
async fetch() {
|
||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||
const hash = await allHash({
|
||||
hciClusters: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.CLUSTER }),
|
||||
mgmtClusters: this.$store.dispatch(`${ inStore }/findAll`, { type: MANAGEMENT.CLUSTER })
|
||||
});
|
||||
|
||||
this.hciClusters = hash.hciClusters;
|
||||
this.mgmtClusters = hash.mgmtClusters;
|
||||
},
|
||||
|
||||
data() {
|
||||
const resource = CAPI.RANCHER_CLUSTER;
|
||||
|
||||
return {
|
||||
navigating: false,
|
||||
VIRTUAL,
|
||||
hciDashboard: HCI.DASHBOARD,
|
||||
resource,
|
||||
hResource: HCI.CLUSTER,
|
||||
realSchema: this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER),
|
||||
hciClusters: [],
|
||||
mgmtClusters: []
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
headers() {
|
||||
return [
|
||||
STATE,
|
||||
NAME_COL,
|
||||
{
|
||||
name: 'harvesterVersion',
|
||||
sort: 'harvesterVersion',
|
||||
labelKey: 'harvesterManager.tableHeaders.harvesterVersion',
|
||||
value: 'harvesterVersion',
|
||||
getValue: (row) => row.harvesterVersion
|
||||
},
|
||||
{
|
||||
...VERSION,
|
||||
labelKey: 'harvesterManager.tableHeaders.kubernetesVersion',
|
||||
value: 'kubernetesVersion',
|
||||
getValue: (row) => row.kubernetesVersion
|
||||
},
|
||||
MACHINE_POOLS,
|
||||
AGE,
|
||||
{
|
||||
name: 'harvester',
|
||||
label: ' ',
|
||||
align: 'right',
|
||||
width: 65,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
importLocation() {
|
||||
return {
|
||||
name: 'c-cluster-product-resource-create',
|
||||
params: {
|
||||
product: this.$store.getters['currentProduct'].name,
|
||||
resource: this.schema.id,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
canCreateCluster() {
|
||||
const schema = this.$store.getters['management/schemaFor'](CAPI.RANCHER_CLUSTER);
|
||||
|
||||
return !!schema?.collectionMethods.find((x) => x.toLowerCase() === 'post');
|
||||
},
|
||||
|
||||
rows() {
|
||||
return this.hciClusters
|
||||
.filter((c) => {
|
||||
const cluster = this.mgmtClusters.find((cluster) => cluster?.metadata?.name === c?.status?.clusterName);
|
||||
|
||||
return isHarvesterCluster(cluster);
|
||||
})
|
||||
.map((row) => {
|
||||
if (row.isReady) {
|
||||
row.setSupportedHarvesterVersion();
|
||||
}
|
||||
|
||||
return row;
|
||||
});
|
||||
},
|
||||
|
||||
typeDisplay() {
|
||||
return this.t(`typeLabel."${ HCI.CLUSTER }"`, { count: this.rows?.length || 0 });
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
async goToCluster(row) {
|
||||
const timeout = setTimeout(() => {
|
||||
// Don't show loading indicator for quickly fetched plugins
|
||||
this.navigating = row.id;
|
||||
}, 1000);
|
||||
|
||||
try {
|
||||
await row.goToCluster();
|
||||
|
||||
clearTimeout(timeout);
|
||||
this.navigating = false;
|
||||
} catch {
|
||||
// The error handling is carried out within goToCluster, but just in case something happens before the promise chain can catch it...
|
||||
clearTimeout(timeout);
|
||||
this.navigating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Loading v-if="$fetchState.pending" />
|
||||
<div v-else>
|
||||
<Masthead
|
||||
:schema="realSchema"
|
||||
:resource="resource"
|
||||
:is-creatable="false"
|
||||
:type-display="typeDisplay"
|
||||
>
|
||||
<template #typeDescription>
|
||||
<TypeDescription :resource="hResource" />
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-if="canCreateCluster"
|
||||
#extraActions
|
||||
>
|
||||
<router-link
|
||||
:to="importLocation"
|
||||
class="btn role-primary"
|
||||
>
|
||||
{{ t('cluster.importAction') }}
|
||||
</router-link>
|
||||
</template>
|
||||
</Masthead>
|
||||
|
||||
<ResourceTable
|
||||
v-if="rows && rows.length"
|
||||
:schema="schema"
|
||||
:headers="headers"
|
||||
:rows="rows"
|
||||
:is-creatable="true"
|
||||
:namespaced="false"
|
||||
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
||||
>
|
||||
<template #col:name="{row}">
|
||||
<td>
|
||||
<span class="cluster-link">
|
||||
<a
|
||||
v-if="row.isReady && row.isSupportedHarvester"
|
||||
class="link"
|
||||
:disabled="navigating ? true : null"
|
||||
@click="goToCluster(row)"
|
||||
>{{ row.nameDisplay }}</a>
|
||||
<span v-else>
|
||||
{{ row.nameDisplay }}
|
||||
</span>
|
||||
<i
|
||||
class="icon icon-spinner icon-spin ml-5"
|
||||
:class="{'navigating': navigating === row.id}"
|
||||
/>
|
||||
</span>
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<template #cell:harvester="{row}">
|
||||
<router-link
|
||||
class="btn btn-sm role-primary"
|
||||
:to="row.detailLocation"
|
||||
>
|
||||
{{ t('harvesterManager.manage') }}
|
||||
</router-link>
|
||||
</template>
|
||||
</ResourceTable>
|
||||
<div v-else>
|
||||
<div class="no-clusters">
|
||||
{{ t('harvesterManager.cluster.none') }}
|
||||
</div>
|
||||
<hr class="info-section">
|
||||
<div class="logo">
|
||||
<BrandImage
|
||||
file-name="harvester.png"
|
||||
height="64"
|
||||
/>
|
||||
</div>
|
||||
<div class="tagline">
|
||||
<div>{{ t('harvesterManager.cluster.description') }}</div>
|
||||
</div>
|
||||
<div class="tagline sub-tagline">
|
||||
<div v-clean-html="t('harvesterManager.cluster.learnMore', {}, true)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cluster-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
// Use visibility to avoid the columns re-adjusting when the icon is shown
|
||||
visibility: hidden;
|
||||
|
||||
&.navigating {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.no-clusters {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 60px 0 40px 0;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
|
||||
> div {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
max-width: 80%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -282,14 +282,14 @@ export default {
|
||||
|
||||
affinityLabels() {
|
||||
return {
|
||||
namespaceInputLabel: this.t('harvesterManager.affinity.namespaces.label'),
|
||||
namespaceInputLabel: this.t('harvester.virtualMachine.affinity.namespaces.label'),
|
||||
namespaceSelectionLabels: [
|
||||
this.t('harvesterManager.affinity.thisPodNamespace'),
|
||||
this.t('harvester.virtualMachine.affinity.thisPodNamespace'),
|
||||
this.t('workload.scheduling.affinity.allNamespaces'),
|
||||
this.t('harvesterManager.affinity.matchExpressions.inNamespaces')
|
||||
this.t('harvester.virtualMachine.affinity.matchExpressions.inNamespaces')
|
||||
],
|
||||
addLabel: this.t('harvesterManager.affinity.addLabel'),
|
||||
topologyKeyPlaceholder: this.t('harvesterManager.affinity.topologyKey.placeholder')
|
||||
addLabel: this.t('harvester.virtualMachine.affinity.addLabel'),
|
||||
topologyKeyPlaceholder: this.t('harvester.virtualMachine.affinity.topologyKey.placeholder')
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
import ProvCluster from '@shell/models/provisioning.cattle.io.cluster';
|
||||
import { DEFAULT_WORKSPACE, HCI, MANAGEMENT } from '@shell/config/types';
|
||||
import { HARVESTER_NAME, HARVESTER_NAME as VIRTUAL } from '@shell/config/features';
|
||||
import { SETTING } from '@shell/config/settings';
|
||||
import { colorForState, stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
||||
|
||||
export default class HciCluster extends ProvCluster {
|
||||
get isSupportedHarvester() {
|
||||
return this._isSupportedHarvester === undefined ? true : this._isSupportedHarvester;
|
||||
}
|
||||
|
||||
get harvesterVersion() {
|
||||
return this._harvesterVersion;
|
||||
}
|
||||
|
||||
get stateObj() {
|
||||
if (!this.isSupportedHarvester) {
|
||||
return { error: true, message: this.t('harvesterManager.cluster.supportMessage') };
|
||||
}
|
||||
|
||||
return this._stateObj;
|
||||
}
|
||||
|
||||
applyDefaults() {
|
||||
if ( !this.spec ) {
|
||||
this['spec'] = { agentEnvVars: [] };
|
||||
this['metadata'] = { namespace: DEFAULT_WORKSPACE };
|
||||
}
|
||||
}
|
||||
|
||||
get isReady() {
|
||||
// If the Connected condition exists, use that (2.6+)
|
||||
if ( this.hasCondition('Connected') ) {
|
||||
return this.isCondition('Connected');
|
||||
}
|
||||
|
||||
// Otherwise use Ready (older)
|
||||
return this.isCondition('Ready');
|
||||
}
|
||||
|
||||
get canEdit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get stateColor() {
|
||||
if (!this.isSupportedHarvester) {
|
||||
return colorForState(STATES_ENUM.DENIED);
|
||||
}
|
||||
|
||||
return colorForState(this.state);
|
||||
}
|
||||
|
||||
get stateDisplay() {
|
||||
if (!this.isSupportedHarvester) {
|
||||
return stateDisplay(STATES_ENUM.DENIED);
|
||||
}
|
||||
|
||||
return stateDisplay(this.state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and cache the response for /ui-info
|
||||
*
|
||||
* Storing this in a cache means any changes to `ui-info` require a dashboard refresh... but it cuts out a http request every time we
|
||||
* go to a cluster
|
||||
*
|
||||
* @param {string} clusterId
|
||||
*/
|
||||
async _getUiInfo(clusterId) {
|
||||
if (!this._uiInfo) {
|
||||
try {
|
||||
const infoUrl = `/k8s/clusters/${ clusterId }/v1/harvester/ui-info`;
|
||||
|
||||
this._uiInfo = await this.$dispatch('request', { url: infoUrl });
|
||||
} catch (e) {
|
||||
console.info(`Failed to fetch harvester ui-info from ${ this.nameDisplay }, this may be an older cluster that cannot provide one`); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
return this._uiInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the harvester plugin's package name and url for legacy clusters that don't provide the package (i.e. it's coming from
|
||||
* outside the cluster)
|
||||
*/
|
||||
_legacyClusterPkgDetails() {
|
||||
let uiOfflinePreferred = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_OFFLINE_PREFERRED)?.value;
|
||||
// options: ['dynamic', 'true', 'false']
|
||||
|
||||
if (uiOfflinePreferred === 'dynamic') {
|
||||
// We shouldn't need to worry about the version of the dashboard when embedded in harvester (aka in isSingleProduct)
|
||||
const version = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.VERSION_RANCHER)?.value;
|
||||
|
||||
if (version.endsWith('-head')) {
|
||||
uiOfflinePreferred = 'false';
|
||||
} else {
|
||||
uiOfflinePreferred = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
// This is the version that's embedded in the dashboard
|
||||
const pkgName = `${ HARVESTER_NAME }-1.0.3`;
|
||||
|
||||
if (uiOfflinePreferred === 'true') {
|
||||
// Embedded (aka give me the embedded plugin that was in the last rancher release)
|
||||
const embeddedPath = `${ pkgName }/${ pkgName }.umd.min.js`;
|
||||
|
||||
return {
|
||||
pkgUrl: process.env.dev ? `${ process.env.api }/dashboard/${ embeddedPath }` : embeddedPath,
|
||||
pkgName
|
||||
};
|
||||
}
|
||||
|
||||
if (uiOfflinePreferred === 'false') {
|
||||
// Remote (aka give me the latest version of the embedded plugin that might not have been released yet)
|
||||
const uiDashboardHarvesterRemotePlugin = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_DASHBOARD_HARVESTER_LEGACY_PLUGIN)?.value;
|
||||
const parts = uiDashboardHarvesterRemotePlugin?.replace('.umd.min.js', '').split('/');
|
||||
const pkgNameFromUrl = parts?.length > 1 ? parts[parts.length - 1] : null;
|
||||
|
||||
if (!pkgNameFromUrl) {
|
||||
throw new Error(`Unable to determine harvester plugin name from '${ uiDashboardHarvesterRemotePlugin }'`);
|
||||
}
|
||||
|
||||
return {
|
||||
pkgUrl: uiDashboardHarvesterRemotePlugin,
|
||||
pkgName: pkgNameFromUrl
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported value for ${ SETTING.UI_OFFLINE_PREFERRED }: 'uiOfflinePreferred'`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the harvester plugin's package name and url for clusters that provide the plugin
|
||||
*/
|
||||
_supportedClusterPkgDetails(uiInfo, clusterId) {
|
||||
let pkgName = `${ HARVESTER_NAME }-${ uiInfo['ui-plugin-bundled-version'] }`;
|
||||
const fileName = `${ pkgName }.umd.min.js`;
|
||||
let pkgUrl;
|
||||
|
||||
if (uiInfo['ui-source'] === 'bundled' ) { // offline bundled
|
||||
pkgUrl = `/k8s/clusters/${ clusterId }/v1/harvester/plugin-assets/${ fileName }`;
|
||||
} else if (uiInfo['ui-source'] === 'external') {
|
||||
if (uiInfo['ui-plugin-index']) {
|
||||
pkgUrl = uiInfo['ui-plugin-index'];
|
||||
|
||||
// When using an external address, the pkgName should also be get from the url
|
||||
const names = pkgUrl.split('/');
|
||||
const jsName = names[names.length - 1];
|
||||
|
||||
pkgName = jsName?.split('.umd.min.js')[0];
|
||||
} else {
|
||||
throw new Error('Harvester cluster requested the plugin at `ui-plugin-index` is used, however did not provide a value for it');
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pkgUrl,
|
||||
pkgName
|
||||
};
|
||||
}
|
||||
|
||||
_overridePkgDetails() {
|
||||
// Support loading the pkg from a locally, or other, address
|
||||
// This helps testing of the harvester plugin when packaged up, instead of directly imported
|
||||
const harvesterPkgUrl = process.env.harvesterPkgUrl;
|
||||
|
||||
if (!harvesterPkgUrl) {
|
||||
return;
|
||||
}
|
||||
const parts = harvesterPkgUrl.replace('.umd.min.js', '').split('/');
|
||||
const pkgNameFromUrl = parts.length > 1 ? parts[parts.length - 1] : null;
|
||||
|
||||
if (pkgNameFromUrl) {
|
||||
return {
|
||||
pkgUrl: harvesterPkgUrl,
|
||||
pkgName: pkgNameFromUrl
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async _pkgDetails() {
|
||||
const overridePkgDetails = this._overridePkgDetails();
|
||||
|
||||
if (overridePkgDetails) {
|
||||
return overridePkgDetails;
|
||||
}
|
||||
|
||||
const clusterId = this.mgmt.id;
|
||||
const uiInfo = await this._getUiInfo(clusterId);
|
||||
|
||||
return uiInfo ? this._supportedClusterPkgDetails(uiInfo, clusterId) : this._legacyClusterPkgDetails();
|
||||
}
|
||||
|
||||
async goToCluster() {
|
||||
this.currentRouter().push({
|
||||
name: `${ VIRTUAL }-c-cluster-resource`,
|
||||
params: {
|
||||
cluster: this.status.clusterName,
|
||||
product: VIRTUAL,
|
||||
resource: HCI.DASHBOARD // Go directly to dashboard to avoid blip of components on screen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async setSupportedHarvesterVersion() {
|
||||
if (this._isSupportedHarvester !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `/k8s/clusters/${ this.status.clusterName }/v1`;
|
||||
|
||||
try {
|
||||
const setting = await this.$dispatch('request', { url: `${ url }/${ HCI.SETTING }s/server-version` });
|
||||
|
||||
this._harvesterVersion = setting?.value;
|
||||
this._isSupportedHarvester = this.$rootGetters['harvester-common/getFeatureEnabled']('supportHarvesterClusterVersion', setting?.value);
|
||||
} catch (error) {
|
||||
console.error('unable to get harvester version from settings/server-version', error); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
import HarvesterResource from './harvester';
|
||||
import { get } from '@shell/utils/object';
|
||||
import { findBy } from '@shell/utils/array';
|
||||
import { colorForState, stateDisplay, STATES } from '@shell/plugins/dashboard-store/resource-class';
|
||||
import { _CREATE } from '@shell/config/query-params';
|
||||
import { ucFirst, escapeHtml } from '@shell/utils/string';
|
||||
@@ -66,15 +64,12 @@ export default class ScheduleVmBackup extends HarvesterResource {
|
||||
}
|
||||
}
|
||||
|
||||
get stateObj() {
|
||||
return this?.metadata?.state || {};
|
||||
}
|
||||
|
||||
get state() {
|
||||
const conditions = get(this, 'status.conditions');
|
||||
const isSuspended = findBy(conditions, 'type', 'BackupSuspend')?.status === 'True';
|
||||
|
||||
if (isSuspended) {
|
||||
return STATES.suspended.label;
|
||||
}
|
||||
|
||||
return this.metadata.state.name;
|
||||
return this.status?.suspended === true ? STATES.suspended.label : STATES.active.label;
|
||||
}
|
||||
|
||||
get stateDescription() {
|
||||
|
||||
@@ -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 || {};
|
||||
|
||||
@@ -1120,10 +1120,6 @@ export default class VirtVm extends HarvesterResource {
|
||||
return qemu?.status === 'True';
|
||||
}
|
||||
|
||||
get warnDeletionMessage() {
|
||||
return this.t('harvester.virtualMachine.promptRemove.tips');
|
||||
}
|
||||
|
||||
get instanceLabels() {
|
||||
const all = this.spec?.template?.metadata?.labels || {};
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "harvester",
|
||||
"description": "Rancher UI Extension for Harvester",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.5",
|
||||
"private": false,
|
||||
"rancher": {
|
||||
"annotations": {
|
||||
"catalog.cattle.io/display-name": "Harvester",
|
||||
"catalog.cattle.io/kube-version": ">= 1.16.0-0",
|
||||
"catalog.cattle.io/rancher-version": ">= 2.10.0-0",
|
||||
"catalog.cattle.io/ui-extensions-version": ">= 3.0.0-0"
|
||||
"catalog.cattle.io/rancher-version": ">= 2.10.1-0",
|
||||
"catalog.cattle.io/ui-extensions-version": ">= 3.0.0 < 4.0.0"
|
||||
}
|
||||
},
|
||||
"icon": "https://raw.githubusercontent.com/harvester/harvester-ui-extension/main/pkg/harvester/icon.svg",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<script>
|
||||
import BrandImage from '@shell/components/BrandImage';
|
||||
|
||||
export default {
|
||||
components: { BrandImage },
|
||||
|
||||
computed: {
|
||||
serverVersion() {
|
||||
const version = this.$store.getters['harvester-common/getServerVersion']() || '';
|
||||
|
||||
return version.replace('v', '');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dashboard-root">
|
||||
<div class="dashboard-content">
|
||||
<main class="main-layout">
|
||||
<div class="logo">
|
||||
<BrandImage
|
||||
file-name="harvester.png"
|
||||
height="64"
|
||||
/>
|
||||
</div>
|
||||
<div class="tagline">
|
||||
<div class="description">
|
||||
{{ t('unsupported.description') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tagline">
|
||||
<div v-clean-html="t('unsupported.serverVersion', { serverVersion }, true)" />
|
||||
</div>
|
||||
<div class="tagline">
|
||||
<div v-clean-html="t('unsupported.learnMore', {}, true)" />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.dashboard-content {
|
||||
display: grid;
|
||||
flex-grow:1;
|
||||
|
||||
grid-template-areas:
|
||||
"main";
|
||||
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 200px 0 40px 0;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
|
||||
> div {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
max-width: 80%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 24px !important;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -4,6 +4,7 @@ import { isEmpty } from '@shell/utils/object';
|
||||
import Parse from 'url-parse';
|
||||
import { resourceNames } from '@shell/utils/string';
|
||||
import { HCI } from '../types';
|
||||
import { alternateLabel as alternateLabelButton } from '@shell/utils/platform';
|
||||
|
||||
export default {
|
||||
name: 'HarvesterPromptRemove',
|
||||
@@ -39,8 +40,9 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
checkedList: [],
|
||||
checkAll: true
|
||||
checkedList: [],
|
||||
checkAll: true,
|
||||
alternateLabel: alternateLabelButton
|
||||
};
|
||||
},
|
||||
|
||||
@@ -138,44 +140,53 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mt-10">
|
||||
{{ t('promptRemove.attemptingToRemove', {type}) }}
|
||||
<span v-clean-html="resourceNames(names, plusMore, t)"></span>
|
||||
|
||||
<div>
|
||||
<div class="mt-10">
|
||||
{{ t('harvester.virtualMachine.promptRemove.title') }}
|
||||
</div>
|
||||
<div v-if="value.length === 1">
|
||||
<span
|
||||
v-for="(name, i) in removeNameArr[value[0].id]"
|
||||
:key="i"
|
||||
>
|
||||
<label class="checkbox-container mr-15"><input
|
||||
v-model="checkedList"
|
||||
type="checkbox"
|
||||
:label="name"
|
||||
:value="name"
|
||||
/>
|
||||
{{ t('promptRemove.attemptingToRemove', {type}) }}
|
||||
<span v-clean-html="resourceNames(names, plusMore, t)"></span>
|
||||
|
||||
<div class="mt-10">
|
||||
{{ t('harvester.virtualMachine.promptRemove.title') }}
|
||||
</div>
|
||||
<div v-if="value.length === 1">
|
||||
<span
|
||||
v-for="(name, i) in removeNameArr[value[0].id]"
|
||||
:key="i"
|
||||
>
|
||||
<label class="checkbox-container mr-15">
|
||||
<input
|
||||
v-model="checkedList"
|
||||
type="checkbox"
|
||||
:label="name"
|
||||
:value="name"
|
||||
/>
|
||||
<span
|
||||
class="checkbox-custom mr-5"
|
||||
role="checkbox"
|
||||
/>
|
||||
{{ name }}
|
||||
</label>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<label class="checkbox-container mr-15">
|
||||
<input
|
||||
v-model="checkedList"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span
|
||||
class="checkbox-custom mr-5"
|
||||
role="checkbox"
|
||||
/>
|
||||
{{ name }}
|
||||
{{ t('harvester.virtualMachine.promptRemove.deleteAll') }}
|
||||
</label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<label class="checkbox-container mr-15"><input
|
||||
v-model="checkAll"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span
|
||||
class="checkbox-custom mr-5"
|
||||
role="checkbox"
|
||||
/>
|
||||
{{ t('harvester.virtualMachine.promptRemove.deleteAll') }}
|
||||
</label>
|
||||
<div class="text-warning mb-10 mt-10">
|
||||
{{ t('harvester.virtualMachine.promptRemove.tips') }}
|
||||
</div>
|
||||
<div class="text-info mt-20">
|
||||
{{ t('promptRemove.protip', { alternateLabel }) }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -15,8 +15,25 @@ import HarvesterAirgapUpdgrade from '../pages/c/_cluster/airgapupgrade/index.vue
|
||||
import HarvesterMembers from '../pages/c/_cluster/members/index.vue';
|
||||
import ProjectNamespaces from '../pages/c/_cluster/projectsnamespaces.vue';
|
||||
import HarvesterAlertmanagerReceiver from '../pages/c/_cluster/alertmanagerconfig/_alertmanagerconfigid/receiver.vue';
|
||||
import HarvesterUnsupported from '../pages/c/_cluster/unsupported/index.vue';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
route: {
|
||||
name: `${ PRODUCT_NAME }-c-cluster-unsupported-standalone`,
|
||||
path: `/:product`,
|
||||
component: HarvesterUnsupported
|
||||
},
|
||||
parent: 'blank'
|
||||
},
|
||||
{
|
||||
route: {
|
||||
name: `${ PRODUCT_NAME }-c-cluster-unsupported`,
|
||||
path: `/:product`,
|
||||
component: HarvesterUnsupported
|
||||
},
|
||||
parent: 'plain'
|
||||
},
|
||||
{
|
||||
name: `${ PRODUCT_NAME }-c-cluster-support`,
|
||||
path: `/:product/c/:cluster/support`,
|
||||
|
||||
@@ -101,6 +101,19 @@ export default {
|
||||
|
||||
const res: any = await allHash(hash);
|
||||
|
||||
const isHarvesterVersionSupported = rootGetters['harvester-common/getFeatureEnabled']('supportHarvesterClusterVersion');
|
||||
|
||||
if (!isHarvesterVersionSupported) {
|
||||
const product = rootGetters['productId'];
|
||||
|
||||
this.$router?.push({
|
||||
name: `${ product }-c-cluster-unsupported${ id === 'local' ? '-standalone' : '' }`,
|
||||
params: { product }
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await dispatch('cleanNamespaces', null, { root: true });
|
||||
|
||||
commit('updateNamespaces', {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"skipLibCheck": true,
|
||||
"useDefineForClassFields": false,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
|
||||
@@ -14,16 +14,35 @@ export function getVersion(v) {
|
||||
}
|
||||
|
||||
try {
|
||||
// v1.4.1-rc.1 => v1.4.1, v1.4.1-dev-20241222 => v1.4.1
|
||||
return `v${ semver.major(v) }.${ semver.minor(v) }.${ semver.patch(v) }`;
|
||||
} catch (error) {
|
||||
// fallback to the latest version
|
||||
return Object.keys(RELEASE_FEATURES).sort((a, b) => semver.compare(a, b)).pop();
|
||||
return latestVersion(Object.keys(RELEASE_FEATURES));
|
||||
}
|
||||
}
|
||||
|
||||
function latestVersion(versions) {
|
||||
return versions.sort((a, b) => semver.compare(a, b)).pop();
|
||||
}
|
||||
|
||||
// v1.3.3 => latest v1.3.x, v1.4.2 => latest v1.4.x
|
||||
function latestMinorVersion(v) {
|
||||
const minor = `v${ semver.major(v) }.${ semver.minor(v) }`;
|
||||
const minorVersions = Object.keys(RELEASE_FEATURES).filter((version) => version.startsWith(minor));
|
||||
|
||||
return latestVersion(minorVersions);
|
||||
}
|
||||
|
||||
export const featureEnabled = (featureKey, serverVersion) => {
|
||||
const version = getVersion(serverVersion);
|
||||
const releasedFeatures = RELEASE_FEATURES[version] || [];
|
||||
let releasedFeatures = RELEASE_FEATURES[version];
|
||||
|
||||
if (!releasedFeatures) {
|
||||
const fallback = latestMinorVersion(version);
|
||||
|
||||
releasedFeatures = RELEASE_FEATURES[fallback];
|
||||
}
|
||||
|
||||
return releasedFeatures.includes(featureKey);
|
||||
};
|
||||
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
set -x
|
||||
|
||||
BUILD_DEBUG="${BUILD_DEBUG:-}"
|
||||
if [[ -n "${BUILD_DEBUG}" ]]; then
|
||||
set -x
|
||||
env
|
||||
fi
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
echo "Bootstrapping..."
|
||||
yarn --pure-lockfile install
|
||||
|
||||
source scripts/version
|
||||
echo "BRANCH: ${COMMIT_BRANCH:-<none>}"
|
||||
echo "TAG: ${GIT_TAG:-<none>}"
|
||||
DIR=${GIT_TAG:-$COMMIT_BRANCH}
|
||||
|
||||
if [[ "${DIR}" == "main" ]]; then
|
||||
DIR="latest"
|
||||
fi
|
||||
|
||||
OUTPUT_DIR=dist/${DIR}-embedded
|
||||
|
||||
echo "Building..."
|
||||
COMMIT=${COMMIT} VERSION=${VERSION} OUTPUT_DIR=$OUTPUT_DIR ROUTER_BASE='/dashboard/' RESOURCE_BASE='/dashboard/' RANCHER_ENV=harvester yarn run build
|
||||
|
||||
if [ -v EMBED_PKG ]; then
|
||||
echo "Build and embed plugin from: $EMBED_PKG"
|
||||
PKG_FILE_NAME=${EMBED_PKG##*/}
|
||||
echo PKG_FILE_NAME: $PKG_FILE_NAME
|
||||
|
||||
PKG_NAME="${PKG_FILE_NAME/.tar.gz/""}"
|
||||
echo "Plugin name: '$PKG_NAME'"
|
||||
|
||||
# Fetch file, unpack and move to dist
|
||||
curl $EMBED_PKG --output $PKG_FILE_NAME
|
||||
OUTPUT_DIR_PKG=$OUTPUT_DIR/$PKG_NAME
|
||||
mkdir -p $OUTPUT_DIR_PKG
|
||||
tar xvfz $PKG_FILE_NAME -C $OUTPUT_DIR/$PKG_NAME
|
||||
echo "Plugin contents that will be served from $PKG_NAME"
|
||||
ls -alR $OUTPUT_DIR/$PKG_NAME
|
||||
fi
|
||||
|
||||
echo "Destroying..."
|
||||
find $OUTPUT_DIR -name "index.html" -mindepth 2 -exec rm {} \;
|
||||
find $OUTPUT_DIR -type d -empty -depth -exec rmdir {} \;
|
||||
|
||||
TARBALL=${DIR}.tar.gz
|
||||
TARBALL_FILE_PATH=dist/${TARBALL}
|
||||
|
||||
ENV_OUTPUT="${GITHUB_OUTPUT:-"temp-env"}"
|
||||
echo "BUILD_EMBEDED_TGZ=${TARBALL_FILE_PATH}" >> "$ENV_OUTPUT"
|
||||
|
||||
echo "Compressing to ${TARBALL}..."
|
||||
tar -czf ${TARBALL_FILE_PATH} $OUTPUT_DIR/
|
||||
|
||||
echo "Cleaning up..."
|
||||
rm -r $OUTPUT_DIR
|
||||
|
||||
ls -alR dist/
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
BUILD_DEBUG="${BUILD_DEBUG:-}"
|
||||
if [[ -n "${BUILD_DEBUG}" ]]; then
|
||||
set -x
|
||||
env
|
||||
fi
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
echo "Bootstrapping..."
|
||||
yarn --pure-lockfile install
|
||||
|
||||
source scripts/version
|
||||
echo "BRANCH: ${COMMIT_BRANCH:-<none>}"
|
||||
echo "TAG: ${GIT_TAG:-<none>}"
|
||||
DIR=${GIT_TAG:-$COMMIT_BRANCH}
|
||||
|
||||
if [[ "${DIR}" == "main" ]]; then
|
||||
DIR="latest"
|
||||
fi
|
||||
|
||||
BASE=${BASE:-https://releases.rancher.com/harvester-ui/dashboard/${DIR}}
|
||||
|
||||
echo "Building for ${BASE}..."
|
||||
|
||||
OUTPUT_DIR=dist/${DIR}
|
||||
|
||||
ENV_OUTPUT="${GITHUB_OUTPUT:-"temp-env"}"
|
||||
echo "BUILD_HOSTED_DIR=${OUTPUT_DIR}" >> "$ENV_OUTPUT"
|
||||
echo "BUILD_HOSTED_LOCATION=${DIR}" >> "$ENV_OUTPUT"
|
||||
|
||||
COMMIT=${COMMIT} VERSION=${VERSION} OUTPUT_DIR=${OUTPUT_DIR} ROUTER_BASE="/dashboard/" RESOURCE_BASE="${BASE}" RANCHER_ENV=harvester yarn run build
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
BASE_DIR="$( cd $SCRIPT_DIR && cd ../.. & pwd)"
|
||||
SHELL_DIR=$BASE_DIR/shell/
|
||||
EXIT_CODE=0
|
||||
FORMATS="umd-min"
|
||||
|
||||
while getopts "df:" opt; do
|
||||
case $opt in
|
||||
d)
|
||||
FORMATS="umd"
|
||||
;;
|
||||
f)
|
||||
FORMATS=$OPTARG
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
# Use shell folder in node modules when we have @rancher/shell installed as a node module
|
||||
# rather than the use-case of the mono-repo with the shell folder at the top-level
|
||||
if [ ! -d ${SHELL_DIR} ]; then
|
||||
SHELL_DIR=$BASE_DIR/node_modules/@rancher/shell/
|
||||
SHELL_DIR=$(cd -P ${SHELL_DIR} && pwd)
|
||||
fi
|
||||
|
||||
CREATE_TARBALL=${2}
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION=$(cd pkg/$1; node -p -e "require('./package.json').version")
|
||||
fi
|
||||
|
||||
NAME=${1}-${VERSION}
|
||||
PKG_DIST=${BASE_DIR}/dist-pkg/${NAME}
|
||||
|
||||
if [ -d "${BASE_DIR}/pkg/${1}" ]; then
|
||||
echo "Building UI Package $1"
|
||||
echo " Package name: ${NAME}"
|
||||
echo " Package version: ${VERSION}"
|
||||
echo " Output formats: ${FORMATS}"
|
||||
echo " Output directory: ${PKG_DIST}"
|
||||
rm -rf ${PKG_DIST}
|
||||
mkdir -p ${PKG_DIST}
|
||||
|
||||
pushd pkg/${1}
|
||||
|
||||
# Check that the .shell link exists and points to the correct place
|
||||
if [ -e ".shell" ]; then
|
||||
LINK=$(readlink .shell)
|
||||
if [ "${LINK}" != "${SHELL_DIR}" ]; then
|
||||
echo ".shell symlink exists but does not point to expected location - please check and fix"
|
||||
popd
|
||||
exit -1
|
||||
fi
|
||||
else
|
||||
ln -s ${SHELL_DIR} .shell
|
||||
fi
|
||||
|
||||
FILE=index.js
|
||||
if [ -f ./index.ts ]; then
|
||||
FILE=index.ts
|
||||
fi
|
||||
|
||||
if [ -n "$COMMIT" ]; then
|
||||
echo ${COMMIT} > ${PKG_DIST}/version
|
||||
fi
|
||||
|
||||
${BASE_DIR}/node_modules/.bin/vue-cli-service build --name ${NAME} --target lib ${FILE} --dest ${PKG_DIST} --formats ${FORMATS} --filename ${NAME}
|
||||
EXIT_CODE=$?
|
||||
cp -f ./package.json ${PKG_DIST}/package.json
|
||||
node ${SCRIPT_DIR}/pkgfile.js ${PKG_DIST}/package.json
|
||||
rm -rf ${PKG_DIST}/*.bak
|
||||
rm .shell
|
||||
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ $EXIT_CODE -ne 0 ]; then
|
||||
exit $EXIT_CODE
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "${CREATE_TARBALL}" ]; then
|
||||
echo $COMMIT $COMMIT_BRANCH > ${PKG_DIST}/version-commit.txt
|
||||
|
||||
TARBALL=${NAME}.tar.gz
|
||||
|
||||
pushd ${PKG_DIST}
|
||||
|
||||
rm -f ../$TARBALL
|
||||
|
||||
echo "Compressing to ${TARBALL}..."
|
||||
|
||||
tar -czf ../${TARBALL} .
|
||||
|
||||
popd
|
||||
|
||||
fi
|
||||
|
||||
exit $EXIT_CODE
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
BUILD_DEBUG="${BUILD_DEBUG:-}"
|
||||
if [[ -n "${BUILD_DEBUG}" ]]; then
|
||||
set -x
|
||||
env
|
||||
fi
|
||||
|
||||
if [[ -n "$CI_BUILD_TAG" ]]; then
|
||||
echo "Build has been triggered by a tag. Skipping gate"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -z "$CI_BRANCH" ]]; then
|
||||
echo "No branch detected. Skipping gate"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -z "$GIT_REPO" ]]; then
|
||||
echo "No repository detected. Unable to gate"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$GIT_COMMIT" ]]; then
|
||||
echo "No commit detected. Unable to gate"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Repo: $GIT_REPO"
|
||||
echo "Branch: $CI_BRANCH"
|
||||
echo "Build Commit: $GIT_COMMIT"
|
||||
|
||||
tmp=$(mktemp -u)
|
||||
STATUS_CODE=$(curl -w "%{http_code}" -s -o $tmp https://api.github.com/repos/$GIT_REPO/branches/$CI_BRANCH)
|
||||
|
||||
if [ "$STATUS_CODE" == "403" ]; then
|
||||
RATE_LIMIT_REMAINING=$(curl -s https://api.github.com/rate_limit | ./scripts/jq-nano - rate remaining)
|
||||
echo "Remaining GITHUB requests available: $RATE_LIMIT_REMAINING"
|
||||
RATE_LIMIT_REMAINING=${RATE_LIMIT_REMAINING:-0}
|
||||
if ((RATE_LIMIT_REMAINING < 1)); then
|
||||
echo "Github Rate Limit has been hit, skipping gate"
|
||||
exit 0
|
||||
fi
|
||||
# Fall through to the normal path like any other failed status code
|
||||
fi
|
||||
|
||||
LATEST_BRANCH_COMMIT=$(cat $tmp | ./scripts/jq-nano - commit sha)
|
||||
rm $tmp
|
||||
echo "Latest Branch Commit: $LATEST_BRANCH_COMMIT"
|
||||
if [ -z "$LATEST_BRANCH_COMMIT" ]; then
|
||||
echo "Unable to determine latest commit, failing gate"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$LATEST_BRANCH_COMMIT" == "$GIT_COMMIT" ]; then
|
||||
echo "Build was created from latest commit, passed upload gate"
|
||||
else
|
||||
echo "Build was not created from latest commit, failing gate"
|
||||
exit 1
|
||||
fi
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
yarn --pure-lockfile install
|
||||
|
||||
source scripts/version
|
||||
|
||||
if [[ $COMMIT_BRANCH == "main" ]]; then
|
||||
VERSION="latest"
|
||||
else
|
||||
VERSION=$COMMIT_BRANCH
|
||||
fi
|
||||
|
||||
echo "CI_BUILD_TAG: ${CI_BUILD_TAG}"
|
||||
echo "GIT_TAG: ${GIT_TAG}"
|
||||
echo "TAG_VERSION: ${TAG_VERSION}"
|
||||
|
||||
echo "CI Build Args"
|
||||
echo "COMMIT: ${COMMIT}"
|
||||
echo "COMMIT_BRANCH: ${COMMIT_BRANCH}"
|
||||
echo "VERSION: ${VERSION}"
|
||||
|
||||
if [ -n "$GIT_TAG" ]; then
|
||||
COMMIT=$COMMIT COMMIT_BRANCH=$COMMIT_BRANCH VERSION=$CI_BUILD_TAG ./scripts/build-pkg.sh ${1} "true"
|
||||
else
|
||||
COMMIT=$COMMIT COMMIT_BRANCH=$COMMIT_BRANCH VERSION=$VERSION ./scripts/build-pkg.sh ${1} "true"
|
||||
fi
|
||||
|
||||
EXIT_CODE=$?
|
||||
|
||||
if [ -n "$GIT_TAG" ]; then
|
||||
export PKG_NAME=${1}-${CI_BUILD_TAG}
|
||||
export PKG_TARBALL=${PKG_NAME}.tar.gz
|
||||
else
|
||||
export PKG_NAME=${1}-${VERSION} # harvester-release-harvester-v1.5 or harvester-latest
|
||||
export PKG_TARBALL=${PKG_NAME}.tar.gz # harvester-release-harvester-v1.5.tar.gz or harvester-latest.tar.gz
|
||||
fi
|
||||
|
||||
echo "CI Build Artifacts"
|
||||
echo "Package Directory: ${PKG_NAME}"
|
||||
echo "Package Tarball: ${PKG_TARBALL}"
|
||||
|
||||
ENV_OUTPUT="${GITHUB_OUTPUT:-"temp-env"}"
|
||||
echo "PKG_TARBALL=${PKG_TARBALL}" >> "$ENV_OUTPUT"
|
||||
echo "PKG_NAME=${PKG_NAME}" >> "$ENV_OUTPUT"
|
||||
|
||||
exit $EXIT_CODE
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const readline = require('readline');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const file = args.shift();
|
||||
|
||||
let text;
|
||||
|
||||
if ( file === '-' ) {
|
||||
process.stdin.resume();
|
||||
text = fs.readFileSync(0, "utf8");
|
||||
} else {
|
||||
text = fs.readFileSync(file, "utf8");
|
||||
}
|
||||
|
||||
const data = JSON.parse(text);
|
||||
|
||||
let out = data;
|
||||
while ( args.length ) {
|
||||
out = out[args.shift()];
|
||||
}
|
||||
|
||||
console.log(out);
|
||||
@@ -0,0 +1,24 @@
|
||||
const fs = require('fs');
|
||||
|
||||
console.log('Updating package file'); // eslint-disable-line no-console
|
||||
|
||||
if (process.argv.length !== 3) {
|
||||
console.error('No enough args'); // eslint-disable-line no-console
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const pkgFilepath = process.argv[process.argv.length - 1];
|
||||
const pkg = require(pkgFilepath);
|
||||
|
||||
// Ensure we have the keys we need
|
||||
|
||||
pkg.files = ['**/*'];
|
||||
pkg.rancher = true;
|
||||
pkg.main = `${ pkg.name }-${ pkg.version }.umd.min.js`;
|
||||
|
||||
delete pkg.scripts;
|
||||
delete pkg.browserslist;
|
||||
|
||||
|
||||
fs.writeFileSync(pkgFilepath, JSON.stringify(pkg, null, 2));
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
shopt -s extglob
|
||||
|
||||
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
|
||||
DIRTY="-dirty"
|
||||
fi
|
||||
|
||||
COMMIT=$(git rev-parse --short HEAD)
|
||||
COMMIT_DATE=$(git --no-pager log -1 --format='%ct')
|
||||
COMMIT_BRANCH=$(git rev-parse --abbrev-ref HEAD | sed -E 's/[^a-zA-Z0-9.-]+/-/g')
|
||||
GIT_TAG=${CI_BUILD_TAG:-$(git tag -l --contains HEAD | head -n 1)}
|
||||
LAST_TAG=${GIT_TAG:-'v0.0.0'}
|
||||
|
||||
if [[ -z "$DIRTY" && -n "$GIT_TAG" ]]; then
|
||||
# human readable version used on rancher dashboard about page
|
||||
export DASHBOARD_VERSION=$GIT_TAG
|
||||
# computer readable version
|
||||
VERSION=$GIT_TAG
|
||||
else
|
||||
# human readable version used on rancher dashboard about page
|
||||
export DASHBOARD_VERSION="${COMMIT_BRANCH} ${COMMIT}"
|
||||
# computer readable version
|
||||
VERSION="${COMMIT}${DIRTY}"
|
||||
fi
|
||||
|
||||
# Chart tag.
|
||||
if [[ -z "${DIRTY}" && -n "${GIT_TAG}" ]]; then
|
||||
CHART_VERSION="${GIT_TAG}"
|
||||
elif [[ "$DIRTY" ]]; then
|
||||
CHART_VERSION="${LAST_TAG}${DIRTY}.${COMMIT}"
|
||||
else
|
||||
CHART_VERSION="${LAST_TAG}-${COMMIT_DATE}.${COMMIT}.${COMMIT_BRANCH}"
|
||||
fi
|
||||
|
||||
# Drop the v prefix for Chart Version to follow existing pattern.
|
||||
CHART_VERSION="$(echo ${CHART_VERSION} | sed -E 's/^v//' | sed -e 's/^\(.\{55\}\).*/\1/')"
|
||||
|
||||
# Chart Repo - Target Repo for releases.
|
||||
case $CHART_VERSION in
|
||||
*-alpha*) # All alpha tags
|
||||
CHART_REPO="alpha" ;;
|
||||
*-rc*) # All rc tags
|
||||
CHART_REPO="latest" ;;
|
||||
+([0-9]).+([0-9]).+([0-9])) # All release tags
|
||||
CHART_REPO="latest" ;;
|
||||
*) # Anything else - Future use
|
||||
CHART_REPO="dev" ;;
|
||||
esac
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH=amd64
|
||||
fi
|
||||
|
||||
echo "ARCH: $ARCH"
|
||||
echo "CHART_REPO: $CHART_REPO"
|
||||
echo "CHART_VERSION: $CHART_VERSION"
|
||||
echo "VERSION: $VERSION"
|
||||
@@ -1466,6 +1466,15 @@
|
||||
"@babel/highlight" "^7.24.7"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/code-frame@^7.26.2":
|
||||
version "7.26.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
|
||||
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.2", "@babel/compat-data@^7.25.4":
|
||||
version "7.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb"
|
||||
@@ -1502,6 +1511,17 @@
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/generator@^7.26.10":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.10.tgz#a60d9de49caca16744e6340c3658dfef6138c3f7"
|
||||
integrity sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.26.10"
|
||||
"@babel/types" "^7.26.10"
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz#5373c7bc8366b12a033b4be1ac13a206c6656aab"
|
||||
@@ -1509,6 +1529,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4"
|
||||
integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-builder-binary-assignment-operator-visitor@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz#37d66feb012024f2422b762b9b2a7cfe27c7fba3"
|
||||
@@ -1541,6 +1568,19 @@
|
||||
"@babel/traverse" "^7.25.4"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.25.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz#d6f83e3039547fbb39967e78043cd3c8b7820c71"
|
||||
integrity sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.25.9"
|
||||
"@babel/helper-member-expression-to-functions" "^7.25.9"
|
||||
"@babel/helper-optimise-call-expression" "^7.25.9"
|
||||
"@babel/helper-replace-supers" "^7.26.5"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
|
||||
"@babel/traverse" "^7.26.9"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0", "@babel/helper-create-regexp-features-plugin@^7.25.2":
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz#24c75974ed74183797ffd5f134169316cd1808d9"
|
||||
@@ -1569,6 +1609,14 @@
|
||||
"@babel/traverse" "^7.24.8"
|
||||
"@babel/types" "^7.24.8"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3"
|
||||
integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b"
|
||||
@@ -1601,11 +1649,23 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e"
|
||||
integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878"
|
||||
integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==
|
||||
|
||||
"@babel/helper-plugin-utils@^7.25.9":
|
||||
version "7.26.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35"
|
||||
integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==
|
||||
|
||||
"@babel/helper-remap-async-to-generator@^7.24.7", "@babel/helper-remap-async-to-generator@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz#d2f0fbba059a42d68e5e378feaf181ef6055365e"
|
||||
@@ -1624,6 +1684,15 @@
|
||||
"@babel/helper-optimise-call-expression" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.0"
|
||||
|
||||
"@babel/helper-replace-supers@^7.26.5":
|
||||
version "7.26.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d"
|
||||
integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.25.9"
|
||||
"@babel/helper-optimise-call-expression" "^7.25.9"
|
||||
"@babel/traverse" "^7.26.5"
|
||||
|
||||
"@babel/helper-simple-access@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3"
|
||||
@@ -1640,16 +1709,34 @@
|
||||
"@babel/traverse" "^7.24.7"
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9"
|
||||
integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-string-parser@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d"
|
||||
integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==
|
||||
|
||||
"@babel/helper-string-parser@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
|
||||
integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db"
|
||||
integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
|
||||
integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
|
||||
|
||||
"@babel/helper-validator-option@^7.16.7", "@babel/helper-validator-option@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d"
|
||||
@@ -1689,6 +1776,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.6"
|
||||
|
||||
"@babel/parser@^7.26.10", "@babel/parser@^7.26.9":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749"
|
||||
integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.26.10"
|
||||
|
||||
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.3":
|
||||
version "7.25.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz#dca427b45a6c0f5c095a1c639dfe2476a3daba7f"
|
||||
@@ -1980,6 +2074,14 @@
|
||||
"@babel/helper-create-class-features-plugin" "^7.25.4"
|
||||
"@babel/helper-plugin-utils" "^7.24.8"
|
||||
|
||||
"@babel/plugin-transform-class-static-block@7.26.0":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz#6c8da219f4eb15cae9834ec4348ff8e9e09664a0"
|
||||
integrity sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==
|
||||
dependencies:
|
||||
"@babel/helper-create-class-features-plugin" "^7.25.9"
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
|
||||
"@babel/plugin-transform-class-static-block@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz#c82027ebb7010bc33c116d4b5044fbbf8c05484d"
|
||||
@@ -2460,7 +2562,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
|
||||
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
||||
|
||||
"@babel/runtime@^7.12.13", "@babel/runtime@^7.15.4", "@babel/runtime@^7.8.4":
|
||||
"@babel/runtime@^7.12.13", "@babel/runtime@^7.8.4":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2"
|
||||
integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==
|
||||
@@ -2476,6 +2578,15 @@
|
||||
"@babel/parser" "^7.25.0"
|
||||
"@babel/types" "^7.25.0"
|
||||
|
||||
"@babel/template@^7.26.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2"
|
||||
integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.26.2"
|
||||
"@babel/parser" "^7.26.9"
|
||||
"@babel/types" "^7.26.9"
|
||||
|
||||
"@babel/traverse@^7.23.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.4", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41"
|
||||
@@ -2489,6 +2600,19 @@
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.9":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.10.tgz#43cca33d76005dbaa93024fae536cc1946a4c380"
|
||||
integrity sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.26.2"
|
||||
"@babel/generator" "^7.26.10"
|
||||
"@babel/parser" "^7.26.10"
|
||||
"@babel/template" "^7.26.9"
|
||||
"@babel/types" "^7.26.10"
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.23.9", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6"
|
||||
@@ -2498,6 +2622,14 @@
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.26.9":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259"
|
||||
integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.25.9"
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
@@ -2915,24 +3047,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@novnc/novnc/-/novnc-1.2.0.tgz#535ffd7d074022d35205deae2753100f1f2b29f3"
|
||||
integrity sha512-FaUckOedGhSbwQBXk/KGyxKt9ngskg4wPw6ghbHWXOUEmQscAZr3467lTU5DSfppwHJt5k+lQiHoeYUuY90l2Q==
|
||||
|
||||
"@nuxtjs/axios@5.13.6":
|
||||
version "5.13.6"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.13.6.tgz#6f4bbd98a3a7799a5d2c0726c6ad2a98aa111881"
|
||||
integrity sha512-XS+pOE0xsDODs1zAIbo95A0LKlilvJi8YW0NoXYuq3/jjxGgWDxizZ6Yx0AIIjZOoGsXJOPc0/BcnSEUQ2mFBA==
|
||||
dependencies:
|
||||
"@nuxtjs/proxy" "^2.1.0"
|
||||
axios "^0.21.1"
|
||||
axios-retry "^3.1.9"
|
||||
consola "^2.15.3"
|
||||
defu "^5.0.0"
|
||||
|
||||
"@nuxtjs/proxy@^2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/proxy/-/proxy-2.1.0.tgz#fa7715a11d237fa1273503c4e9e137dd1bf5575b"
|
||||
integrity sha512-/qtoeqXgZ4Mg6LRg/gDUZQrFpOlOdHrol/vQYMnKu3aN3bP90UfOUB3QSDghUUK7OISAJ0xp8Ld78aHyCTcKCQ==
|
||||
dependencies:
|
||||
http-proxy-middleware "^1.0.6"
|
||||
|
||||
"@one-ini/wasm@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323"
|
||||
@@ -2958,10 +3072,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@rancher/icons/-/icons-2.0.29.tgz#6546d69768c706bebd66bfa73b36aef3d105987a"
|
||||
integrity sha512-qBBqfazS9y5VjV7fJDPNXmxd9AP/2uiE05mKFWP41kpbO+tEb62RnUBXCm14XLeScDZQcOuiAKVHMmvCFzF0BA==
|
||||
|
||||
"@rancher/shell@3.0.1-rc.1":
|
||||
version "3.0.1-rc.1"
|
||||
resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-3.0.1-rc.1.tgz#db3abc5e5160daffce4e42b113f7d38c025041b2"
|
||||
integrity sha512-1h245vyOaFXVHPdeSre4laCguXZijeIEQp31Yse0YV1KaHjNM7WZZRvLk3CqASrOtpVEGQ3W/vZO3qWLSQMJ9A==
|
||||
"@rancher/shell@3.0.1-rc.4":
|
||||
version "3.0.1-rc.4"
|
||||
resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-3.0.1-rc.4.tgz#d5b57a0184a89be09e7d4d21472545b3306d23d5"
|
||||
integrity sha512-cTBLjn7iysSi86XgptWDi8ErarVyPh6yRrRfBefQrxhMeCJNy3aH40neO37zJO/0e99/YBe4bRsr6Z2NV9TqBA==
|
||||
dependencies:
|
||||
"@aws-sdk/client-ec2" "3.658.1"
|
||||
"@aws-sdk/client-eks" "3.1.0"
|
||||
@@ -2972,7 +3086,6 @@
|
||||
"@babel/plugin-proposal-private-property-in-object" "7.14.5"
|
||||
"@babel/preset-typescript" "7.16.7"
|
||||
"@novnc/novnc" "1.2.0"
|
||||
"@nuxtjs/axios" "5.13.6"
|
||||
"@popperjs/core" "2.4.4"
|
||||
"@rancher/icons" "2.0.29"
|
||||
"@types/is-url" "1.2.30"
|
||||
@@ -2987,6 +3100,8 @@
|
||||
"@vue/vue3-jest" "^27.0.0-alpha.1"
|
||||
add "2.0.6"
|
||||
ansi_up "5.0.0"
|
||||
axios "0.21.4"
|
||||
axios-retry "3.1.9"
|
||||
babel-eslint "10.1.0"
|
||||
babel-plugin-module-resolver "4.0.0"
|
||||
babel-preset-vue "2.0.2"
|
||||
@@ -3009,6 +3124,7 @@
|
||||
d3-selection "1.4.1"
|
||||
dagre-d3 "0.6.4"
|
||||
dayjs "1.8.29"
|
||||
defu "5.0.1"
|
||||
diff2html "3.4.24"
|
||||
dompurify "2.5.4"
|
||||
element-matches "^0.1.2"
|
||||
@@ -3065,7 +3181,6 @@
|
||||
vue-router "4.4.3"
|
||||
vue-select "4.0.0-beta.6"
|
||||
vue-server-renderer "2.7.16"
|
||||
vue-template-compiler "2.7.16"
|
||||
vue3-resize "0.2.0"
|
||||
vue3-virtual-scroll-list "0.2.1"
|
||||
vuedraggable "4.1.0"
|
||||
@@ -3698,7 +3813,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
|
||||
integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
|
||||
|
||||
"@types/http-proxy@^1.17.5", "@types/http-proxy@^1.17.8":
|
||||
"@types/http-proxy@^1.17.8":
|
||||
version "1.17.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36"
|
||||
integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==
|
||||
@@ -4330,17 +4445,6 @@
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-core@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.7.tgz#04300bdc9fb52f89e6f250bbac16e03f0e0ed914"
|
||||
integrity sha512-A0gay3lK71MddsSnGlBxRPOugIVdACze9L/rCo5X5srCyjQfZOfYtSFMJc3aOZCM+xN55EQpb4R97rYn/iEbSw==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.25.3"
|
||||
"@vue/shared" "3.5.7"
|
||||
entities "^4.5.0"
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-dom@3.2.47":
|
||||
version "3.2.47"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305"
|
||||
@@ -4365,14 +4469,6 @@
|
||||
"@vue/compiler-core" "3.5.1"
|
||||
"@vue/shared" "3.5.1"
|
||||
|
||||
"@vue/compiler-dom@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.7.tgz#604ced082189b66cb811068332a45dcc11ae0af3"
|
||||
integrity sha512-GYWl3+gO8/g0ZdYaJ18fYHdI/WVic2VuuUd1NsPp60DWXKy+XjdhFsDW7FbUto8siYYZcosBGn9yVBkjhq1M8Q==
|
||||
dependencies:
|
||||
"@vue/compiler-core" "3.5.7"
|
||||
"@vue/shared" "3.5.7"
|
||||
|
||||
"@vue/compiler-sfc@3.2.47":
|
||||
version "3.2.47"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
|
||||
@@ -4404,21 +4500,6 @@
|
||||
postcss "^8.4.44"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-sfc@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.7.tgz#1150c49c0e3b39d40b2cf0f7de9edfcba98fa3e9"
|
||||
integrity sha512-EjOJtCWJrC7HqoCEzOwpIYHm+JH7YmkxC1hG6VkqIukYRqj8KFUlTLK6hcT4nGgtVov2+ZfrdrRlcaqS78HnBA==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.25.3"
|
||||
"@vue/compiler-core" "3.5.7"
|
||||
"@vue/compiler-dom" "3.5.7"
|
||||
"@vue/compiler-ssr" "3.5.7"
|
||||
"@vue/shared" "3.5.7"
|
||||
estree-walker "^2.0.2"
|
||||
magic-string "^0.30.11"
|
||||
postcss "^8.4.47"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-sfc@^3.4.15":
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.0.tgz#dc1e34a331d5deea9e258a1e10e1b4d711b1afd6"
|
||||
@@ -4458,14 +4539,6 @@
|
||||
"@vue/compiler-dom" "3.5.1"
|
||||
"@vue/shared" "3.5.1"
|
||||
|
||||
"@vue/compiler-ssr@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.7.tgz#042144dfd574a1f64b685e87730b0196dc1846d2"
|
||||
integrity sha512-oZx+jXP2k5arV/8Ly3TpQbfFyimMw2ANrRqvHJoKjPqtEzazxQGZjCLOfq8TnZ3wy2TOXdqfmVp4q7FyYeHV4g==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.5.7"
|
||||
"@vue/shared" "3.5.7"
|
||||
|
||||
"@vue/component-compiler-utils@^3.1.0", "@vue/component-compiler-utils@^3.3.0":
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz#f9f5fb53464b0c37b2c8d2f3fbfe44df60f61dc9"
|
||||
@@ -4512,13 +4585,6 @@
|
||||
dependencies:
|
||||
"@vue/shared" "3.5.1"
|
||||
|
||||
"@vue/reactivity@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.7.tgz#a52237fce841d92fc861220a8f26b51f5c3245e2"
|
||||
integrity sha512-yF0EpokpOHRNXyn/h6abXc9JFIzfdAf0MJHIi92xxCWS0mqrXH6+2aZ+A6EbSrspGzX5MHTd5N8iBA28HnXu9g==
|
||||
dependencies:
|
||||
"@vue/shared" "3.5.7"
|
||||
|
||||
"@vue/runtime-core@3.2.47":
|
||||
version "3.2.47"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.47.tgz#406ebade3d5551c00fc6409bbc1eeb10f32e121d"
|
||||
@@ -4535,14 +4601,6 @@
|
||||
"@vue/reactivity" "3.5.1"
|
||||
"@vue/shared" "3.5.1"
|
||||
|
||||
"@vue/runtime-core@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.7.tgz#4181b0a921d331f2efd5eda9aa35549ac97e6530"
|
||||
integrity sha512-OzLpBpKbZEaZVSNfd+hQbfBrDKux+b7Yl5hYhhWWWhHD7fEpF+CdI3Brm5k5GsufHEfvMcjruPxwQZuBN6nFYQ==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.5.7"
|
||||
"@vue/shared" "3.5.7"
|
||||
|
||||
"@vue/runtime-dom@3.2.47":
|
||||
version "3.2.47"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz#93e760eeaeab84dedfb7c3eaf3ed58d776299382"
|
||||
@@ -4562,16 +4620,6 @@
|
||||
"@vue/shared" "3.5.1"
|
||||
csstype "^3.1.3"
|
||||
|
||||
"@vue/runtime-dom@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.7.tgz#646e006d403f2e6337f566fdf461fbe400e8487d"
|
||||
integrity sha512-fL7cETfE27U2jyTgqzE382IGFY6a6uyznErn27KbbEzNctzxxUWYDbaN3B55l9nXh0xW2LRWPuWKOvjtO2UewQ==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.5.7"
|
||||
"@vue/runtime-core" "3.5.7"
|
||||
"@vue/shared" "3.5.7"
|
||||
csstype "^3.1.3"
|
||||
|
||||
"@vue/server-renderer@3.2.47":
|
||||
version "3.2.47"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.47.tgz#8aa1d1871fc4eb5a7851aa7f741f8f700e6de3c0"
|
||||
@@ -4588,14 +4636,6 @@
|
||||
"@vue/compiler-ssr" "3.5.1"
|
||||
"@vue/shared" "3.5.1"
|
||||
|
||||
"@vue/server-renderer@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.7.tgz#65ba8b60c0ee9e791619c0f8b2b6209a258484e5"
|
||||
integrity sha512-peRypij815eIDjpPpPXvYQGYqPH6QXwLJGWraJYPPn8JqWGl29A8QXnS7/Mh3TkMiOcdsJNhbFCoW2Agc2NgAQ==
|
||||
dependencies:
|
||||
"@vue/compiler-ssr" "3.5.7"
|
||||
"@vue/shared" "3.5.7"
|
||||
|
||||
"@vue/shared@3.2.47":
|
||||
version "3.2.47"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c"
|
||||
@@ -4611,11 +4651,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.1.tgz#f9418dae5ac194a4f19023d812978c21a15412a1"
|
||||
integrity sha512-NdcTRoO4KuW2RSFgpE2c+E/R/ZHaRzWPxAGxhmxZaaqLh6nYCXx7lc9a88ioqOCxCaV2SFJmujkxbUScW7dNsQ==
|
||||
|
||||
"@vue/shared@3.5.7":
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.7.tgz#1eedd1ffbf804c488fe806a17ff26c22e0ddb72f"
|
||||
integrity sha512-NBE1PBIvzIedxIc2RZiKXvGbJkrZ2/hLf3h8GlS4/sP9xcXEZMFWOazFkNd6aGeUCMaproe5MHVYB3/4AW9q9g==
|
||||
|
||||
"@vue/test-utils@~2.0.0-0":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-2.0.2.tgz#0b5edd683366153d5bc5a91edc62f292118710eb"
|
||||
@@ -5201,15 +5236,14 @@ aws4@^1.8.0:
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef"
|
||||
integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==
|
||||
|
||||
axios-retry@^3.1.9:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.9.1.tgz#c8924a8781c8e0a2c5244abf773deb7566b3830d"
|
||||
integrity sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==
|
||||
axios-retry@3.1.9:
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.1.9.tgz#6c30fc9aeb4519aebaec758b90ef56fa03fe72e8"
|
||||
integrity sha512-NFCoNIHq8lYkJa6ku4m+V1837TP6lCa7n79Iuf8/AqATAHYB0ISaAS1eyIenDOfHOLtym34W65Sjke2xjg2fsA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
is-retry-allowed "^2.2.0"
|
||||
is-retry-allowed "^1.1.0"
|
||||
|
||||
axios@^0.21.1:
|
||||
axios@0.21.4, axios@^0.21.1:
|
||||
version "0.21.4"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
|
||||
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
|
||||
@@ -6110,11 +6144,6 @@ connect-history-api-fallback@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8"
|
||||
integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==
|
||||
|
||||
consola@^2.15.3:
|
||||
version "2.15.3"
|
||||
resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550"
|
||||
integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==
|
||||
|
||||
console-browserify@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
|
||||
@@ -7129,11 +7158,6 @@ dayjs@^1.10.4, dayjs@^1.11.3:
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
|
||||
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
|
||||
|
||||
de-indent@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
|
||||
integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
|
||||
|
||||
debounce@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
|
||||
@@ -7241,7 +7265,7 @@ define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1:
|
||||
has-property-descriptors "^1.0.0"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
defu@^5.0.0:
|
||||
defu@5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/defu/-/defu-5.0.1.tgz#a034278f9b032bf0845d261aa75e9ad98da878ac"
|
||||
integrity sha512-EPS1carKg+dkEVy3qNTqIdp2qV7mUP08nIsupfwQpz++slCVRw7qbQyWvSTig+kFPwz2XXp5/kIIkH+CwrJKkQ==
|
||||
@@ -9039,17 +9063,6 @@ http-proxy-agent@^4.0.1:
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
http-proxy-middleware@^1.0.6:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz#43700d6d9eecb7419bf086a128d0f7205d9eb665"
|
||||
integrity sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==
|
||||
dependencies:
|
||||
"@types/http-proxy" "^1.17.5"
|
||||
http-proxy "^1.18.1"
|
||||
is-glob "^4.0.1"
|
||||
is-plain-obj "^3.0.0"
|
||||
micromatch "^4.0.2"
|
||||
|
||||
http-proxy-middleware@^2.0.3:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f"
|
||||
@@ -9474,10 +9487,10 @@ is-regex@^1.1.4:
|
||||
call-bind "^1.0.2"
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-retry-allowed@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d"
|
||||
integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==
|
||||
is-retry-allowed@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
|
||||
integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
|
||||
|
||||
is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3:
|
||||
version "1.0.3"
|
||||
@@ -10215,6 +10228,11 @@ jsesc@^2.5.1:
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||
|
||||
jsesc@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
|
||||
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
|
||||
|
||||
jsesc@~0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
@@ -11565,7 +11583,7 @@ picocolors@^0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f"
|
||||
integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==
|
||||
|
||||
picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0:
|
||||
picocolors@^1.0.0, picocolors@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59"
|
||||
integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==
|
||||
@@ -11901,15 +11919,6 @@ postcss@^8.1.10, postcss@^8.2.6, postcss@^8.3.5, postcss@^8.4.19, postcss@^8.4.3
|
||||
picocolors "^1.0.1"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
postcss@^8.4.47:
|
||||
version "8.4.47"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365"
|
||||
integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==
|
||||
dependencies:
|
||||
nanoid "^3.3.7"
|
||||
picocolors "^1.1.0"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
@@ -12844,34 +12853,16 @@ sockjs@^0.3.24:
|
||||
uuid "^8.3.2"
|
||||
websocket-driver "^0.7.4"
|
||||
|
||||
sortablejs-vue3@^1.2.11:
|
||||
version "1.2.11"
|
||||
resolved "https://registry.yarnpkg.com/sortablejs-vue3/-/sortablejs-vue3-1.2.11.tgz#c04f767253a03862a5445d310b335d9fdab71261"
|
||||
integrity sha512-oKOA6N7yu2ktmqYXPHlPTQWbe9G4v16mn5ewogb+Ybc9Bk1Y+MIURrpbgedEv7f9TS5Bptvh81HGjazh5FEyJw==
|
||||
dependencies:
|
||||
sortablejs "^1.15.0"
|
||||
vue "^3.3.7"
|
||||
|
||||
sortablejs@1.14.0:
|
||||
version "1.14.0"
|
||||
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
|
||||
integrity sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==
|
||||
|
||||
sortablejs@^1.15.0:
|
||||
version "1.15.3"
|
||||
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.3.tgz#033668db5ebfb11167d1249ab88e748f27959e29"
|
||||
integrity sha512-zdK3/kwwAK1cJgy1rwl1YtNTbRmc8qW/+vgXf75A7NHag5of4pyI6uK86ktmQETyWRH7IGaE73uZOOBcGxgqZg==
|
||||
|
||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
|
||||
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
|
||||
|
||||
source-map-js@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||
|
||||
source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.20:
|
||||
version "0.5.21"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||
@@ -13856,6 +13847,11 @@ vue-demi@*:
|
||||
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
|
||||
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
||||
|
||||
vue-draggable-next@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-draggable-next/-/vue-draggable-next-2.2.1.tgz#adbe98c74610cca8f4eb63f92042681f96920451"
|
||||
integrity sha512-EAMS1IRHF0kZO0o5PMOinsQsXIqsrKT1hKmbICxG3UEtn7zLFkLxlAtajcCcUTisNvQ6TtCB5COjD9a1raNADw==
|
||||
|
||||
vue-eslint-parser@^9.0.1:
|
||||
version "9.4.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz#9b04b22c71401f1e8bca9be7c3e3416a4bde76a8"
|
||||
@@ -13922,14 +13918,6 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.3:
|
||||
hash-sum "^1.0.2"
|
||||
loader-utils "^1.0.2"
|
||||
|
||||
vue-template-compiler@2.7.16:
|
||||
version "2.7.16"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz#c81b2d47753264c77ac03b9966a46637482bb03b"
|
||||
integrity sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==
|
||||
dependencies:
|
||||
de-indent "^1.0.2"
|
||||
he "^1.2.0"
|
||||
|
||||
vue-template-es2015-compiler@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||
@@ -13945,17 +13933,6 @@ vue3-virtual-scroll-list@0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/vue3-virtual-scroll-list/-/vue3-virtual-scroll-list-0.2.1.tgz#7fdc5be066c9b8d877614626a0bc02eb1fd12ad0"
|
||||
integrity sha512-G4KxITUOy9D4ro15zOp40D6ogmMefzjIyMsBKqN3xGbV1P6dlKYMx+BBXCKm3Nr/6iipcUKM272Sh2AJRyWMyQ==
|
||||
|
||||
vue@^3.3.7:
|
||||
version "3.5.7"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.7.tgz#511df1fab33a4c20cfe6b59659d6f601f0c26625"
|
||||
integrity sha512-JcFm0f5j8DQO9E07pZRxqZ/ZsNopMVzHYXpKvnfqXFcA4JTi+4YcrikRn9wkzWsdj0YsLzlLIsR0zzGxA2P6Wg==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.5.7"
|
||||
"@vue/compiler-sfc" "3.5.7"
|
||||
"@vue/runtime-dom" "3.5.7"
|
||||
"@vue/server-renderer" "3.5.7"
|
||||
"@vue/shared" "3.5.7"
|
||||
|
||||
vue@^3.4.31:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.1.tgz#507eb4ab010a2ad894f8d7765f32e68be1604815"
|
||||
|
||||
Reference in New Issue
Block a user