mirror of https://github.com/rancher/dashboard.git
Merge remote-tracking branch 'upstream/epinio-dev'
This commit is contained in:
commit
94e15d3e52
|
|
@ -25,7 +25,7 @@ jobs:
|
||||||
|
|
||||||
- name: Install & Build
|
- name: Install & Build
|
||||||
run:
|
run:
|
||||||
RANCHER_ENV=epinio ./.github/workflows/scripts/build-dashboard.sh
|
RANCHER_ENV=epinio EXCLUDES_PKG=rancher-components ./.github/workflows/scripts/build-dashboard.sh
|
||||||
|
|
||||||
- name: Upload Build
|
- name: Upload Build
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ set -e
|
||||||
echo "GITHUB_SHA: $GITHUB_SHA"
|
echo "GITHUB_SHA: $GITHUB_SHA"
|
||||||
echo "GITHUB_REF_NAME: $GITHUB_REF_NAME"
|
echo "GITHUB_REF_NAME: $GITHUB_REF_NAME"
|
||||||
echo "ROUTER_BASE: $ROUTER_BASE"
|
echo "ROUTER_BASE: $ROUTER_BASE"
|
||||||
|
echo
|
||||||
echo "RANCHER_ENV: $RANCHER_ENV"
|
echo "RANCHER_ENV: $RANCHER_ENV"
|
||||||
|
echo "EXCLUDES_PKG: $EXCLUDES_PKG"
|
||||||
echo
|
echo
|
||||||
echo "RELEASE_DIR: $RELEASE_DIR"
|
echo "RELEASE_DIR: $RELEASE_DIR"
|
||||||
RELEASE_LOCATION="$RELEASE_DIR/$ARTIFACT_NAME"
|
RELEASE_LOCATION="$RELEASE_DIR/$ARTIFACT_NAME"
|
||||||
|
|
@ -26,7 +28,7 @@ echo Installing dependencies
|
||||||
yarn install --frozen-lockfile
|
yarn install --frozen-lockfile
|
||||||
|
|
||||||
echo Building
|
echo Building
|
||||||
NUXT_ENV_commit=$GITHUB_SHA NUXT_ENV_version=$GITHUB_REF_NAME OUTPUT_DIR="$ARTIFACT_LOCATION" ROUTER_BASE="$ROUTER_BASE" RANCHER_ENV=$RANCHER_ENV API=$API RESOURCE_BASE=$RESOURCE_BASE yarn run build --spa
|
NUXT_ENV_commit=$GITHUB_SHA NUXT_ENV_version=$GITHUB_REF_NAME OUTPUT_DIR="$ARTIFACT_LOCATION" ROUTER_BASE="$ROUTER_BASE" RANCHER_ENV=$RANCHER_ENV API=$API RESOURCE_BASE=$RESOURCE_BASE EXCLUDES_PKG=$EXCLUDES_PKG yarn run build --spa
|
||||||
|
|
||||||
echo Creating tar
|
echo Creating tar
|
||||||
tar -czf $RELEASE_LOCATION.tar.gz -C $ARTIFACT_LOCATION .
|
tar -czf $RELEASE_LOCATION.tar.gz -C $ARTIFACT_LOCATION .
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
<script>
|
||||||
|
import { EPINIO_TYPES } from '@/pkg/epinio/types';
|
||||||
|
import { createEpinioRoute } from '@/pkg/epinio/utils/custom-routing';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
name: 'EpinioIntro',
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
getStartedLink: createEpinioRoute(`c-cluster-resource`, {
|
||||||
|
cluster: this.$store.getters['clusterId'],
|
||||||
|
resource: EPINIO_TYPES.NAMESPACE,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="epinio-intro">
|
||||||
|
<i class="icon-epinio mb-30" />
|
||||||
|
<h1>{{ t('epinio.intro.welcome') }}</h1>
|
||||||
|
<p class="mb-30">
|
||||||
|
<span>{{ t('epinio.intro.blurb') }}</span>
|
||||||
|
<a :href="t('epinio.intro.learnMoreLink')" target="_blank" rel="noopener noreferrer nofollow">
|
||||||
|
{{ t('epinio.intro.learnMore') }} <i class="icon icon-external-link" />
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<h3 class="mb-30">
|
||||||
|
{{ t('epinio.intro.noNamespaces', null, true) }}
|
||||||
|
</h3>
|
||||||
|
<n-link
|
||||||
|
:to="getStartedLink"
|
||||||
|
class="btn role-secondary"
|
||||||
|
>
|
||||||
|
{{ t('epinio.intro.getStarted') }}
|
||||||
|
</n-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.epinio-intro {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100%;
|
||||||
|
|
||||||
|
.icon-epinio {
|
||||||
|
font-size: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> p > span {
|
||||||
|
color: var(--disabled-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -5,10 +5,11 @@ import NameNsDescription from '@shell/components/form/NameNsDescription.vue';
|
||||||
import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
|
import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
|
||||||
import KeyValue from '@shell/components/form/KeyValue.vue';
|
import KeyValue from '@shell/components/form/KeyValue.vue';
|
||||||
import ArrayList from '@shell/components/form/ArrayList.vue';
|
import ArrayList from '@shell/components/form/ArrayList.vue';
|
||||||
import Banner from '@components/Banner/Banner.vue';
|
import Loading from '@shell/components/Loading.vue';
|
||||||
|
|
||||||
import { EPINIO_TYPES } from '../../types';
|
import { EPINIO_TYPES } from '../../types';
|
||||||
import { sortBy } from '@shell/utils/sort';
|
import { sortBy } from '@shell/utils/sort';
|
||||||
|
import { validateKubernetesName } from '@shell/utils/validators/kubernetes-name';
|
||||||
|
|
||||||
export interface EpinioAppInfo {
|
export interface EpinioAppInfo {
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -24,7 +25,7 @@ export interface EpinioAppInfo {
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
errors: string[],
|
errors: string[],
|
||||||
values: EpinioAppInfo
|
values?: EpinioAppInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data, Methods, Computed, Props
|
// Data, Methods, Computed, Props
|
||||||
|
|
@ -35,7 +36,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
NameNsDescription,
|
NameNsDescription,
|
||||||
LabeledInput,
|
LabeledInput,
|
||||||
KeyValue,
|
KeyValue,
|
||||||
Banner
|
Loading
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -52,17 +53,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
errors: [],
|
errors: [],
|
||||||
values: {
|
values: undefined
|
||||||
meta: {
|
|
||||||
name: this.application.meta?.name,
|
|
||||||
namespace: this.application.meta?.namespace
|
|
||||||
},
|
|
||||||
configuration: {
|
|
||||||
instances: this.application.configuration?.instances || 1,
|
|
||||||
environment: this.application.configuration?.environment || {},
|
|
||||||
routes: this.application.configuration?.routes || [],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -70,7 +61,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
this.values = {
|
this.values = {
|
||||||
meta: {
|
meta: {
|
||||||
name: this.application.meta?.name,
|
name: this.application.meta?.name,
|
||||||
namespace: this.application.meta?.namespace
|
namespace: this.application.meta?.namespace || this.namespaces[0]?.metadata.name
|
||||||
},
|
},
|
||||||
configuration: {
|
configuration: {
|
||||||
instances: this.application.configuration?.instances || 1,
|
instances: this.application.configuration?.instances || 1,
|
||||||
|
|
@ -105,8 +96,13 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
},
|
},
|
||||||
|
|
||||||
valid() {
|
valid() {
|
||||||
|
if (!this.values) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const validName = !!this.values.meta?.name;
|
const validName = !!this.values.meta?.name;
|
||||||
const validNamespace = !!this.values.meta?.namespace;
|
|
||||||
|
const nsErrors = validateKubernetesName(this.values.meta?.namespace || '', '', this.$store.getters, undefined, []);
|
||||||
|
const validNamespace = nsErrors.length === 0;
|
||||||
const validInstances = typeof this.values.configuration?.instances !== 'string' && this.values.configuration?.instances >= 0;
|
const validInstances = typeof this.values.configuration?.instances !== 'string' && this.values.configuration?.instances >= 0;
|
||||||
|
|
||||||
return validName && validNamespace && validInstances;
|
return validName && validNamespace && validInstances;
|
||||||
|
|
@ -127,11 +123,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="!namespaces.length">
|
<Loading v-if="!values" />
|
||||||
<Banner color="warning">
|
|
||||||
{{ t('epinio.warnings.noNamespace') }}
|
|
||||||
</Banner>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<NameNsDescription
|
<NameNsDescription
|
||||||
|
|
@ -143,6 +135,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
:value="values.meta"
|
:value="values.meta"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
@change="update"
|
@change="update"
|
||||||
|
@createNamespace="ns => values.meta.namespace = ns"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col span-6">
|
<div class="col span-6">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { STATE, DESCRIPTION } from '@shell/config/table-headers';
|
||||||
import { EPINIO_TYPES, APPLICATION_ACTION_STATE, APPLICATION_SOURCE_TYPE, EpinioApplication } from '../../types';
|
import { EPINIO_TYPES, APPLICATION_ACTION_STATE, APPLICATION_SOURCE_TYPE, EpinioApplication } from '../../types';
|
||||||
import { EpinioAppSource } from '../../components/application/AppSource.vue';
|
import { EpinioAppSource } from '../../components/application/AppSource.vue';
|
||||||
import { EpinioAppBindings } from '../../components/application/AppConfiguration.vue';
|
import { EpinioAppBindings } from '../../components/application/AppConfiguration.vue';
|
||||||
|
import EpinioNamespace from '~/pkg/epinio/models/namespaces';
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
running: boolean;
|
running: boolean;
|
||||||
|
|
@ -35,7 +36,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
},
|
},
|
||||||
bindings: {
|
bindings: {
|
||||||
type: Object as PropType<EpinioAppBindings>,
|
type: Object as PropType<EpinioAppBindings>,
|
||||||
required: true
|
default: () => null
|
||||||
},
|
},
|
||||||
mode: {
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
@ -48,22 +49,34 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetch() {
|
async fetch() {
|
||||||
const coreArgs = {
|
const coreArgs: Partial<ApplicationAction & {
|
||||||
|
application: EpinioApplication,
|
||||||
|
bindings: EpinioAppBindings,
|
||||||
|
type: string,
|
||||||
|
}> = {
|
||||||
application: this.application,
|
application: this.application,
|
||||||
bindings: this.bindings,
|
bindings: this.bindings,
|
||||||
type: EPINIO_TYPES.APP_ACTION,
|
type: EPINIO_TYPES.APP_ACTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!this.namespaces.find((ns: EpinioNamespace) => ns.name === coreArgs.application?.meta.namespace)) {
|
||||||
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
|
action: APPLICATION_ACTION_TYPE.CREATE_NS,
|
||||||
|
index: 0, // index used for sorting
|
||||||
|
...coreArgs,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
action: APPLICATION_ACTION_TYPE.CREATE,
|
action: APPLICATION_ACTION_TYPE.CREATE,
|
||||||
index: 0, // index used for sorting
|
index: 1, // index used for sorting
|
||||||
...coreArgs,
|
...coreArgs,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (this.bindings?.configurations?.length) {
|
if (this.bindings?.configurations?.length) {
|
||||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
action: APPLICATION_ACTION_TYPE.BIND_CONFIGURATIONS,
|
action: APPLICATION_ACTION_TYPE.BIND_CONFIGURATIONS,
|
||||||
index: 1,
|
index: 2,
|
||||||
...coreArgs,
|
...coreArgs,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +84,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
if (this.bindings?.services?.length) {
|
if (this.bindings?.services?.length) {
|
||||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
action: APPLICATION_ACTION_TYPE.BIND_SERVICES,
|
action: APPLICATION_ACTION_TYPE.BIND_SERVICES,
|
||||||
index: 2,
|
index: 3,
|
||||||
...coreArgs,
|
...coreArgs,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +93,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
this.source.type === APPLICATION_SOURCE_TYPE.FOLDER) {
|
this.source.type === APPLICATION_SOURCE_TYPE.FOLDER) {
|
||||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
action: APPLICATION_ACTION_TYPE.UPLOAD,
|
action: APPLICATION_ACTION_TYPE.UPLOAD,
|
||||||
index: 3,
|
index: 4,
|
||||||
...coreArgs,
|
...coreArgs,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +101,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
if (this.source.type === APPLICATION_SOURCE_TYPE.GIT_URL) {
|
if (this.source.type === APPLICATION_SOURCE_TYPE.GIT_URL) {
|
||||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
action: APPLICATION_ACTION_TYPE.GIT_FETCH,
|
action: APPLICATION_ACTION_TYPE.GIT_FETCH,
|
||||||
index: 3,
|
index: 4,
|
||||||
...coreArgs,
|
...coreArgs,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
@ -98,14 +111,14 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
this.source.type === APPLICATION_SOURCE_TYPE.GIT_URL) {
|
this.source.type === APPLICATION_SOURCE_TYPE.GIT_URL) {
|
||||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
action: APPLICATION_ACTION_TYPE.BUILD,
|
action: APPLICATION_ACTION_TYPE.BUILD,
|
||||||
index: 4,
|
index: 5,
|
||||||
...coreArgs,
|
...coreArgs,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||||
action: APPLICATION_ACTION_TYPE.DEPLOY,
|
action: APPLICATION_ACTION_TYPE.DEPLOY,
|
||||||
index: 5,
|
index: 6,
|
||||||
...coreArgs,
|
...coreArgs,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -121,7 +134,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
labelKey: 'epinio.applications.steps.progress.table.stage.label',
|
labelKey: 'epinio.applications.steps.progress.table.stage.label',
|
||||||
value: 'name',
|
value: 'name',
|
||||||
sort: ['index'],
|
sort: ['index'],
|
||||||
width: 100,
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...DESCRIPTION,
|
...DESCRIPTION,
|
||||||
|
|
@ -144,7 +157,11 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
computed: {
|
computed: {
|
||||||
actionsToRun() {
|
actionsToRun() {
|
||||||
return this.actions.filter((action: ApplicationAction) => action.run);
|
return this.actions.filter((action: ApplicationAction) => action.run);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
namespaces() {
|
||||||
|
return this.$store.getters['epinio/all'](EPINIO_TYPES.NAMESPACE);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@ import FileSelector from '@shell/components/form/FileSelector.vue';
|
||||||
import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
|
import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
|
||||||
import { sortBy } from '@shell/utils/sort';
|
import { sortBy } from '@shell/utils/sort';
|
||||||
import { generateZip } from '@shell/utils/download';
|
import { generateZip } from '@shell/utils/download';
|
||||||
|
import Collapse from '@shell/components/Collapse.vue';
|
||||||
|
|
||||||
import { APPLICATION_SOURCE_TYPE, EPINIO_TYPES } from '../../types';
|
import { APPLICATION_SOURCE_TYPE, EpinioApplicationChartResource, EPINIO_TYPES } from '../../types';
|
||||||
import { EpinioAppInfo } from './AppInfo.vue';
|
import { EpinioAppInfo } from './AppInfo.vue';
|
||||||
|
|
||||||
interface Archive{
|
interface Archive{
|
||||||
|
|
@ -34,6 +35,7 @@ interface BuilderImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
|
open: boolean,
|
||||||
archive: Archive,
|
archive: Archive,
|
||||||
container: Container,
|
container: Container,
|
||||||
gitUrl: GitUrl,
|
gitUrl: GitUrl,
|
||||||
|
|
@ -49,6 +51,12 @@ export interface EpinioAppSource {
|
||||||
container: Container,
|
container: Container,
|
||||||
gitUrl: GitUrl,
|
gitUrl: GitUrl,
|
||||||
builderImage: BuilderImage,
|
builderImage: BuilderImage,
|
||||||
|
appChart: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FileWithRelativePath extends File {
|
||||||
|
// For some reason TS throws this as missing at transpile time .. so recreate it
|
||||||
|
readonly webkitRelativePath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_BUILD_PACK = 'paketobuildpacks/builder:full';
|
const DEFAULT_BUILD_PACK = 'paketobuildpacks/builder:full';
|
||||||
|
|
@ -60,7 +68,8 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
FileSelector,
|
FileSelector,
|
||||||
LabeledInput,
|
LabeledInput,
|
||||||
LabeledSelect,
|
LabeledSelect,
|
||||||
RadioGroup
|
RadioGroup,
|
||||||
|
Collapse
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -80,6 +89,8 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
open: false,
|
||||||
|
|
||||||
archive: {
|
archive: {
|
||||||
tarball: this.source?.archive.tarball || '',
|
tarball: this.source?.archive.tarball || '',
|
||||||
fileName: this.source?.archive.fileName || '',
|
fileName: this.source?.archive.fileName || '',
|
||||||
|
|
@ -97,6 +108,8 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
default: this.source?.builderImage?.default !== undefined ? this.source.builderImage.default : true,
|
default: this.source?.builderImage?.default !== undefined ? this.source.builderImage.default : true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
appChart: this.source?.appChart,
|
||||||
|
|
||||||
types: [{
|
types: [{
|
||||||
label: this.t('epinio.applications.steps.source.archive.label'),
|
label: this.t('epinio.applications.steps.source.archive.label'),
|
||||||
value: APPLICATION_SOURCE_TYPE.ARCHIVE
|
value: APPLICATION_SOURCE_TYPE.ARCHIVE
|
||||||
|
|
@ -116,6 +129,9 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
if (!this.appChart) {
|
||||||
|
Vue.set(this, 'appChart', this.appCharts[0].value);
|
||||||
|
}
|
||||||
this.update();
|
this.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -139,6 +155,9 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
Vue.set(this.gitUrl, 'url', parsed.origin.git.url);
|
Vue.set(this.gitUrl, 'url', parsed.origin.git.url);
|
||||||
Vue.set(this.gitUrl, 'branch', parsed.origin.git.revision);
|
Vue.set(this.gitUrl, 'branch', parsed.origin.git.revision);
|
||||||
}
|
}
|
||||||
|
if (parsed.configuration) {
|
||||||
|
Vue.set(this, 'appChart', parsed.configuration.appchart);
|
||||||
|
}
|
||||||
|
|
||||||
const appInfo: EpinioAppInfo = {
|
const appInfo: EpinioAppInfo = {
|
||||||
meta: {
|
meta: {
|
||||||
|
|
@ -160,11 +179,12 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onFolderSelected(files: any[]) {
|
onFolderSelected(files: FileWithRelativePath | FileWithRelativePath[]) {
|
||||||
|
const safeFiles = Array.isArray(files) ? files : [files];
|
||||||
let folderName: string = '';
|
let folderName: string = '';
|
||||||
|
|
||||||
// Determine parent folder name
|
// Determine parent folder name
|
||||||
for (const f of files) {
|
for (const f of safeFiles) {
|
||||||
const paths = f.webkitRelativePath.split('/');
|
const paths = f.webkitRelativePath.split('/');
|
||||||
|
|
||||||
if (paths.length > 1) {
|
if (paths.length > 1) {
|
||||||
|
|
@ -179,7 +199,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filesToZip = files.reduce((res, f) => {
|
const filesToZip = safeFiles.reduce((res, f) => {
|
||||||
let path = f.webkitRelativePath;
|
let path = f.webkitRelativePath;
|
||||||
|
|
||||||
if (folderName) {
|
if (folderName) {
|
||||||
|
|
@ -211,7 +231,8 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
archive: this.archive,
|
archive: this.archive,
|
||||||
container: this.container,
|
container: this.container,
|
||||||
gitUrl: this.gitUrl,
|
gitUrl: this.gitUrl,
|
||||||
builderImage: this.builderImage
|
builderImage: this.builderImage,
|
||||||
|
appChart: this.appChart
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -271,6 +292,13 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
return sortBy(this.$store.getters['epinio/all'](EPINIO_TYPES.NAMESPACE), 'name');
|
return sortBy(this.$store.getters['epinio/all'](EPINIO_TYPES.NAMESPACE), 'name');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
appCharts() {
|
||||||
|
return sortBy(this.$store.getters['epinio/all'](EPINIO_TYPES.APP_CHARTS), 'name').map((ap: EpinioApplicationChartResource) => ({
|
||||||
|
value: ap.meta.name,
|
||||||
|
label: `${ ap.meta.name } (${ ap.short_description })`
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
type() {
|
type() {
|
||||||
// There's a bug in the select component which fires off the option ({ value, label}) instead of the value
|
// There's a bug in the select component which fires off the option ({ value, label}) instead of the value
|
||||||
// (possibly `reduce` related). This the workaround
|
// (possibly `reduce` related). This the workaround
|
||||||
|
|
@ -387,9 +415,23 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<Collapse :open.sync="open" :title="'Advanced Settings'" class="mt-30">
|
||||||
|
<template>
|
||||||
|
<LabeledSelect
|
||||||
|
v-model="appChart"
|
||||||
|
data-testid="epinio_app-source_appchart"
|
||||||
|
label="Application Chart"
|
||||||
|
:options="appCharts"
|
||||||
|
:mode="mode"
|
||||||
|
:clearable="false"
|
||||||
|
:required="true"
|
||||||
|
:tooltip="t('typeDescription.appcharts')"
|
||||||
|
:reduce="(e) => e.value"
|
||||||
|
@input="update"
|
||||||
|
/>
|
||||||
<template v-if="showBuilderImage">
|
<template v-if="showBuilderImage">
|
||||||
<div class="spacer">
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
|
class="mt-20"
|
||||||
name="defaultBuilderImage"
|
name="defaultBuilderImage"
|
||||||
data-testid="epinio_app-source_builder-select"
|
data-testid="epinio_app-source_builder-select"
|
||||||
:value="builderImage.default"
|
:value="builderImage.default"
|
||||||
|
|
@ -406,8 +448,9 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
@input="update"
|
@input="update"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
</template>
|
||||||
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -423,6 +466,10 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collapse {
|
||||||
|
margin-left: -5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.archive {
|
.archive {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,6 @@ export function init($plugin: any, store: any) {
|
||||||
configureType(EPINIO_TYPES.INSTANCE, { customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.INSTANCE }) });
|
configureType(EPINIO_TYPES.INSTANCE, { customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.INSTANCE }) });
|
||||||
|
|
||||||
// App resource
|
// App resource
|
||||||
weightType(EPINIO_TYPES.APP, 300, true);
|
|
||||||
configureType(EPINIO_TYPES.APP, {
|
configureType(EPINIO_TYPES.APP, {
|
||||||
isCreatable: true,
|
isCreatable: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
|
|
@ -81,8 +80,17 @@ export function init($plugin: any, store: any) {
|
||||||
customRoute: createEpinioRoute('c-cluster-applications', { }),
|
customRoute: createEpinioRoute('c-cluster-applications', { }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// App Chart resource
|
||||||
|
configureType(EPINIO_TYPES.APP_CHARTS, {
|
||||||
|
isCreatable: false,
|
||||||
|
isEditable: false,
|
||||||
|
isRemovable: false,
|
||||||
|
showState: false,
|
||||||
|
canYaml: false,
|
||||||
|
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.APP_CHARTS }),
|
||||||
|
});
|
||||||
|
|
||||||
// Configuration resource
|
// Configuration resource
|
||||||
weightType(EPINIO_TYPES.CONFIGURATION, 200, true);
|
|
||||||
configureType(EPINIO_TYPES.CONFIGURATION, {
|
configureType(EPINIO_TYPES.CONFIGURATION, {
|
||||||
isCreatable: true,
|
isCreatable: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
|
|
@ -92,12 +100,11 @@ export function init($plugin: any, store: any) {
|
||||||
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.CONFIGURATION }),
|
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.CONFIGURATION }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Groups
|
||||||
|
const ADVANCED_GROUP = 'Advanced';
|
||||||
const SERVICE_GROUP = 'Services';
|
const SERVICE_GROUP = 'Services';
|
||||||
|
|
||||||
weightGroup(SERVICE_GROUP, 1, true);
|
|
||||||
|
|
||||||
// Service Instance
|
// Service Instance
|
||||||
weightType(EPINIO_TYPES.SERVICE_INSTANCE, 151, true);
|
|
||||||
configureType(EPINIO_TYPES.SERVICE_INSTANCE, {
|
configureType(EPINIO_TYPES.SERVICE_INSTANCE, {
|
||||||
isCreatable: true,
|
isCreatable: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
|
|
@ -108,7 +115,6 @@ export function init($plugin: any, store: any) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Catalog Service
|
// Catalog Service
|
||||||
weightType(EPINIO_TYPES.CATALOG_SERVICE, 150, true);
|
|
||||||
configureType(EPINIO_TYPES.CATALOG_SERVICE, {
|
configureType(EPINIO_TYPES.CATALOG_SERVICE, {
|
||||||
isCreatable: false,
|
isCreatable: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|
@ -119,7 +125,6 @@ export function init($plugin: any, store: any) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Namespace resource
|
// Namespace resource
|
||||||
weightType(EPINIO_TYPES.NAMESPACE, 100, true);
|
|
||||||
configureType(EPINIO_TYPES.NAMESPACE, {
|
configureType(EPINIO_TYPES.NAMESPACE, {
|
||||||
isCreatable: true,
|
isCreatable: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
|
|
@ -130,16 +135,30 @@ export function init($plugin: any, store: any) {
|
||||||
showListMasthead: false // Disable default masthead because we provide a custom one.
|
showListMasthead: false // Disable default masthead because we provide a custom one.
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Side Nav
|
||||||
|
weightType(EPINIO_TYPES.CATALOG_SERVICE, 150, true);
|
||||||
|
weightType(EPINIO_TYPES.SERVICE_INSTANCE, 151, true);
|
||||||
basicType([
|
basicType([
|
||||||
EPINIO_TYPES.SERVICE_INSTANCE,
|
EPINIO_TYPES.SERVICE_INSTANCE,
|
||||||
EPINIO_TYPES.CATALOG_SERVICE,
|
EPINIO_TYPES.CATALOG_SERVICE,
|
||||||
], SERVICE_GROUP);
|
], SERVICE_GROUP);
|
||||||
|
|
||||||
|
weightType(EPINIO_TYPES.CONFIGURATION, 200, true);
|
||||||
|
weightType(EPINIO_TYPES.APP_CHARTS, 150, true);
|
||||||
|
basicType([
|
||||||
|
EPINIO_TYPES.CONFIGURATION,
|
||||||
|
EPINIO_TYPES.APP_CHARTS
|
||||||
|
], ADVANCED_GROUP);
|
||||||
|
|
||||||
|
weightType(EPINIO_TYPES.APP, 300, true);
|
||||||
|
weightGroup(SERVICE_GROUP, 2, true);
|
||||||
|
weightType(EPINIO_TYPES.NAMESPACE, 100, true);
|
||||||
|
weightGroup(ADVANCED_GROUP, 1, true);
|
||||||
basicType([
|
basicType([
|
||||||
EPINIO_TYPES.APP,
|
EPINIO_TYPES.APP,
|
||||||
SERVICE_GROUP,
|
SERVICE_GROUP,
|
||||||
EPINIO_TYPES.NAMESPACE,
|
EPINIO_TYPES.NAMESPACE,
|
||||||
EPINIO_TYPES.CONFIGURATION
|
ADVANCED_GROUP
|
||||||
]);
|
]);
|
||||||
|
|
||||||
headers(EPINIO_TYPES.APP, [
|
headers(EPINIO_TYPES.APP, [
|
||||||
|
|
@ -150,8 +169,6 @@ export function init($plugin: any, store: any) {
|
||||||
labelKey: 'epinio.tableHeaders.namespace',
|
labelKey: 'epinio.tableHeaders.namespace',
|
||||||
value: 'meta.namespace',
|
value: 'meta.namespace',
|
||||||
sort: ['meta.namespace'],
|
sort: ['meta.namespace'],
|
||||||
formatter: 'LinkDetail',
|
|
||||||
formatterOpts: { reference: 'nsLocation' }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'dep-status',
|
name: 'dep-status',
|
||||||
|
|
@ -266,8 +283,6 @@ export function init($plugin: any, store: any) {
|
||||||
labelKey: 'epinio.tableHeaders.namespace',
|
labelKey: 'epinio.tableHeaders.namespace',
|
||||||
value: 'meta.namespace',
|
value: 'meta.namespace',
|
||||||
sort: ['meta.namespace'],
|
sort: ['meta.namespace'],
|
||||||
formatter: 'LinkDetail',
|
|
||||||
formatterOpts: { reference: 'nsLocation' }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'boundApps',
|
name: 'boundApps',
|
||||||
|
|
@ -298,20 +313,26 @@ export function init($plugin: any, store: any) {
|
||||||
|
|
||||||
headers(EPINIO_TYPES.SERVICE_INSTANCE, [
|
headers(EPINIO_TYPES.SERVICE_INSTANCE, [
|
||||||
STATE,
|
STATE,
|
||||||
SIMPLE_NAME,
|
NAME,
|
||||||
{
|
{
|
||||||
name: 'namespace',
|
name: 'namespace',
|
||||||
labelKey: 'epinio.tableHeaders.namespace',
|
labelKey: 'epinio.tableHeaders.namespace',
|
||||||
value: 'metadata.namespace',
|
value: 'metadata.namespace',
|
||||||
sort: ['metadata.namespace'],
|
sort: ['metadata.namespace'],
|
||||||
formatter: 'LinkDetail',
|
|
||||||
formatterOpts: { reference: 'nsLocation' }
|
|
||||||
},
|
},
|
||||||
{ // This will be a link once the service instance detail / create / edit pages are created
|
{
|
||||||
name: 'catalog_service',
|
name: 'catalog_service',
|
||||||
labelKey: 'epinio.serviceInstance.tableHeaders.service',
|
labelKey: 'epinio.serviceInstance.tableHeaders.service',
|
||||||
value: 'catalog_service',
|
value: 'catalog_service',
|
||||||
sort: ['catalog_service'],
|
sort: ['catalog_service'],
|
||||||
|
formatter: 'LinkDetail',
|
||||||
|
formatterOpts: { reference: 'serviceLocation' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'catalog_service_version',
|
||||||
|
labelKey: 'epinio.serviceInstance.tableHeaders.serviceVersion',
|
||||||
|
value: 'catalog_service_version',
|
||||||
|
sort: ['catalog_service_version'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'boundApps',
|
name: 'boundApps',
|
||||||
|
|
@ -338,4 +359,21 @@ export function init($plugin: any, store: any) {
|
||||||
},
|
},
|
||||||
AGE
|
AGE
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
headers(EPINIO_TYPES.APP_CHARTS, [
|
||||||
|
SIMPLE_NAME,
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
labelKey: 'epinio.catalogService.tableHeaders.desc',
|
||||||
|
value: 'description',
|
||||||
|
sort: ['description'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'helm_chart',
|
||||||
|
label: 'Helm Chart',
|
||||||
|
value: 'helm_chart',
|
||||||
|
sort: ['helm_chart'],
|
||||||
|
},
|
||||||
|
AGE
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import ResourceTable from '@shell/components/ResourceTable.vue';
|
||||||
import PlusMinus from '@shell/components/form/PlusMinus.vue';
|
import PlusMinus from '@shell/components/form/PlusMinus.vue';
|
||||||
import { epinioExceptionToErrorsArray } from '../utils/errors';
|
import { epinioExceptionToErrorsArray } from '../utils/errors';
|
||||||
import ApplicationCard from '@/shell/components/cards/ApplicationCard.vue';
|
import ApplicationCard from '@/shell/components/cards/ApplicationCard.vue';
|
||||||
|
import Tabbed from '@shell/components/Tabbed/index.vue';
|
||||||
|
import Tab from '@shell/components/Tabbed/Tab.vue';
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +21,9 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
ConsumptionGauge,
|
ConsumptionGauge,
|
||||||
ResourceTable,
|
ResourceTable,
|
||||||
PlusMinus,
|
PlusMinus,
|
||||||
ApplicationCard
|
ApplicationCard,
|
||||||
|
Tabbed,
|
||||||
|
Tab,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
|
|
@ -35,12 +39,35 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fetch() {
|
||||||
|
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.SERVICE_INSTANCE });
|
||||||
|
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.CONFIGURATION });
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
const appInstanceSchema = this.$store.getters[`${ EPINIO_PRODUCT_NAME }/schemaFor`](EPINIO_TYPES.APP_INSTANCE);
|
||||||
|
const servicesSchema = this.$store.getters[`${ EPINIO_PRODUCT_NAME }/schemaFor`](EPINIO_TYPES.SERVICE_INSTANCE);
|
||||||
|
const servicesHeaders: [] = this.$store.getters['type-map/headersFor'](servicesSchema);
|
||||||
|
const configsSchema = this.$store.getters[`${ EPINIO_PRODUCT_NAME }/schemaFor`](EPINIO_TYPES.CONFIGURATION);
|
||||||
|
const configsHeaders: [] = this.$store.getters['type-map/headersFor'](configsSchema);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appInstanceSchema: this.$store.getters[`${ EPINIO_PRODUCT_NAME }/schemaFor`](EPINIO_TYPES.APP_INSTANCE),
|
|
||||||
saving: false,
|
saving: false,
|
||||||
|
appInstance: {
|
||||||
|
schema: appInstanceSchema,
|
||||||
|
headers: this.$store.getters['type-map/headersFor'](appInstanceSchema),
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
schema: servicesSchema,
|
||||||
|
headers: servicesHeaders.filter((h: any) => !['namespace', 'boundApps'].includes(h.name)),
|
||||||
|
},
|
||||||
|
configs: {
|
||||||
|
schema: configsSchema,
|
||||||
|
headers: configsHeaders.filter((h: any) => !['namespace', 'boundApps', 'service'].includes(h.name)),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async updateInstances(newInstances: number) {
|
async updateInstances(newInstances: number) {
|
||||||
this.$set(this, 'saving', true);
|
this.$set(this, 'saving', true);
|
||||||
|
|
@ -58,6 +85,12 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
|
|
||||||
return `${ matchGithub?.[4] }/${ matchGithub?.[5] }`;
|
return `${ matchGithub?.[4] }/${ matchGithub?.[5] }`;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
sourceIcon(): string {
|
||||||
|
return this.value.sourceInfo?.icon || 'icon-epinio';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -68,7 +101,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
<ApplicationCard>
|
<ApplicationCard>
|
||||||
<!-- Icon slot -->
|
<!-- Icon slot -->
|
||||||
<template v-slot:cardIcon>
|
<template v-slot:cardIcon>
|
||||||
<i class="icon icon-fw" :class="value.sourceInfo.icon || icon-epinio"></i>
|
<i class="icon icon-fw" :class="sourceIcon"></i>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Routes links slot -->
|
<!-- Routes links slot -->
|
||||||
|
|
@ -87,25 +120,24 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
|
|
||||||
<!-- Resources count slot -->
|
<!-- Resources count slot -->
|
||||||
<template v-slot:resourcesCount>
|
<template v-slot:resourcesCount>
|
||||||
<!-- // TODO: Depends on https://github.com/epinio/epinio/issues/1471 -->
|
|
||||||
<!-- <div>
|
|
||||||
{{ value.configCount }} {{ t('epinio.applications.detail.counts.config') }}
|
|
||||||
</div> -->
|
|
||||||
<div>
|
|
||||||
{{ value.configCount }} {{ t('epinio.applications.detail.counts.config') }}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
{{ value.envCount }} {{ t('epinio.applications.detail.counts.envVars') }}
|
{{ value.envCount }} {{ t('epinio.applications.detail.counts.envVars') }}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ value.serviceConfigurations.length }} {{ t('epinio.applications.detail.counts.services') }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ value.baseConfigurations.length }} {{ t('epinio.applications.detail.counts.config') }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ApplicationCard>
|
</ApplicationCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 v-if="value.deployment" class="mt-20 mb-20">
|
<h3 v-if="value.deployment" class="mt-20">
|
||||||
{{ t('epinio.applications.detail.deployment.label') }}
|
{{ t('epinio.applications.detail.deployment.label') }}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="deployment">
|
<div v-if="value.deployment" class="deployment">
|
||||||
<div class="simple-box-row app-instances">
|
<div class="simple-box-row app-instances">
|
||||||
<SimpleBox>
|
<SimpleBox>
|
||||||
<ConsumptionGauge
|
<ConsumptionGauge
|
||||||
|
|
@ -165,28 +197,41 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
</thead>
|
</thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ t('tableHeaders.memory') }}</td>
|
<td>{{ t('tableHeaders.memory') }}</td>
|
||||||
<td>{{ value.instanceMemory.min }} MiB</td>
|
<td>{{ value.instanceMemory.min }}</td>
|
||||||
<td>{{ value.instanceMemory.max }} MiB</td>
|
<td>{{ value.instanceMemory.max }}</td>
|
||||||
<td>{{ value.instanceMemory.avg }} MiB</td>
|
<td>{{ value.instanceMemory.avg }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ t('tableHeaders.cpu') }}</td>
|
<td>{{ t('tableHeaders.cpu') }}</td>
|
||||||
<td>{{ value.instanceCpu.min }} m</td>
|
<td>{{ value.instanceCpu.min }}</td>
|
||||||
<td>{{ value.instanceCpu.max }} m</td>
|
<td>{{ value.instanceCpu.max }}</td>
|
||||||
<td>{{ value.instanceCpu.avg }} m</td>
|
<td>{{ value.instanceCpu.avg }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</SimpleBox>
|
</SimpleBox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3 class="mt-20">
|
||||||
|
{{ t('epinio.applications.detail.tables.label') }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<!-- //TODO: Add Services & Configurations as tabs -->
|
<Tabbed>
|
||||||
<ResourceTable :schema="appInstanceSchema" :rows="value.instances" :table-actions="false">
|
<Tab label-key="epinio.applications.detail.tables.instances" name="instances" :weight="3">
|
||||||
<template #header-left>
|
<ResourceTable :schema="appInstance.schema" :headers="appInstance.headers" :rows="value.instances" :table-actions="false">
|
||||||
<h1>Instances</h1>
|
|
||||||
</template>
|
|
||||||
</ResourceTable>
|
</ResourceTable>
|
||||||
|
</Tab>
|
||||||
|
<Tab label-key="epinio.applications.detail.tables.services" name="services" :weight="2">
|
||||||
|
<ResourceTable :schema="services.schema" :headers="services.headers" :rows="value.services" :namespaced="false" :table-actions="false">
|
||||||
|
</ResourceTable>
|
||||||
|
</Tab>
|
||||||
|
<Tab label-key="epinio.applications.detail.tables.configs" name="configs" :weight="1">
|
||||||
|
<ResourceTable :schema="configs.schema" :headers="configs.headers" :rows="value.baseConfigurations" :namespaced="false" :table-actions="false">
|
||||||
|
</ResourceTable>
|
||||||
|
</Tab>
|
||||||
|
</Tabbed>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -292,7 +337,6 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
}
|
}
|
||||||
|
|
||||||
.deployment {
|
.deployment {
|
||||||
margin-bottom: 60px;
|
|
||||||
.simple-box {
|
.simple-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue, { PropType } from 'vue';
|
||||||
|
import EpinioCatalogServiceModel from '~/pkg/epinio/models/catalogservices';
|
||||||
|
import { EPINIO_PRODUCT_NAME, EPINIO_TYPES } from '../types';
|
||||||
|
|
||||||
|
import ResourceTable from '@shell/components/ResourceTable.vue';
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Vue.extend<Data, any, any, any>({
|
||||||
|
components: { ResourceTable },
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object as PropType<EpinioCatalogServiceModel>,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetch() {
|
||||||
|
await this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.SERVICE_INSTANCE });
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
const servicesSchema = this.$store.getters[`${ EPINIO_PRODUCT_NAME }/schemaFor`](EPINIO_TYPES.SERVICE_INSTANCE);
|
||||||
|
const servicesHeaders: [] = this.$store.getters['type-map/headersFor'](servicesSchema);
|
||||||
|
|
||||||
|
return {
|
||||||
|
servicesSchema,
|
||||||
|
servicesHeaders
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2 class="mt-20">
|
||||||
|
{{ t('epinio.catalogService.detail.servicesTitle', { catalogService: value.name }) }}
|
||||||
|
</h2>
|
||||||
|
<ResourceTable
|
||||||
|
:schema="servicesSchema"
|
||||||
|
:rows="value.services"
|
||||||
|
:loading="$fetchState.pending"
|
||||||
|
:headers="servicesHeaders"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -48,7 +48,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
async fetch() {
|
async fetch() {
|
||||||
await this.mixinFetch();
|
await this.mixinFetch();
|
||||||
|
|
||||||
Vue.set(this.value.meta, 'namespace', this.initialValue.meta.namespace || this.namespaces[0].metadata.name);
|
Vue.set(this.value.meta, 'namespace', this.initialValue.meta.namespace || this.namespaces[0]?.metadata.name);
|
||||||
this.selectedApps = [...this.initialValue.configuration?.boundapps || []];
|
this.selectedApps = [...this.initialValue.configuration?.boundapps || []];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -105,8 +105,9 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
|
|
||||||
updateValidation() {
|
updateValidation() {
|
||||||
const nameErrors = validateKubernetesName(this.value?.meta.name || '', this.t('epinio.namespace.name'), this.$store.getters, undefined, []);
|
const nameErrors = validateKubernetesName(this.value?.meta.name || '', this.t('epinio.namespace.name'), this.$store.getters, undefined, []);
|
||||||
|
const nsErrors = validateKubernetesName(this.value?.meta.namespace || '', '', this.$store.getters, undefined, []);
|
||||||
|
|
||||||
if (nameErrors.length === 0) {
|
if (nameErrors.length === 0 && nsErrors.length === 0) {
|
||||||
const dataValues = Object.entries(this.value?.data || {});
|
const dataValues = Object.entries(this.value?.data || {});
|
||||||
|
|
||||||
if (!!dataValues.length) {
|
if (!!dataValues.length) {
|
||||||
|
|
@ -124,6 +125,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
watch: {
|
watch: {
|
||||||
'value.meta.namespace'() {
|
'value.meta.namespace'() {
|
||||||
Vue.set(this, 'selectedApps', []);
|
Vue.set(this, 'selectedApps', []);
|
||||||
|
this.updateValidation(); // For when a user is supplying their own ns
|
||||||
},
|
},
|
||||||
|
|
||||||
'value.meta.name'() {
|
'value.meta.name'() {
|
||||||
|
|
@ -142,14 +144,9 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Loading v-if="!value || !namespaces" />
|
<Loading v-if="!value || $fetchState.pending" />
|
||||||
<div v-else-if="!namespaces.length">
|
|
||||||
<Banner color="warning">
|
|
||||||
{{ t('epinio.warnings.noNamespace') }}
|
|
||||||
</Banner>
|
|
||||||
</div>
|
|
||||||
<CruResource
|
<CruResource
|
||||||
v-else-if="value && namespaces.length > 0"
|
v-else-if="value"
|
||||||
:min-height="'7em'"
|
:min-height="'7em'"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
:done-route="doneRoute"
|
:done-route="doneRoute"
|
||||||
|
|
@ -157,10 +154,14 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
:can-yaml="false"
|
:can-yaml="false"
|
||||||
:errors="errors"
|
:errors="errors"
|
||||||
:validation-passed="validationPassed"
|
:validation-passed="validationPassed"
|
||||||
|
namespace-key="meta.namespace"
|
||||||
@error="(e) => (errors = e)"
|
@error="(e) => (errors = e)"
|
||||||
@finish="save"
|
@finish="save"
|
||||||
@cancel="done"
|
@cancel="done"
|
||||||
>
|
>
|
||||||
|
<Banner v-if="value.isServiceRelated" color="info">
|
||||||
|
{{ t('epinio.configurations.tableHeaders.service.tooltip') }}
|
||||||
|
</Banner>
|
||||||
<NameNsDescription
|
<NameNsDescription
|
||||||
name-key="name"
|
name-key="name"
|
||||||
namespace-key="namespace"
|
namespace-key="namespace"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import NameNsDescription from '@shell/components/form/NameNsDescription.vue';
|
||||||
import EpinioBindAppsMixin from './bind-apps-mixin.js';
|
import EpinioBindAppsMixin from './bind-apps-mixin.js';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
export const EPINIO_SERVICE_PARAM = 'service';
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,7 +24,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
Loading,
|
Loading,
|
||||||
CruResource,
|
CruResource,
|
||||||
LabeledSelect,
|
LabeledSelect,
|
||||||
NameNsDescription
|
NameNsDescription,
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [CreateEditView, EpinioBindAppsMixin],
|
mixins: [CreateEditView, EpinioBindAppsMixin],
|
||||||
|
|
@ -48,7 +50,8 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
this.mixinFetch()
|
this.mixinFetch()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Vue.set(this.value.meta, 'namespace', this.initialValue.meta.namespace || this.namespaces[0].meta.name);
|
Vue.set(this.value, 'catalog_service', this.$route.query[EPINIO_SERVICE_PARAM]);
|
||||||
|
Vue.set(this.value.meta, 'namespace', this.initialValue.meta.namespace || this.namespaces[0]?.meta.name);
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -68,12 +71,13 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameErrors = validateKubernetesName(this.value?.name || '', this.t('epinio.namespace.name'), this.$store.getters, undefined, []);
|
const nameErrors = validateKubernetesName(this.value?.name || '', this.t('epinio.namespace.name'), this.$store.getters, undefined, []);
|
||||||
|
const nsErrors = validateKubernetesName(this.value?.meta.namespace || '', '', this.$store.getters, undefined, []);
|
||||||
|
|
||||||
if (nameErrors.length > 0) {
|
if (nameErrors.length === 0 && nsErrors.length === 0) {
|
||||||
return false;
|
return !this.failedWaitingForDeploy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !this.failedWaitingForDeploy;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
namespaces() {
|
namespaces() {
|
||||||
|
|
@ -125,7 +129,7 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
'value.namespace'() {
|
'value.meta.namespace'() {
|
||||||
Vue.set(this, 'selectedApps', []);
|
Vue.set(this, 'selectedApps', []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -134,20 +138,16 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Loading v-if="!value || !namespaces" />
|
<Loading v-if="!value || $fetchState.pending" />
|
||||||
<div v-else-if="!namespaces.length">
|
|
||||||
<Banner color="warning">
|
|
||||||
{{ t('epinio.warnings.noNamespace') }}
|
|
||||||
</Banner>
|
|
||||||
</div>
|
|
||||||
<CruResource
|
<CruResource
|
||||||
v-else-if="value && namespaces.length > 0"
|
v-else-if="value"
|
||||||
:can-yaml="false"
|
:can-yaml="false"
|
||||||
:done-route="doneRoute"
|
:done-route="doneRoute"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
:validation-passed="validationPassed"
|
:validation-passed="validationPassed"
|
||||||
:resource="value"
|
:resource="value"
|
||||||
:errors="errors"
|
:errors="errors"
|
||||||
|
namespace-key="meta.namespace"
|
||||||
@error="e=>errors = e"
|
@error="e=>errors = e"
|
||||||
@finish="save"
|
@finish="save"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@ typeLabel:
|
||||||
one { Applications }
|
one { Applications }
|
||||||
other { Applications }
|
other { Applications }
|
||||||
}
|
}
|
||||||
|
appcharts: |-
|
||||||
|
{count, plural,
|
||||||
|
one { Application Templates }
|
||||||
|
other { Application Templates }
|
||||||
|
}
|
||||||
"services": |-
|
"services": |-
|
||||||
{count, plural,
|
{count, plural,
|
||||||
one { Instances }
|
one { Instances }
|
||||||
|
|
@ -24,8 +29,22 @@ typeLabel:
|
||||||
one { Catalog }
|
one { Catalog }
|
||||||
other { Catalog }
|
other { Catalog }
|
||||||
}
|
}
|
||||||
|
typeDescription:
|
||||||
|
namespaces: Namespaces group your applications, services and other resources. Deleting a namespace will delete all of it's resources.
|
||||||
|
applications: Epinio uses Applications to transition your code, through build, to being deployed.
|
||||||
|
services: Epinio can create instances of your services. Instances can be bound to your applications to provide data, for example a database service bound to an application might provide connection credentials.
|
||||||
|
configurations: Configurations are a way to provide data to applications. The data becomes available once the configuration is bound to them.
|
||||||
|
appcharts: Application Templates define kube resources created by your application
|
||||||
|
catalogservices: Catalog Services provide additional, common functionality to applications. For example an instance of a database Catalog Service can be bound to an application.
|
||||||
epinio:
|
epinio:
|
||||||
label: Epinio
|
label: Epinio
|
||||||
|
intro:
|
||||||
|
welcome: Welcome to Epinio
|
||||||
|
blurb: The Application Development Engine for Kubernetes
|
||||||
|
learnMoreLink: https://epinio.io/
|
||||||
|
learnMore: Learn more
|
||||||
|
noNamespaces: Create a Namespace, then create your Applications
|
||||||
|
getStarted: Get started
|
||||||
tableHeaders:
|
tableHeaders:
|
||||||
namespace: Namespace
|
namespace: Namespace
|
||||||
instances:
|
instances:
|
||||||
|
|
@ -59,6 +78,11 @@ epinio:
|
||||||
instances: Instances
|
instances: Instances
|
||||||
memory: Memory
|
memory: Memory
|
||||||
cpu: CPU
|
cpu: CPU
|
||||||
|
tables:
|
||||||
|
label: Resources
|
||||||
|
instances: Instances
|
||||||
|
services: Services
|
||||||
|
configs: Configurations
|
||||||
create:
|
create:
|
||||||
title: Application
|
title: Application
|
||||||
titleSubText: Epinio
|
titleSubText: Epinio
|
||||||
|
|
@ -140,8 +164,11 @@ epinio:
|
||||||
run:
|
run:
|
||||||
label: Run
|
label: Run
|
||||||
action:
|
action:
|
||||||
|
create_namespace:
|
||||||
|
label: Create Namespace
|
||||||
|
description: A Namespace will be created to contain your Application
|
||||||
create:
|
create:
|
||||||
label: Create
|
label: Create Application
|
||||||
description: The Application will be created ready to deploy source to
|
description: The Application will be created ready to deploy source to
|
||||||
bind_configurations:
|
bind_configurations:
|
||||||
label: Bind Configurations
|
label: Bind Configurations
|
||||||
|
|
@ -206,6 +233,7 @@ epinio:
|
||||||
serviceInstance:
|
serviceInstance:
|
||||||
tableHeaders:
|
tableHeaders:
|
||||||
service: Catalog Service
|
service: Catalog Service
|
||||||
|
serviceVersion: Catalog Service Version
|
||||||
create:
|
create:
|
||||||
catalogService:
|
catalogService:
|
||||||
label: Catalog Service
|
label: Catalog Service
|
||||||
|
|
@ -216,5 +244,10 @@ epinio:
|
||||||
tableHeaders:
|
tableHeaders:
|
||||||
shortDesc: Headline
|
shortDesc: Headline
|
||||||
desc: Description
|
desc: Description
|
||||||
|
detail:
|
||||||
|
servicesTitle: "{catalogService} Services"
|
||||||
|
chartVersion: Chart Version
|
||||||
|
appVersion: Version
|
||||||
|
helmChart: Helm Chart
|
||||||
warnings:
|
warnings:
|
||||||
noNamespace: There are no namespaces. Please create one before proceeding
|
noNamespace: There are no namespaces. Please create one before proceeding
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<script>
|
||||||
|
import ResourceTable from '@shell/components/ResourceTable';
|
||||||
|
import { EPINIO_TYPES } from '../types';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EpinioAppChartsList',
|
||||||
|
components: { ResourceTable },
|
||||||
|
async fetch() {
|
||||||
|
await this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.APP_CHARTS });
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
schema: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
rows() {
|
||||||
|
return this.$store.getters['epinio/all'](EPINIO_TYPES.APP_CHARTS);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ResourceTable
|
||||||
|
v-bind="$attrs"
|
||||||
|
:rows="rows"
|
||||||
|
:schema="schema"
|
||||||
|
:loading="$fetchState.pending"
|
||||||
|
:table-actions="false"
|
||||||
|
v-on="$listeners"
|
||||||
|
>
|
||||||
|
</ResourceTable>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
<script>
|
||||||
|
import { EPINIO_TYPES } from '../types';
|
||||||
|
import Loading from '@shell/components/Loading';
|
||||||
|
import SelectIconGrid from '@shell/components/SelectIconGrid';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EpinioCatalogList',
|
||||||
|
components: { Loading, SelectIconGrid },
|
||||||
|
fetch() {
|
||||||
|
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.CATALOG_SERVICE });
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
schema: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return { searchQuery: null };
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
showDetails(chart) {
|
||||||
|
this.$router.push(chart.detailLocation);
|
||||||
|
},
|
||||||
|
|
||||||
|
colorFor() {
|
||||||
|
return `color-1`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
list() {
|
||||||
|
const list = this.$store.getters['epinio/all'](EPINIO_TYPES.CATALOG_SERVICE);
|
||||||
|
|
||||||
|
if (!this.searchQuery) {
|
||||||
|
return list;
|
||||||
|
} else {
|
||||||
|
const query = this.searchQuery.toLowerCase();
|
||||||
|
|
||||||
|
return list.filter(e => e?.chart.toLowerCase().includes(query) || e?.description.toLowerCase().includes(query) || e?.short_description.toLowerCase().includes(query));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Loading v-if="$fetchState.pending" />
|
||||||
|
<div v-else>
|
||||||
|
<div class="filter-block">
|
||||||
|
<input
|
||||||
|
ref="searchQuery"
|
||||||
|
v-model="searchQuery"
|
||||||
|
type="search"
|
||||||
|
class="input-sm"
|
||||||
|
:placeholder="t('catalog.charts.search')"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SelectIconGrid
|
||||||
|
:rows="list"
|
||||||
|
:color-for="colorFor"
|
||||||
|
name-field="name"
|
||||||
|
icon-field="serviceIcon"
|
||||||
|
key-field="name"
|
||||||
|
description-field="short_description"
|
||||||
|
@clicked="(row) => showDetails(row)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.filter-block {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
input {
|
||||||
|
width: 315px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -32,6 +32,7 @@ export default {
|
||||||
submitted: false,
|
submitted: false,
|
||||||
mode: _CREATE,
|
mode: _CREATE,
|
||||||
touched: false,
|
touched: false,
|
||||||
|
resource: EPINIO_TYPES.NAMESPACE
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -110,7 +111,7 @@ export default {
|
||||||
<div>
|
<div>
|
||||||
<Masthead
|
<Masthead
|
||||||
:schema="schema"
|
:schema="schema"
|
||||||
:resource="'undefined'"
|
:resource="resource"
|
||||||
>
|
>
|
||||||
<template v-slot:createButton>
|
<template v-slot:createButton>
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import EpinioMetaResource from '~/pkg/epinio/models/epinio-namespaced-resource';
|
||||||
|
|
||||||
|
export default class EpinioAppChartModel extends EpinioMetaResource {
|
||||||
|
get links() {
|
||||||
|
return {
|
||||||
|
update: this.getUrl(),
|
||||||
|
self: this.getUrl(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getUrl(name = this.metadata?.name) {
|
||||||
|
// Add baseUrl in a generic way
|
||||||
|
return this.$getters['urlFor'](this.type, this.id, { url: `/api/v1/appcharts/${ name || '' }` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import Resource from '@shell/plugins/dashboard-store/resource-class';
|
import Resource from '@shell/plugins/dashboard-store/resource-class';
|
||||||
import { APPLICATION_ACTION_STATE, APPLICATION_MANIFEST_SOURCE_TYPE, APPLICATION_SOURCE_TYPE } from '../types';
|
import { APPLICATION_ACTION_STATE, APPLICATION_MANIFEST_SOURCE_TYPE, APPLICATION_SOURCE_TYPE, EPINIO_PRODUCT_NAME } from '../types';
|
||||||
import { epinioExceptionToErrorsArray } from '../utils/errors';
|
import { epinioExceptionToErrorsArray } from '../utils/errors';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
export const APPLICATION_ACTION_TYPE = {
|
export const APPLICATION_ACTION_TYPE = {
|
||||||
|
CREATE_NS: 'create_namespace',
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
GIT_FETCH: 'gitFetch',
|
GIT_FETCH: 'gitFetch',
|
||||||
UPLOAD: 'upload',
|
UPLOAD: 'upload',
|
||||||
|
|
@ -18,6 +19,10 @@ export default class ApplicationActionResource extends Resource {
|
||||||
run = true;
|
run = true;
|
||||||
state = APPLICATION_ACTION_STATE.PENDING;
|
state = APPLICATION_ACTION_STATE.PENDING;
|
||||||
|
|
||||||
|
// application; // : EpinioApplication;
|
||||||
|
// bindings; // : EpinioAppBindings;
|
||||||
|
// type; // : EPINIO_TYPES / string;
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return this.t(`epinio.applications.action.${ this.action }.label`);
|
return this.t(`epinio.applications.action.${ this.action }.label`);
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +66,9 @@ export default class ApplicationActionResource extends Resource {
|
||||||
|
|
||||||
async innerExecute(params) {
|
async innerExecute(params) {
|
||||||
switch (this.action) {
|
switch (this.action) {
|
||||||
|
case APPLICATION_ACTION_TYPE.CREATE_NS:
|
||||||
|
await this.createNamespace(params);
|
||||||
|
break;
|
||||||
case APPLICATION_ACTION_TYPE.CREATE:
|
case APPLICATION_ACTION_TYPE.CREATE:
|
||||||
await this.create(params);
|
await this.create(params);
|
||||||
break;
|
break;
|
||||||
|
|
@ -85,6 +93,12 @@ export default class ApplicationActionResource extends Resource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createNamespace() {
|
||||||
|
const ns = await this.$dispatch(`${ EPINIO_PRODUCT_NAME }/createNamespace`, { name: this.application.meta.namespace }, { root: true });
|
||||||
|
|
||||||
|
await ns.create();
|
||||||
|
}
|
||||||
|
|
||||||
async create() {
|
async create() {
|
||||||
await this.application.create();
|
await this.application.create();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { APPLICATION_MANIFEST_SOURCE_TYPE, EPINIO_PRODUCT_NAME, EPINIO_TYPES } from '../types';
|
import { APPLICATION_MANIFEST_SOURCE_TYPE, EPINIO_PRODUCT_NAME, EPINIO_TYPES } from '../types';
|
||||||
import { createEpinioRoute } from '../utils/custom-routing';
|
|
||||||
import { formatSi } from '@shell/utils/units';
|
import { formatSi } from '@shell/utils/units';
|
||||||
import { classify } from '@shell/plugins/dashboard-store/classify';
|
import { classify } from '@shell/plugins/dashboard-store/classify';
|
||||||
import EpinioMetaResource from './epinio-namespaced-resource';
|
import EpinioMetaResource from './epinio-namespaced-resource';
|
||||||
|
|
@ -41,18 +40,6 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
get listLocation() {
|
|
||||||
return this.$rootGetters['type-map/optionsFor'](this.type).customRoute || createEpinioRoute(`c-cluster-applications`, { cluster: this.$rootGetters['clusterId'] });
|
|
||||||
}
|
|
||||||
|
|
||||||
get parentLocationOverride() {
|
|
||||||
return this.listLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
get doneRoute() {
|
|
||||||
return this.listLocation.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get state() {
|
get state() {
|
||||||
return STATES_MAPPED[this.status] || STATES_MAPPED.unknown;
|
return STATES_MAPPED[this.status] || STATES_MAPPED.unknown;
|
||||||
}
|
}
|
||||||
|
|
@ -152,14 +139,6 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
get nsLocation() {
|
|
||||||
return createEpinioRoute(`c-cluster-resource-id`, {
|
|
||||||
cluster: this.$rootGetters['clusterId'],
|
|
||||||
resource: EPINIO_TYPES.NAMESPACE,
|
|
||||||
id: this.meta.namespace
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get links() {
|
get links() {
|
||||||
return {
|
return {
|
||||||
update: this.getUrl(),
|
update: this.getUrl(),
|
||||||
|
|
@ -225,10 +204,6 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
||||||
return Object.keys(this.configuration?.environment || []).length;
|
return Object.keys(this.configuration?.environment || []).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
get configCount() {
|
|
||||||
return this.configuration?.configurations.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
get routeCount() {
|
get routeCount() {
|
||||||
return this.configuration?.routes.length;
|
return this.configuration?.routes.length;
|
||||||
}
|
}
|
||||||
|
|
@ -257,14 +232,26 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
||||||
if (!this.origin) {
|
if (!this.origin) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const appChart = {
|
||||||
|
label: 'App Chart',
|
||||||
|
value: this.configuration.appchart
|
||||||
|
};
|
||||||
|
|
||||||
switch (this.origin.Kind) { // APPLICATION_MANIFEST_SOURCE_TYPE
|
switch (this.origin.Kind) { // APPLICATION_MANIFEST_SOURCE_TYPE
|
||||||
case APPLICATION_MANIFEST_SOURCE_TYPE.PATH:
|
case APPLICATION_MANIFEST_SOURCE_TYPE.PATH:
|
||||||
return { label: 'File system', icon: 'icon-file' };
|
return {
|
||||||
|
label: 'File system',
|
||||||
|
icon: 'icon-file',
|
||||||
|
details: [
|
||||||
|
appChart
|
||||||
|
]
|
||||||
|
};
|
||||||
case APPLICATION_MANIFEST_SOURCE_TYPE.GIT:
|
case APPLICATION_MANIFEST_SOURCE_TYPE.GIT:
|
||||||
return {
|
return {
|
||||||
label: 'Git',
|
label: 'Git',
|
||||||
icon: 'icon-file',
|
icon: 'icon-file',
|
||||||
details: [{
|
details: [
|
||||||
|
appChart, {
|
||||||
label: 'Url',
|
label: 'Url',
|
||||||
value: this.origin.git.repository
|
value: this.origin.git.repository
|
||||||
}, {
|
}, {
|
||||||
|
|
@ -277,7 +264,8 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
||||||
return {
|
return {
|
||||||
label: 'Container',
|
label: 'Container',
|
||||||
icon: 'icon-docker',
|
icon: 'icon-docker',
|
||||||
details: [{
|
details: [
|
||||||
|
appChart, {
|
||||||
label: 'Image',
|
label: 'Image',
|
||||||
value: this.origin.Container || this.origin.container
|
value: this.origin.Container || this.origin.container
|
||||||
}]
|
}]
|
||||||
|
|
@ -370,6 +358,7 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
||||||
data: {
|
data: {
|
||||||
name: this.meta.name,
|
name: this.meta.name,
|
||||||
configuration: {
|
configuration: {
|
||||||
|
appchart: this.configuration.appchart,
|
||||||
instances: this.configuration.instances,
|
instances: this.configuration.instances,
|
||||||
configurations: this.configuration.configurations,
|
configurations: this.configuration.configurations,
|
||||||
environment: this.configuration.environment,
|
environment: this.configuration.environment,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,18 @@
|
||||||
|
import { EPINIO_TYPES } from '@pkg/types';
|
||||||
|
import { createEpinioRoute } from '@pkg/utils/custom-routing';
|
||||||
import EpinioMetaResource from './epinio-namespaced-resource';
|
import EpinioMetaResource from './epinio-namespaced-resource';
|
||||||
|
import { EPINIO_SERVICE_PARAM } from '../edit/services.vue';
|
||||||
|
|
||||||
export default class EpinioCatalogServiceModel extends EpinioMetaResource {
|
export default class EpinioCatalogServiceModel extends EpinioMetaResource {
|
||||||
|
get _availableActions() {
|
||||||
|
return [{
|
||||||
|
action: 'createService',
|
||||||
|
label: this.t('generic.create'),
|
||||||
|
icon: 'icon icon-fw icon-chevron-up',
|
||||||
|
enabled: true,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
get links() {
|
get links() {
|
||||||
return {
|
return {
|
||||||
update: this.getUrl(),
|
update: this.getUrl(),
|
||||||
|
|
@ -14,4 +26,45 @@ export default class EpinioCatalogServiceModel extends EpinioMetaResource {
|
||||||
// Add baseUrl in a generic way
|
// Add baseUrl in a generic way
|
||||||
return this.$getters['urlFor'](this.type, this.id, { url: `/api/v1/catalogservices/${ name || '' }` });
|
return this.$getters['urlFor'](this.type, this.id, { url: `/api/v1/catalogservices/${ name || '' }` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get details() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: this.t('epinio.catalogService.detail.appVersion'),
|
||||||
|
content: this.appVersion,
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
// label: this.t('epinio.catalogService.detail.chartVersion'),
|
||||||
|
// content: this.chartVersion,
|
||||||
|
// }, {
|
||||||
|
// label: this.t('epinio.catalogService.detail.helmChart'),
|
||||||
|
// content: this.helm_repo.name,
|
||||||
|
// formatter: `Link`,
|
||||||
|
// formatterOpts: {
|
||||||
|
// urlKey: 'helm_repo.url',
|
||||||
|
// labelKey: 'helm_repo.name',
|
||||||
|
// row: this,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
get services() {
|
||||||
|
return this.$getters['all'](EPINIO_TYPES.SERVICE_INSTANCE)
|
||||||
|
.filter((s) => {
|
||||||
|
return s.catalog_service === this.name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createService() {
|
||||||
|
const serviceCreateLocation = createEpinioRoute(`c-cluster-resource-create`, {
|
||||||
|
cluster: this.$rootGetters['clusterId'],
|
||||||
|
resource: EPINIO_TYPES.SERVICE_INSTANCE,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.currentRouter().push({
|
||||||
|
...serviceCreateLocation,
|
||||||
|
query: { [EPINIO_SERVICE_PARAM]: this.name }
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export default class EpinioConfigurationModel extends EpinioNamespacedResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
get isServiceRelated() {
|
get isServiceRelated() {
|
||||||
return !!this.configuration.origin;
|
return !!this.configuration?.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
get service() {
|
get service() {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,14 @@ export default class EpinioResource extends Resource {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get parentLocationOverride() {
|
||||||
|
return this.listLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
get doneRoute() {
|
||||||
|
return this.listLocation.name;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
get canClone() {
|
get canClone() {
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,13 @@ export default class EpinioNamespace extends EpinioMetaResource {
|
||||||
const namespaces = await this.$dispatch('findAll', { type: this.type, opt: { force: true } });
|
const namespaces = await this.$dispatch('findAll', { type: this.type, opt: { force: true } });
|
||||||
|
|
||||||
// Find new namespace
|
// Find new namespace
|
||||||
// return new namespace
|
|
||||||
return namespaces.filter(n => n.name === this.name)?.[0];
|
return namespaces.filter(n => n.name === this.name)?.[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
return this.create();
|
||||||
|
}
|
||||||
|
|
||||||
get canClone() {
|
get canClone() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { createEpinioRoute } from '@pkg/utils/custom-routing';
|
||||||
import { EPINIO_TYPES } from '~/pkg/epinio/types';
|
import { EPINIO_TYPES } from '~/pkg/epinio/types';
|
||||||
import EpinioNamespacedResource from './epinio-namespaced-resource';
|
import EpinioNamespacedResource from './epinio-namespaced-resource';
|
||||||
|
|
||||||
|
|
@ -36,6 +37,14 @@ export default class EpinioServiceModel extends EpinioNamespacedResource {
|
||||||
return this.status;
|
return this.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get serviceLocation() {
|
||||||
|
return createEpinioRoute(`c-cluster-resource-id`, {
|
||||||
|
cluster: this.$rootGetters['clusterId'],
|
||||||
|
resource: EPINIO_TYPES.CATALOG_SERVICE,
|
||||||
|
id: this.catalog_service
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async create() {
|
async create() {
|
||||||
await this.followLink('create', {
|
await this.followLink('create', {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,10 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
],
|
],
|
||||||
|
|
||||||
async fetch() {
|
async fetch() {
|
||||||
await this.$store.dispatch('epinio/findAll', { type: EPINIO_TYPES.NAMESPACE });
|
await Promise.all([
|
||||||
|
this.$store.dispatch('epinio/findAll', { type: EPINIO_TYPES.NAMESPACE }),
|
||||||
|
this.$store.dispatch('epinio/findAll', { type: EPINIO_TYPES.APP_CHARTS }),
|
||||||
|
]);
|
||||||
|
|
||||||
this.originalModel = await this.$store.dispatch(`epinio/create`, { type: EPINIO_TYPES.APP });
|
this.originalModel = await this.$store.dispatch(`epinio/create`, { type: EPINIO_TYPES.APP });
|
||||||
// Dissassociate the original model & model. This fixes `Create` after refreshing page with SSR on
|
// Dissassociate the original model & model. This fixes `Create` after refreshing page with SSR on
|
||||||
|
|
@ -97,7 +100,14 @@ export default Vue.extend<Data, any, any, any>({
|
||||||
|
|
||||||
updateSource(changes: EpinioAppSource) {
|
updateSource(changes: EpinioAppSource) {
|
||||||
this.source = {};
|
this.source = {};
|
||||||
this.set(this.source, changes);
|
const { appChart, ...cleanChanges } = changes;
|
||||||
|
|
||||||
|
if (appChart) {
|
||||||
|
// app chart actuall belongs in config, so stick it in there
|
||||||
|
this.value.configuration = this.value.configuration || {};
|
||||||
|
this.set(this.value.configuration, { appchart: appChart });
|
||||||
|
}
|
||||||
|
this.set(this.source, cleanChanges);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateManifestConfigurations(changes: string[]) {
|
updateManifestConfigurations(changes: string[]) {
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ import Masthead from '@shell/components/ResourceList/Masthead';
|
||||||
import LinkDetail from '@shell/components/formatter/LinkDetail';
|
import LinkDetail from '@shell/components/formatter/LinkDetail';
|
||||||
import { EPINIO_TYPES } from '../../../../types';
|
import { EPINIO_TYPES } from '../../../../types';
|
||||||
import { createEpinioRoute } from '../../../../utils/custom-routing';
|
import { createEpinioRoute } from '../../../../utils/custom-routing';
|
||||||
|
import EpinioIntro from '../../../../components/EpinioIntro.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Loading,
|
Loading,
|
||||||
LinkDetail,
|
LinkDetail,
|
||||||
ResourceTable,
|
ResourceTable,
|
||||||
Masthead
|
Masthead,
|
||||||
|
EpinioIntro
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetch() {
|
async fetch() {
|
||||||
|
|
@ -47,6 +49,10 @@ export default {
|
||||||
rows() {
|
rows() {
|
||||||
return this.$store.getters['epinio/all'](this.resource);
|
return this.$store.getters['epinio/all'](this.resource);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hasNamespaces() {
|
||||||
|
return !!this.$store.getters['epinio/all'](EPINIO_TYPES.NAMESPACE)?.length;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -54,6 +60,7 @@ export default {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Loading v-if="$fetchState.pending" />
|
<Loading v-if="$fetchState.pending" />
|
||||||
|
<EpinioIntro v-else-if="!hasNamespaces" />
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<Masthead
|
<Masthead
|
||||||
:schema="schema"
|
:schema="schema"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { base64Encode } from '@shell/utils/crypto';
|
||||||
import { NAMESPACE_FILTERS } from '@shell/store/prefs';
|
import { NAMESPACE_FILTERS } from '@shell/store/prefs';
|
||||||
import { createNamespaceFilterKeyWithId } from '@shell/utils/namespace-filter';
|
import { createNamespaceFilterKeyWithId } from '@shell/utils/namespace-filter';
|
||||||
import { parse as parseUrl, stringify as unParseUrl } from '@shell/utils/url';
|
import { parse as parseUrl, stringify as unParseUrl } from '@shell/utils/url';
|
||||||
// import https from 'https';
|
import { classify } from '@shell/plugins/dashboard-store/classify';
|
||||||
|
|
||||||
const createId = (schema: any, resource: any) => {
|
const createId = (schema: any, resource: any) => {
|
||||||
const name = resource.meta?.name || resource.name;
|
const name = resource.meta?.name || resource.name;
|
||||||
|
|
@ -178,6 +178,13 @@ export default {
|
||||||
collectionMethods: ['get', 'post'],
|
collectionMethods: ['get', 'post'],
|
||||||
resourceFields: { },
|
resourceFields: { },
|
||||||
attributes: { namespaced: true }
|
attributes: { namespaced: true }
|
||||||
|
}, {
|
||||||
|
product: EPINIO_PRODUCT_NAME,
|
||||||
|
id: EPINIO_TYPES.APP_CHARTS,
|
||||||
|
type: 'schema',
|
||||||
|
links: { collection: '/api/v1/appcharts' },
|
||||||
|
collectionMethods: ['get'],
|
||||||
|
resourceFields: { },
|
||||||
}, {
|
}, {
|
||||||
product: EPINIO_PRODUCT_NAME,
|
product: EPINIO_PRODUCT_NAME,
|
||||||
id: EPINIO_TYPES.NAMESPACE,
|
id: EPINIO_TYPES.NAMESPACE,
|
||||||
|
|
@ -264,5 +271,13 @@ export default {
|
||||||
commit('singleProductCNSI', cnsi);
|
commit('singleProductCNSI', cnsi);
|
||||||
|
|
||||||
return cnsi;
|
return cnsi;
|
||||||
|
},
|
||||||
|
|
||||||
|
createNamespace(ctx: any, obj: { name : string }) {
|
||||||
|
// Note - created model save --> create
|
||||||
|
return classify(ctx, {
|
||||||
|
type: EPINIO_TYPES.NAMESPACE,
|
||||||
|
meta: { name: obj.name }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,9 @@
|
||||||
"@shell/models/*": [
|
"@shell/models/*": [
|
||||||
"../../shell/models/*"
|
"../../shell/models/*"
|
||||||
],
|
],
|
||||||
|
"@components/*": [
|
||||||
|
"../../pkg/rancher-components/*"
|
||||||
|
],
|
||||||
"@pkg/*": [
|
"@pkg/*": [
|
||||||
"./*"
|
"./*"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import EpinioApplicationModel from './models/applications';
|
||||||
import EpinioCatalogServiceModel from './models/catalogservices';
|
import EpinioCatalogServiceModel from './models/catalogservices';
|
||||||
import EpinioConfigurationModel from './models/configurations';
|
import EpinioConfigurationModel from './models/configurations';
|
||||||
import EpinioServiceModel from './models/services';
|
import EpinioServiceModel from './models/services';
|
||||||
|
import EpinioAppChartModel from './models/appcharts';
|
||||||
|
|
||||||
export const EPINIO_PRODUCT_NAME = 'epinio';
|
export const EPINIO_PRODUCT_NAME = 'epinio';
|
||||||
|
|
||||||
|
|
@ -13,6 +14,7 @@ export const EPINIO_STANDALONE_CLUSTER_NAME = 'default';
|
||||||
export const EPINIO_TYPES = {
|
export const EPINIO_TYPES = {
|
||||||
// From API
|
// From API
|
||||||
APP: 'applications',
|
APP: 'applications',
|
||||||
|
APP_CHARTS: 'appcharts',
|
||||||
NAMESPACE: 'namespaces',
|
NAMESPACE: 'namespaces',
|
||||||
CONFIGURATION: 'configurations',
|
CONFIGURATION: 'configurations',
|
||||||
CATALOG_SERVICE: 'catalogservices',
|
CATALOG_SERVICE: 'catalogservices',
|
||||||
|
|
@ -65,6 +67,7 @@ export interface EpinioApplicationResource {
|
||||||
configuration: {
|
configuration: {
|
||||||
instances: number,
|
instances: number,
|
||||||
configurations: string[],
|
configurations: string[],
|
||||||
|
appchart?: string,
|
||||||
environment: Map<string, string>,
|
environment: Map<string, string>,
|
||||||
routes: string[]
|
routes: string[]
|
||||||
},
|
},
|
||||||
|
|
@ -83,6 +86,15 @@ export interface EpinioApplicationResource {
|
||||||
|
|
||||||
export type EpinioApplication = EpinioApplicationResource & EpinioApplicationModel & EpinioMetaProperty;
|
export type EpinioApplication = EpinioApplicationResource & EpinioApplicationModel & EpinioMetaProperty;
|
||||||
|
|
||||||
|
export interface EpinioApplicationChartResource {
|
||||||
|
meta: EpinioMeta,
|
||||||
|
description: string,
|
||||||
|
helm_chart: string, // eslint-disable-line camelcase
|
||||||
|
short_description: string, // eslint-disable-line camelcase
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EpinioAppChart = EpinioApplicationChartResource & EpinioAppChartModel & EpinioMetaProperty;
|
||||||
|
|
||||||
export interface EpinioHelmRepoResource {
|
export interface EpinioHelmRepoResource {
|
||||||
name: string,
|
name: string,
|
||||||
url: string,
|
url: string,
|
||||||
|
|
@ -116,6 +128,7 @@ export interface EpinioServiceResource {
|
||||||
meta: EpinioMeta
|
meta: EpinioMeta
|
||||||
boundapps: string[],
|
boundapps: string[],
|
||||||
catalog_service: string, // eslint-disable-line camelcase
|
catalog_service: string, // eslint-disable-line camelcase
|
||||||
|
catalog_service_version: string, // eslint-disable-line camelcase
|
||||||
status: string,
|
status: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
selectNamespace(e) {
|
selectNamespace(e) {
|
||||||
if (e.value === '') { // The blank value in the dropdown is labeled "Create a New Namespace"
|
if (!e || e.value === '') { // The blank value in the dropdown is labeled "Create a New Namespace"
|
||||||
this.createNamespace = true;
|
this.createNamespace = true;
|
||||||
this.$parent.$emit('createNamespace', true);
|
this.$parent.$emit('createNamespace', true);
|
||||||
Vue.nextTick(() => this.$refs.namespace.focus());
|
Vue.nextTick(() => this.$refs.namespace.focus());
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,7 @@ export default {
|
||||||
<div class="rd-header-right">
|
<div class="rd-header-right">
|
||||||
<HarvesterUpgrade v-if="isVirtualCluster" />
|
<HarvesterUpgrade v-if="isVirtualCluster" />
|
||||||
<div
|
<div
|
||||||
v-if="currentCluster && !simple && (currentProduct.showNamespaceFilter || currentProduct.showWorkspaceSwitcher)"
|
v-if="(currentCluster || currentProduct.customNamespaceFilter) && !simple && (currentProduct.showNamespaceFilter || currentProduct.showWorkspaceSwitcher)"
|
||||||
class="top"
|
class="top"
|
||||||
>
|
>
|
||||||
<NamespaceFilter v-if="clusterReady && currentProduct && (currentProduct.showNamespaceFilter || isExplorer)" />
|
<NamespaceFilter v-if="clusterReady && currentProduct && (currentProduct.showNamespaceFilter || isExplorer)" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue