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
|
||||
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
|
||||
uses: actions/upload-artifact@v2
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ set -e
|
|||
echo "GITHUB_SHA: $GITHUB_SHA"
|
||||
echo "GITHUB_REF_NAME: $GITHUB_REF_NAME"
|
||||
echo "ROUTER_BASE: $ROUTER_BASE"
|
||||
echo
|
||||
echo "RANCHER_ENV: $RANCHER_ENV"
|
||||
echo "EXCLUDES_PKG: $EXCLUDES_PKG"
|
||||
echo
|
||||
echo "RELEASE_DIR: $RELEASE_DIR"
|
||||
RELEASE_LOCATION="$RELEASE_DIR/$ARTIFACT_NAME"
|
||||
|
|
@ -26,7 +28,7 @@ echo Installing dependencies
|
|||
yarn install --frozen-lockfile
|
||||
|
||||
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
|
||||
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 KeyValue from '@shell/components/form/KeyValue.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 { sortBy } from '@shell/utils/sort';
|
||||
import { validateKubernetesName } from '@shell/utils/validators/kubernetes-name';
|
||||
|
||||
export interface EpinioAppInfo {
|
||||
meta: {
|
||||
|
|
@ -24,7 +25,7 @@ export interface EpinioAppInfo {
|
|||
|
||||
interface Data {
|
||||
errors: string[],
|
||||
values: EpinioAppInfo
|
||||
values?: EpinioAppInfo
|
||||
}
|
||||
|
||||
// Data, Methods, Computed, Props
|
||||
|
|
@ -35,7 +36,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
NameNsDescription,
|
||||
LabeledInput,
|
||||
KeyValue,
|
||||
Banner
|
||||
Loading
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -52,17 +53,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
data() {
|
||||
return {
|
||||
errors: [],
|
||||
values: {
|
||||
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 || [],
|
||||
},
|
||||
}
|
||||
values: undefined
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -70,7 +61,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
this.values = {
|
||||
meta: {
|
||||
name: this.application.meta?.name,
|
||||
namespace: this.application.meta?.namespace
|
||||
namespace: this.application.meta?.namespace || this.namespaces[0]?.metadata.name
|
||||
},
|
||||
configuration: {
|
||||
instances: this.application.configuration?.instances || 1,
|
||||
|
|
@ -105,8 +96,13 @@ export default Vue.extend<Data, any, any, any>({
|
|||
},
|
||||
|
||||
valid() {
|
||||
if (!this.values) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
|
||||
return validName && validNamespace && validInstances;
|
||||
|
|
@ -127,11 +123,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!namespaces.length">
|
||||
<Banner color="warning">
|
||||
{{ t('epinio.warnings.noNamespace') }}
|
||||
</Banner>
|
||||
</div>
|
||||
<Loading v-if="!values" />
|
||||
<div v-else>
|
||||
<div class="col">
|
||||
<NameNsDescription
|
||||
|
|
@ -143,6 +135,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
:value="values.meta"
|
||||
:mode="mode"
|
||||
@change="update"
|
||||
@createNamespace="ns => values.meta.namespace = ns"
|
||||
/>
|
||||
</div>
|
||||
<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 { EpinioAppSource } from '../../components/application/AppSource.vue';
|
||||
import { EpinioAppBindings } from '../../components/application/AppConfiguration.vue';
|
||||
import EpinioNamespace from '~/pkg/epinio/models/namespaces';
|
||||
|
||||
interface Data {
|
||||
running: boolean;
|
||||
|
|
@ -35,7 +36,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
},
|
||||
bindings: {
|
||||
type: Object as PropType<EpinioAppBindings>,
|
||||
required: true
|
||||
default: () => null
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
|
|
@ -48,22 +49,34 @@ export default Vue.extend<Data, any, any, any>({
|
|||
},
|
||||
|
||||
async fetch() {
|
||||
const coreArgs = {
|
||||
const coreArgs: Partial<ApplicationAction & {
|
||||
application: EpinioApplication,
|
||||
bindings: EpinioAppBindings,
|
||||
type: string,
|
||||
}> = {
|
||||
application: this.application,
|
||||
bindings: this.bindings,
|
||||
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', {
|
||||
action: APPLICATION_ACTION_TYPE.CREATE,
|
||||
index: 0, // index used for sorting
|
||||
index: 1, // index used for sorting
|
||||
...coreArgs,
|
||||
}));
|
||||
|
||||
if (this.bindings?.configurations?.length) {
|
||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||
action: APPLICATION_ACTION_TYPE.BIND_CONFIGURATIONS,
|
||||
index: 1,
|
||||
index: 2,
|
||||
...coreArgs,
|
||||
}));
|
||||
}
|
||||
|
|
@ -71,7 +84,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
if (this.bindings?.services?.length) {
|
||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||
action: APPLICATION_ACTION_TYPE.BIND_SERVICES,
|
||||
index: 2,
|
||||
index: 3,
|
||||
...coreArgs,
|
||||
}));
|
||||
}
|
||||
|
|
@ -80,7 +93,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
this.source.type === APPLICATION_SOURCE_TYPE.FOLDER) {
|
||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||
action: APPLICATION_ACTION_TYPE.UPLOAD,
|
||||
index: 3,
|
||||
index: 4,
|
||||
...coreArgs,
|
||||
}));
|
||||
}
|
||||
|
|
@ -88,7 +101,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
if (this.source.type === APPLICATION_SOURCE_TYPE.GIT_URL) {
|
||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||
action: APPLICATION_ACTION_TYPE.GIT_FETCH,
|
||||
index: 3,
|
||||
index: 4,
|
||||
...coreArgs,
|
||||
}));
|
||||
}
|
||||
|
|
@ -98,14 +111,14 @@ export default Vue.extend<Data, any, any, any>({
|
|||
this.source.type === APPLICATION_SOURCE_TYPE.GIT_URL) {
|
||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||
action: APPLICATION_ACTION_TYPE.BUILD,
|
||||
index: 4,
|
||||
index: 5,
|
||||
...coreArgs,
|
||||
}));
|
||||
}
|
||||
|
||||
this.actions.push(await this.$store.dispatch('epinio/create', {
|
||||
action: APPLICATION_ACTION_TYPE.DEPLOY,
|
||||
index: 5,
|
||||
index: 6,
|
||||
...coreArgs,
|
||||
}));
|
||||
|
||||
|
|
@ -121,7 +134,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
labelKey: 'epinio.applications.steps.progress.table.stage.label',
|
||||
value: 'name',
|
||||
sort: ['index'],
|
||||
width: 100,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
...DESCRIPTION,
|
||||
|
|
@ -144,7 +157,11 @@ export default Vue.extend<Data, any, any, any>({
|
|||
computed: {
|
||||
actionsToRun() {
|
||||
return this.actions.filter((action: ApplicationAction) => action.run);
|
||||
}
|
||||
},
|
||||
|
||||
namespaces() {
|
||||
return this.$store.getters['epinio/all'](EPINIO_TYPES.NAMESPACE);
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ import FileSelector from '@shell/components/form/FileSelector.vue';
|
|||
import RadioGroup from '@components/Form/Radio/RadioGroup.vue';
|
||||
import { sortBy } from '@shell/utils/sort';
|
||||
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';
|
||||
|
||||
interface Archive{
|
||||
|
|
@ -34,6 +35,7 @@ interface BuilderImage {
|
|||
}
|
||||
|
||||
interface Data {
|
||||
open: boolean,
|
||||
archive: Archive,
|
||||
container: Container,
|
||||
gitUrl: GitUrl,
|
||||
|
|
@ -49,6 +51,12 @@ export interface EpinioAppSource {
|
|||
container: Container,
|
||||
gitUrl: GitUrl,
|
||||
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';
|
||||
|
|
@ -60,7 +68,8 @@ export default Vue.extend<Data, any, any, any>({
|
|||
FileSelector,
|
||||
LabeledInput,
|
||||
LabeledSelect,
|
||||
RadioGroup
|
||||
RadioGroup,
|
||||
Collapse
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -80,6 +89,8 @@ export default Vue.extend<Data, any, any, any>({
|
|||
|
||||
data() {
|
||||
return {
|
||||
open: false,
|
||||
|
||||
archive: {
|
||||
tarball: this.source?.archive.tarball || '',
|
||||
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,
|
||||
},
|
||||
|
||||
appChart: this.source?.appChart,
|
||||
|
||||
types: [{
|
||||
label: this.t('epinio.applications.steps.source.archive.label'),
|
||||
value: APPLICATION_SOURCE_TYPE.ARCHIVE
|
||||
|
|
@ -116,6 +129,9 @@ export default Vue.extend<Data, any, any, any>({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
if (!this.appChart) {
|
||||
Vue.set(this, 'appChart', this.appCharts[0].value);
|
||||
}
|
||||
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, 'branch', parsed.origin.git.revision);
|
||||
}
|
||||
if (parsed.configuration) {
|
||||
Vue.set(this, 'appChart', parsed.configuration.appchart);
|
||||
}
|
||||
|
||||
const appInfo: EpinioAppInfo = {
|
||||
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 = '';
|
||||
|
||||
// Determine parent folder name
|
||||
for (const f of files) {
|
||||
for (const f of safeFiles) {
|
||||
const paths = f.webkitRelativePath.split('/');
|
||||
|
||||
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;
|
||||
|
||||
if (folderName) {
|
||||
|
|
@ -211,7 +231,8 @@ export default Vue.extend<Data, any, any, any>({
|
|||
archive: this.archive,
|
||||
container: this.container,
|
||||
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');
|
||||
},
|
||||
|
||||
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() {
|
||||
// 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
|
||||
|
|
@ -387,27 +415,42 @@ export default Vue.extend<Data, any, any, any>({
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="showBuilderImage">
|
||||
<div class="spacer">
|
||||
<RadioGroup
|
||||
name="defaultBuilderImage"
|
||||
data-testid="epinio_app-source_builder-select"
|
||||
:value="builderImage.default"
|
||||
:labels="[t('epinio.applications.steps.source.archive.builderimage.default'), t('epinio.applications.steps.source.archive.builderimage.custom')]"
|
||||
:options="[true, false]"
|
||||
:label-key="'epinio.applications.steps.source.archive.builderimage.label'"
|
||||
@input="onImageType"
|
||||
/>
|
||||
<LabeledInput
|
||||
v-model="builderImage.value"
|
||||
data-testid="epinio_app-source_builder-value"
|
||||
:disabled="builderImage.default"
|
||||
:tooltip="t('epinio.applications.steps.source.archive.builderimage.tooltip')"
|
||||
<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"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="showBuilderImage">
|
||||
<RadioGroup
|
||||
class="mt-20"
|
||||
name="defaultBuilderImage"
|
||||
data-testid="epinio_app-source_builder-select"
|
||||
:value="builderImage.default"
|
||||
:labels="[t('epinio.applications.steps.source.archive.builderimage.default'), t('epinio.applications.steps.source.archive.builderimage.custom')]"
|
||||
:options="[true, false]"
|
||||
:label-key="'epinio.applications.steps.source.archive.builderimage.label'"
|
||||
@input="onImageType"
|
||||
/>
|
||||
<LabeledInput
|
||||
v-model="builderImage.value"
|
||||
data-testid="epinio_app-source_builder-value"
|
||||
:disabled="builderImage.default"
|
||||
:tooltip="t('epinio.applications.steps.source.archive.builderimage.tooltip')"
|
||||
:mode="mode"
|
||||
@input="update"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</Collapse>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -423,6 +466,10 @@ export default Vue.extend<Data, any, any, any>({
|
|||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.collapse {
|
||||
margin-left: -5px;
|
||||
}
|
||||
}
|
||||
.archive {
|
||||
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 }) });
|
||||
|
||||
// App resource
|
||||
weightType(EPINIO_TYPES.APP, 300, true);
|
||||
configureType(EPINIO_TYPES.APP, {
|
||||
isCreatable: true,
|
||||
isEditable: true,
|
||||
|
|
@ -81,8 +80,17 @@ export function init($plugin: any, store: any) {
|
|||
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
|
||||
weightType(EPINIO_TYPES.CONFIGURATION, 200, true);
|
||||
configureType(EPINIO_TYPES.CONFIGURATION, {
|
||||
isCreatable: true,
|
||||
isEditable: true,
|
||||
|
|
@ -92,12 +100,11 @@ export function init($plugin: any, store: any) {
|
|||
customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.CONFIGURATION }),
|
||||
});
|
||||
|
||||
// Groups
|
||||
const ADVANCED_GROUP = 'Advanced';
|
||||
const SERVICE_GROUP = 'Services';
|
||||
|
||||
weightGroup(SERVICE_GROUP, 1, true);
|
||||
|
||||
// Service Instance
|
||||
weightType(EPINIO_TYPES.SERVICE_INSTANCE, 151, true);
|
||||
configureType(EPINIO_TYPES.SERVICE_INSTANCE, {
|
||||
isCreatable: true,
|
||||
isEditable: true,
|
||||
|
|
@ -108,7 +115,6 @@ export function init($plugin: any, store: any) {
|
|||
});
|
||||
|
||||
// Catalog Service
|
||||
weightType(EPINIO_TYPES.CATALOG_SERVICE, 150, true);
|
||||
configureType(EPINIO_TYPES.CATALOG_SERVICE, {
|
||||
isCreatable: false,
|
||||
isEditable: false,
|
||||
|
|
@ -119,7 +125,6 @@ export function init($plugin: any, store: any) {
|
|||
});
|
||||
|
||||
// Namespace resource
|
||||
weightType(EPINIO_TYPES.NAMESPACE, 100, true);
|
||||
configureType(EPINIO_TYPES.NAMESPACE, {
|
||||
isCreatable: 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.
|
||||
});
|
||||
|
||||
// Side Nav
|
||||
weightType(EPINIO_TYPES.CATALOG_SERVICE, 150, true);
|
||||
weightType(EPINIO_TYPES.SERVICE_INSTANCE, 151, true);
|
||||
basicType([
|
||||
EPINIO_TYPES.SERVICE_INSTANCE,
|
||||
EPINIO_TYPES.CATALOG_SERVICE,
|
||||
], 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([
|
||||
EPINIO_TYPES.APP,
|
||||
SERVICE_GROUP,
|
||||
EPINIO_TYPES.NAMESPACE,
|
||||
EPINIO_TYPES.CONFIGURATION
|
||||
ADVANCED_GROUP
|
||||
]);
|
||||
|
||||
headers(EPINIO_TYPES.APP, [
|
||||
|
|
@ -150,8 +169,6 @@ export function init($plugin: any, store: any) {
|
|||
labelKey: 'epinio.tableHeaders.namespace',
|
||||
value: 'meta.namespace',
|
||||
sort: ['meta.namespace'],
|
||||
formatter: 'LinkDetail',
|
||||
formatterOpts: { reference: 'nsLocation' }
|
||||
},
|
||||
{
|
||||
name: 'dep-status',
|
||||
|
|
@ -266,8 +283,6 @@ export function init($plugin: any, store: any) {
|
|||
labelKey: 'epinio.tableHeaders.namespace',
|
||||
value: 'meta.namespace',
|
||||
sort: ['meta.namespace'],
|
||||
formatter: 'LinkDetail',
|
||||
formatterOpts: { reference: 'nsLocation' }
|
||||
},
|
||||
{
|
||||
name: 'boundApps',
|
||||
|
|
@ -298,20 +313,26 @@ export function init($plugin: any, store: any) {
|
|||
|
||||
headers(EPINIO_TYPES.SERVICE_INSTANCE, [
|
||||
STATE,
|
||||
SIMPLE_NAME,
|
||||
NAME,
|
||||
{
|
||||
name: 'namespace',
|
||||
labelKey: 'epinio.tableHeaders.namespace',
|
||||
value: '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',
|
||||
labelKey: 'epinio.serviceInstance.tableHeaders.service',
|
||||
value: 'catalog_service',
|
||||
sort: ['catalog_service'],
|
||||
{
|
||||
name: 'catalog_service',
|
||||
labelKey: 'epinio.serviceInstance.tableHeaders.service',
|
||||
value: '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',
|
||||
|
|
@ -338,4 +359,21 @@ export function init($plugin: any, store: any) {
|
|||
},
|
||||
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 { epinioExceptionToErrorsArray } from '../utils/errors';
|
||||
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 {
|
||||
}
|
||||
|
|
@ -19,7 +21,9 @@ export default Vue.extend<Data, any, any, any>({
|
|||
ConsumptionGauge,
|
||||
ResourceTable,
|
||||
PlusMinus,
|
||||
ApplicationCard
|
||||
ApplicationCard,
|
||||
Tabbed,
|
||||
Tab,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
|
|
@ -35,12 +39,35 @@ export default Vue.extend<Data, any, any, any>({
|
|||
required: true
|
||||
},
|
||||
},
|
||||
fetch() {
|
||||
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.SERVICE_INSTANCE });
|
||||
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.CONFIGURATION });
|
||||
},
|
||||
|
||||
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 {
|
||||
appInstanceSchema: this.$store.getters[`${ EPINIO_PRODUCT_NAME }/schemaFor`](EPINIO_TYPES.APP_INSTANCE),
|
||||
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: {
|
||||
async updateInstances(newInstances: number) {
|
||||
this.$set(this, 'saving', true);
|
||||
|
|
@ -58,6 +85,12 @@ export default Vue.extend<Data, any, any, any>({
|
|||
|
||||
return `${ matchGithub?.[4] }/${ matchGithub?.[5] }`;
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
sourceIcon(): string {
|
||||
return this.value.sourceInfo?.icon || 'icon-epinio';
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
@ -68,7 +101,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
<ApplicationCard>
|
||||
<!-- Icon slot -->
|
||||
<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>
|
||||
|
||||
<!-- Routes links slot -->
|
||||
|
|
@ -87,25 +120,24 @@ export default Vue.extend<Data, any, any, any>({
|
|||
|
||||
<!-- Resources count slot -->
|
||||
<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>
|
||||
{{ value.envCount }} {{ t('epinio.applications.detail.counts.envVars') }}
|
||||
</div>
|
||||
<div>
|
||||
{{ value.serviceConfigurations.length }} {{ t('epinio.applications.detail.counts.services') }}
|
||||
</div>
|
||||
<div>
|
||||
{{ value.baseConfigurations.length }} {{ t('epinio.applications.detail.counts.config') }}
|
||||
</div>
|
||||
</template>
|
||||
</ApplicationCard>
|
||||
</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') }}
|
||||
</h3>
|
||||
|
||||
<div class="deployment">
|
||||
<div v-if="value.deployment" class="deployment">
|
||||
<div class="simple-box-row app-instances">
|
||||
<SimpleBox>
|
||||
<ConsumptionGauge
|
||||
|
|
@ -165,28 +197,41 @@ export default Vue.extend<Data, any, any, any>({
|
|||
</thead>
|
||||
<tr>
|
||||
<td>{{ t('tableHeaders.memory') }}</td>
|
||||
<td>{{ value.instanceMemory.min }} MiB</td>
|
||||
<td>{{ value.instanceMemory.max }} MiB</td>
|
||||
<td>{{ value.instanceMemory.avg }} MiB</td>
|
||||
<td>{{ value.instanceMemory.min }}</td>
|
||||
<td>{{ value.instanceMemory.max }}</td>
|
||||
<td>{{ value.instanceMemory.avg }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ t('tableHeaders.cpu') }}</td>
|
||||
<td>{{ value.instanceCpu.min }} m</td>
|
||||
<td>{{ value.instanceCpu.max }} m</td>
|
||||
<td>{{ value.instanceCpu.avg }} m</td>
|
||||
<td>{{ value.instanceCpu.min }}</td>
|
||||
<td>{{ value.instanceCpu.max }}</td>
|
||||
<td>{{ value.instanceCpu.avg }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</SimpleBox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="mt-20">
|
||||
{{ t('epinio.applications.detail.tables.label') }}
|
||||
</h3>
|
||||
|
||||
<div>
|
||||
<!-- //TODO: Add Services & Configurations as tabs -->
|
||||
<ResourceTable :schema="appInstanceSchema" :rows="value.instances" :table-actions="false">
|
||||
<template #header-left>
|
||||
<h1>Instances</h1>
|
||||
</template>
|
||||
</ResourceTable>
|
||||
<Tabbed>
|
||||
<Tab label-key="epinio.applications.detail.tables.instances" name="instances" :weight="3">
|
||||
<ResourceTable :schema="appInstance.schema" :headers="appInstance.headers" :rows="value.instances" :table-actions="false">
|
||||
</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>
|
||||
</template>
|
||||
|
|
@ -292,7 +337,6 @@ export default Vue.extend<Data, any, any, any>({
|
|||
}
|
||||
|
||||
.deployment {
|
||||
margin-bottom: 60px;
|
||||
.simple-box {
|
||||
width: 100%;
|
||||
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() {
|
||||
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 || []];
|
||||
},
|
||||
|
||||
|
|
@ -105,8 +105,9 @@ export default Vue.extend<Data, any, any, any>({
|
|||
|
||||
updateValidation() {
|
||||
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 || {});
|
||||
|
||||
if (!!dataValues.length) {
|
||||
|
|
@ -124,6 +125,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
watch: {
|
||||
'value.meta.namespace'() {
|
||||
Vue.set(this, 'selectedApps', []);
|
||||
this.updateValidation(); // For when a user is supplying their own ns
|
||||
},
|
||||
|
||||
'value.meta.name'() {
|
||||
|
|
@ -142,14 +144,9 @@ export default Vue.extend<Data, any, any, any>({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Loading v-if="!value || !namespaces" />
|
||||
<div v-else-if="!namespaces.length">
|
||||
<Banner color="warning">
|
||||
{{ t('epinio.warnings.noNamespace') }}
|
||||
</Banner>
|
||||
</div>
|
||||
<Loading v-if="!value || $fetchState.pending" />
|
||||
<CruResource
|
||||
v-else-if="value && namespaces.length > 0"
|
||||
v-else-if="value"
|
||||
:min-height="'7em'"
|
||||
:mode="mode"
|
||||
:done-route="doneRoute"
|
||||
|
|
@ -157,10 +154,14 @@ export default Vue.extend<Data, any, any, any>({
|
|||
:can-yaml="false"
|
||||
:errors="errors"
|
||||
:validation-passed="validationPassed"
|
||||
namespace-key="meta.namespace"
|
||||
@error="(e) => (errors = e)"
|
||||
@finish="save"
|
||||
@cancel="done"
|
||||
>
|
||||
<Banner v-if="value.isServiceRelated" color="info">
|
||||
{{ t('epinio.configurations.tableHeaders.service.tooltip') }}
|
||||
</Banner>
|
||||
<NameNsDescription
|
||||
name-key="name"
|
||||
namespace-key="namespace"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import NameNsDescription from '@shell/components/form/NameNsDescription.vue';
|
|||
import EpinioBindAppsMixin from './bind-apps-mixin.js';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export const EPINIO_SERVICE_PARAM = 'service';
|
||||
|
||||
interface Data {
|
||||
}
|
||||
|
||||
|
|
@ -22,7 +24,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
Loading,
|
||||
CruResource,
|
||||
LabeledSelect,
|
||||
NameNsDescription
|
||||
NameNsDescription,
|
||||
},
|
||||
|
||||
mixins: [CreateEditView, EpinioBindAppsMixin],
|
||||
|
|
@ -48,7 +50,8 @@ export default Vue.extend<Data, any, any, any>({
|
|||
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() {
|
||||
|
|
@ -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 nsErrors = validateKubernetesName(this.value?.meta.namespace || '', '', this.$store.getters, undefined, []);
|
||||
|
||||
if (nameErrors.length > 0) {
|
||||
return false;
|
||||
if (nameErrors.length === 0 && nsErrors.length === 0) {
|
||||
return !this.failedWaitingForDeploy;
|
||||
}
|
||||
|
||||
return !this.failedWaitingForDeploy;
|
||||
return false;
|
||||
},
|
||||
|
||||
namespaces() {
|
||||
|
|
@ -125,7 +129,7 @@ export default Vue.extend<Data, any, any, any>({
|
|||
},
|
||||
|
||||
watch: {
|
||||
'value.namespace'() {
|
||||
'value.meta.namespace'() {
|
||||
Vue.set(this, 'selectedApps', []);
|
||||
}
|
||||
}
|
||||
|
|
@ -134,20 +138,16 @@ export default Vue.extend<Data, any, any, any>({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Loading v-if="!value || !namespaces" />
|
||||
<div v-else-if="!namespaces.length">
|
||||
<Banner color="warning">
|
||||
{{ t('epinio.warnings.noNamespace') }}
|
||||
</Banner>
|
||||
</div>
|
||||
<Loading v-if="!value || $fetchState.pending" />
|
||||
<CruResource
|
||||
v-else-if="value && namespaces.length > 0"
|
||||
v-else-if="value"
|
||||
:can-yaml="false"
|
||||
:done-route="doneRoute"
|
||||
:mode="mode"
|
||||
:validation-passed="validationPassed"
|
||||
:resource="value"
|
||||
:errors="errors"
|
||||
namespace-key="meta.namespace"
|
||||
@error="e=>errors = e"
|
||||
@finish="save"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ typeLabel:
|
|||
one { Applications }
|
||||
other { Applications }
|
||||
}
|
||||
appcharts: |-
|
||||
{count, plural,
|
||||
one { Application Templates }
|
||||
other { Application Templates }
|
||||
}
|
||||
"services": |-
|
||||
{count, plural,
|
||||
one { Instances }
|
||||
|
|
@ -24,8 +29,22 @@ typeLabel:
|
|||
one { 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:
|
||||
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:
|
||||
namespace: Namespace
|
||||
instances:
|
||||
|
|
@ -59,6 +78,11 @@ epinio:
|
|||
instances: Instances
|
||||
memory: Memory
|
||||
cpu: CPU
|
||||
tables:
|
||||
label: Resources
|
||||
instances: Instances
|
||||
services: Services
|
||||
configs: Configurations
|
||||
create:
|
||||
title: Application
|
||||
titleSubText: Epinio
|
||||
|
|
@ -140,8 +164,11 @@ epinio:
|
|||
run:
|
||||
label: Run
|
||||
action:
|
||||
create_namespace:
|
||||
label: Create Namespace
|
||||
description: A Namespace will be created to contain your Application
|
||||
create:
|
||||
label: Create
|
||||
label: Create Application
|
||||
description: The Application will be created ready to deploy source to
|
||||
bind_configurations:
|
||||
label: Bind Configurations
|
||||
|
|
@ -206,6 +233,7 @@ epinio:
|
|||
serviceInstance:
|
||||
tableHeaders:
|
||||
service: Catalog Service
|
||||
serviceVersion: Catalog Service Version
|
||||
create:
|
||||
catalogService:
|
||||
label: Catalog Service
|
||||
|
|
@ -216,5 +244,10 @@ epinio:
|
|||
tableHeaders:
|
||||
shortDesc: Headline
|
||||
desc: Description
|
||||
detail:
|
||||
servicesTitle: "{catalogService} Services"
|
||||
chartVersion: Chart Version
|
||||
appVersion: Version
|
||||
helmChart: Helm Chart
|
||||
warnings:
|
||||
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,
|
||||
mode: _CREATE,
|
||||
touched: false,
|
||||
resource: EPINIO_TYPES.NAMESPACE
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -110,7 +111,7 @@ export default {
|
|||
<div>
|
||||
<Masthead
|
||||
:schema="schema"
|
||||
:resource="'undefined'"
|
||||
:resource="resource"
|
||||
>
|
||||
<template v-slot:createButton>
|
||||
<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 { 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 Vue from 'vue';
|
||||
|
||||
export const APPLICATION_ACTION_TYPE = {
|
||||
CREATE_NS: 'create_namespace',
|
||||
CREATE: 'create',
|
||||
GIT_FETCH: 'gitFetch',
|
||||
UPLOAD: 'upload',
|
||||
|
|
@ -18,6 +19,10 @@ export default class ApplicationActionResource extends Resource {
|
|||
run = true;
|
||||
state = APPLICATION_ACTION_STATE.PENDING;
|
||||
|
||||
// application; // : EpinioApplication;
|
||||
// bindings; // : EpinioAppBindings;
|
||||
// type; // : EPINIO_TYPES / string;
|
||||
|
||||
get name() {
|
||||
return this.t(`epinio.applications.action.${ this.action }.label`);
|
||||
}
|
||||
|
|
@ -61,6 +66,9 @@ export default class ApplicationActionResource extends Resource {
|
|||
|
||||
async innerExecute(params) {
|
||||
switch (this.action) {
|
||||
case APPLICATION_ACTION_TYPE.CREATE_NS:
|
||||
await this.createNamespace(params);
|
||||
break;
|
||||
case APPLICATION_ACTION_TYPE.CREATE:
|
||||
await this.create(params);
|
||||
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() {
|
||||
await this.application.create();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
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 { classify } from '@shell/plugins/dashboard-store/classify';
|
||||
import EpinioMetaResource from './epinio-namespaced-resource';
|
||||
|
|
@ -41,18 +40,6 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
|||
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() {
|
||||
return STATES_MAPPED[this.status] || STATES_MAPPED.unknown;
|
||||
}
|
||||
|
|
@ -152,14 +139,6 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
|||
return res;
|
||||
}
|
||||
|
||||
get nsLocation() {
|
||||
return createEpinioRoute(`c-cluster-resource-id`, {
|
||||
cluster: this.$rootGetters['clusterId'],
|
||||
resource: EPINIO_TYPES.NAMESPACE,
|
||||
id: this.meta.namespace
|
||||
});
|
||||
}
|
||||
|
||||
get links() {
|
||||
return {
|
||||
update: this.getUrl(),
|
||||
|
|
@ -225,10 +204,6 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
|||
return Object.keys(this.configuration?.environment || []).length;
|
||||
}
|
||||
|
||||
get configCount() {
|
||||
return this.configuration?.configurations.length;
|
||||
}
|
||||
|
||||
get routeCount() {
|
||||
return this.configuration?.routes.length;
|
||||
}
|
||||
|
|
@ -257,30 +232,43 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
|||
if (!this.origin) {
|
||||
return undefined;
|
||||
}
|
||||
const appChart = {
|
||||
label: 'App Chart',
|
||||
value: this.configuration.appchart
|
||||
};
|
||||
|
||||
switch (this.origin.Kind) { // APPLICATION_MANIFEST_SOURCE_TYPE
|
||||
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:
|
||||
return {
|
||||
label: 'Git',
|
||||
icon: 'icon-file',
|
||||
details: [{
|
||||
label: 'Url',
|
||||
value: this.origin.git.repository
|
||||
}, {
|
||||
label: 'Revision',
|
||||
icon: 'icon-github',
|
||||
value: this.origin.git.revision
|
||||
}]
|
||||
details: [
|
||||
appChart, {
|
||||
label: 'Url',
|
||||
value: this.origin.git.repository
|
||||
}, {
|
||||
label: 'Revision',
|
||||
icon: 'icon-github',
|
||||
value: this.origin.git.revision
|
||||
}]
|
||||
};
|
||||
case APPLICATION_MANIFEST_SOURCE_TYPE.CONTAINER:
|
||||
return {
|
||||
label: 'Container',
|
||||
icon: 'icon-docker',
|
||||
details: [{
|
||||
label: 'Image',
|
||||
value: this.origin.Container || this.origin.container
|
||||
}]
|
||||
details: [
|
||||
appChart, {
|
||||
label: 'Image',
|
||||
value: this.origin.Container || this.origin.container
|
||||
}]
|
||||
};
|
||||
default:
|
||||
return undefined;
|
||||
|
|
@ -370,6 +358,7 @@ export default class EpinioApplicationModel extends EpinioMetaResource {
|
|||
data: {
|
||||
name: this.meta.name,
|
||||
configuration: {
|
||||
appchart: this.configuration.appchart,
|
||||
instances: this.configuration.instances,
|
||||
configurations: this.configuration.configurations,
|
||||
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 { EPINIO_SERVICE_PARAM } from '../edit/services.vue';
|
||||
|
||||
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() {
|
||||
return {
|
||||
update: this.getUrl(),
|
||||
|
|
@ -14,4 +26,45 @@ export default class EpinioCatalogServiceModel extends EpinioMetaResource {
|
|||
// Add baseUrl in a generic way
|
||||
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() {
|
||||
return !!this.configuration.origin;
|
||||
return !!this.configuration?.origin;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,13 @@ export default class EpinioNamespace extends EpinioMetaResource {
|
|||
const namespaces = await this.$dispatch('findAll', { type: this.type, opt: { force: true } });
|
||||
|
||||
// Find new namespace
|
||||
// return new namespace
|
||||
return namespaces.filter(n => n.name === this.name)?.[0];
|
||||
}
|
||||
|
||||
save() {
|
||||
return this.create();
|
||||
}
|
||||
|
||||
get canClone() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { createEpinioRoute } from '@pkg/utils/custom-routing';
|
||||
import { EPINIO_TYPES } from '~/pkg/epinio/types';
|
||||
import EpinioNamespacedResource from './epinio-namespaced-resource';
|
||||
|
||||
|
|
@ -36,6 +37,14 @@ export default class EpinioServiceModel extends EpinioNamespacedResource {
|
|||
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() {
|
||||
await this.followLink('create', {
|
||||
method: 'post',
|
||||
|
|
|
|||
|
|
@ -38,7 +38,10 @@ export default Vue.extend<Data, any, any, any>({
|
|||
],
|
||||
|
||||
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 });
|
||||
// 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) {
|
||||
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[]) {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@ import Masthead from '@shell/components/ResourceList/Masthead';
|
|||
import LinkDetail from '@shell/components/formatter/LinkDetail';
|
||||
import { EPINIO_TYPES } from '../../../../types';
|
||||
import { createEpinioRoute } from '../../../../utils/custom-routing';
|
||||
import EpinioIntro from '../../../../components/EpinioIntro.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Loading,
|
||||
LinkDetail,
|
||||
ResourceTable,
|
||||
Masthead
|
||||
Masthead,
|
||||
EpinioIntro
|
||||
},
|
||||
|
||||
async fetch() {
|
||||
|
|
@ -47,6 +49,10 @@ export default {
|
|||
rows() {
|
||||
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>
|
||||
<Loading v-if="$fetchState.pending" />
|
||||
<EpinioIntro v-else-if="!hasNamespaces" />
|
||||
<div v-else>
|
||||
<Masthead
|
||||
:schema="schema"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { base64Encode } from '@shell/utils/crypto';
|
|||
import { NAMESPACE_FILTERS } from '@shell/store/prefs';
|
||||
import { createNamespaceFilterKeyWithId } from '@shell/utils/namespace-filter';
|
||||
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 name = resource.meta?.name || resource.name;
|
||||
|
|
@ -178,6 +178,13 @@ export default {
|
|||
collectionMethods: ['get', 'post'],
|
||||
resourceFields: { },
|
||||
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,
|
||||
id: EPINIO_TYPES.NAMESPACE,
|
||||
|
|
@ -264,5 +271,13 @@ export default {
|
|||
commit('singleProductCNSI', 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/*"
|
||||
],
|
||||
"@components/*": [
|
||||
"../../pkg/rancher-components/*"
|
||||
],
|
||||
"@pkg/*": [
|
||||
"./*"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import EpinioApplicationModel from './models/applications';
|
|||
import EpinioCatalogServiceModel from './models/catalogservices';
|
||||
import EpinioConfigurationModel from './models/configurations';
|
||||
import EpinioServiceModel from './models/services';
|
||||
import EpinioAppChartModel from './models/appcharts';
|
||||
|
||||
export const EPINIO_PRODUCT_NAME = 'epinio';
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ export const EPINIO_STANDALONE_CLUSTER_NAME = 'default';
|
|||
export const EPINIO_TYPES = {
|
||||
// From API
|
||||
APP: 'applications',
|
||||
APP_CHARTS: 'appcharts',
|
||||
NAMESPACE: 'namespaces',
|
||||
CONFIGURATION: 'configurations',
|
||||
CATALOG_SERVICE: 'catalogservices',
|
||||
|
|
@ -65,6 +67,7 @@ export interface EpinioApplicationResource {
|
|||
configuration: {
|
||||
instances: number,
|
||||
configurations: string[],
|
||||
appchart?: string,
|
||||
environment: Map<string, string>,
|
||||
routes: string[]
|
||||
},
|
||||
|
|
@ -83,6 +86,15 @@ export interface EpinioApplicationResource {
|
|||
|
||||
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 {
|
||||
name: string,
|
||||
url: string,
|
||||
|
|
@ -116,6 +128,7 @@ export interface EpinioServiceResource {
|
|||
meta: EpinioMeta
|
||||
boundapps: string[],
|
||||
catalog_service: string, // eslint-disable-line camelcase
|
||||
catalog_service_version: string, // eslint-disable-line camelcase
|
||||
status: string,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ export default {
|
|||
},
|
||||
|
||||
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.$parent.$emit('createNamespace', true);
|
||||
Vue.nextTick(() => this.$refs.namespace.focus());
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ export default {
|
|||
<div class="rd-header-right">
|
||||
<HarvesterUpgrade v-if="isVirtualCluster" />
|
||||
<div
|
||||
v-if="currentCluster && !simple && (currentProduct.showNamespaceFilter || currentProduct.showWorkspaceSwitcher)"
|
||||
v-if="(currentCluster || currentProduct.customNamespaceFilter) && !simple && (currentProduct.showNamespaceFilter || currentProduct.showWorkspaceSwitcher)"
|
||||
class="top"
|
||||
>
|
||||
<NamespaceFilter v-if="clusterReady && currentProduct && (currentProduct.showNamespaceFilter || isExplorer)" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue