mirror of https://github.com/rancher/dashboard.git
Initial dashboard view (#7519)
* Dashboard view with quick access and details about resources. --------- Co-authored-by: Richard Cox <richard.cox@suse.com>
This commit is contained in:
parent
072cc00286
commit
93381d9cf3
|
|
@ -12,6 +12,15 @@
|
|||
"webRoot": "${workspaceFolder}",
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
},
|
||||
{
|
||||
"name": "Debug in Brave - MacOS",
|
||||
"request": "launch",
|
||||
"type": "pwa-chrome",
|
||||
"url": "https://localhost:8005",
|
||||
"runtimeExecutable": "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
"cacerts",
|
||||
"chainable",
|
||||
"Codecov",
|
||||
"createapp",
|
||||
"epinio",
|
||||
"hevi",
|
||||
"kube",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"nuxt": "2.15.8",
|
||||
"papaparse": "5.3.0",
|
||||
"portal-vue": "2.1.7",
|
||||
"rancher-icons": "rancher/icons#v2.0.9",
|
||||
"rancher-icons": "rancher/icons#v2.0.12",
|
||||
"require-extension-hooks": "0.3.3",
|
||||
"require-extension-hooks-babel": "1.0.0",
|
||||
"require-extension-hooks-vue": "3.0.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'DashboardCard',
|
||||
props: {
|
||||
isLoaded: { type: Boolean, required: true },
|
||||
title: { type: String, required: true },
|
||||
icon: { type: String, required: true },
|
||||
cta: { type: Object, required: true },
|
||||
link: { type: Object, required: true },
|
||||
linkText: { type: String, required: true },
|
||||
description: { type: String, required: true },
|
||||
slotTitle: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
setLoading() {
|
||||
return !this.isLoaded ? 'loading' : '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="!isLoaded"
|
||||
:class="setLoading"
|
||||
>
|
||||
<i class="icon-spinner animate-spin" />
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="d-main"
|
||||
:class="setLoading"
|
||||
>
|
||||
<div class="d-header">
|
||||
<i
|
||||
class="icon icon-fw"
|
||||
:class="icon"
|
||||
/>
|
||||
<n-link :to="link">
|
||||
<h1>
|
||||
{{ title }}
|
||||
</h1>
|
||||
</n-link>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
{{ description }}
|
||||
</p>
|
||||
|
||||
<n-link
|
||||
class="btn role-secondary"
|
||||
:to="cta"
|
||||
>
|
||||
{{ linkText }}
|
||||
</n-link>
|
||||
|
||||
<hr>
|
||||
|
||||
<div
|
||||
class="d-slot"
|
||||
>
|
||||
<h2 v-if="slotTitle">
|
||||
{{ slotTitle }}
|
||||
</h2>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.d-main, .loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: $space-m;
|
||||
grid-auto-rows: 1fr;
|
||||
gap: $space-m;
|
||||
outline: 1px solid var(--border);
|
||||
border-radius: var(--border-radius);
|
||||
height: 100%;
|
||||
|
||||
// Header's style
|
||||
.d-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
margin-right: 5px ;
|
||||
width: auto;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.d-slot {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
h2 {
|
||||
min-height: 18px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $space-s;
|
||||
|
||||
li, .link {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding-bottom: $space-s;
|
||||
}
|
||||
}
|
||||
|
||||
li > .disabled {
|
||||
color: var(--disabled-text);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
min-height: 325px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
place-content: center;
|
||||
|
||||
// INFO: Disable shimmer effect for now
|
||||
// &::after {
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// right: 0;
|
||||
// bottom: 0;
|
||||
// left: 0;
|
||||
// opacity: 0.1;
|
||||
// transform: translateX(-100%);
|
||||
// background-image: linear-gradient(
|
||||
// 90deg,
|
||||
// rgba(#fff, 0) 0,
|
||||
// rgba(#fff, 0.2) 20%,
|
||||
// rgba(#fff, 0.5) 60%,
|
||||
// rgba(#fff, 0)
|
||||
// );
|
||||
// animation: shimmer 4s infinite;
|
||||
// content: '';
|
||||
// }
|
||||
|
||||
// @keyframes shimmer {
|
||||
// 100% {
|
||||
// transform: translateX(100%);
|
||||
// }
|
||||
// }
|
||||
|
||||
.animate-spin {
|
||||
opacity: 0.5;
|
||||
font-size: 24px;
|
||||
animation: spin 5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -14,6 +14,7 @@ export function init($plugin: any, store: any) {
|
|||
configureType,
|
||||
spoofedType,
|
||||
weightType,
|
||||
virtualType,
|
||||
weightGroup
|
||||
} = $plugin.DSL(store, $plugin.name);
|
||||
|
||||
|
|
@ -24,8 +25,8 @@ export function init($plugin: any, store: any) {
|
|||
logo: require(`../assets/logo-epinio.svg`),
|
||||
productNameKey: 'epinio.label',
|
||||
aboutPage: createEpinioRoute('about', { cluster: EPINIO_STANDALONE_CLUSTER_NAME }),
|
||||
afterLoginRoute: createEpinioRoute('c-cluster-applications', { cluster: EPINIO_STANDALONE_CLUSTER_NAME }),
|
||||
logoRoute: createEpinioRoute('c-cluster-applications', { cluster: EPINIO_STANDALONE_CLUSTER_NAME }),
|
||||
afterLoginRoute: createEpinioRoute('c-cluster-dashboard', { cluster: EPINIO_STANDALONE_CLUSTER_NAME }),
|
||||
logoRoute: createEpinioRoute('c-cluster-dashboard', { cluster: EPINIO_STANDALONE_CLUSTER_NAME }),
|
||||
disableSteveSockets: true,
|
||||
});
|
||||
}
|
||||
|
|
@ -79,6 +80,15 @@ export function init($plugin: any, store: any) {
|
|||
customRoute: createEpinioRoute('c-cluster-applications', { }),
|
||||
});
|
||||
|
||||
virtualType({
|
||||
label: store.getters['i18n/t']('epinio.intro.dashboard'),
|
||||
icon: 'dashboard',
|
||||
group: 'Root',
|
||||
namespaced: false,
|
||||
name: EPINIO_TYPES.DASHBOARD,
|
||||
route: createEpinioRoute('c-cluster-dashboard', { })
|
||||
});
|
||||
|
||||
// App Chart resource
|
||||
configureType(EPINIO_TYPES.APP_CHARTS, {
|
||||
isCreatable: false,
|
||||
|
|
@ -149,11 +159,13 @@ export function init($plugin: any, store: any) {
|
|||
EPINIO_TYPES.APP_CHARTS
|
||||
], ADVANCED_GROUP);
|
||||
|
||||
weightType(EPINIO_TYPES.APP, 300, true);
|
||||
weightType(EPINIO_TYPES.DASHBOARD, 300, true);
|
||||
weightType(EPINIO_TYPES.APP, 250, true);
|
||||
weightGroup(SERVICE_GROUP, 2, true);
|
||||
weightType(EPINIO_TYPES.NAMESPACE, 100, true);
|
||||
weightGroup(ADVANCED_GROUP, 1, true);
|
||||
basicType([
|
||||
EPINIO_TYPES.DASHBOARD,
|
||||
EPINIO_TYPES.APP,
|
||||
SERVICE_GROUP,
|
||||
EPINIO_TYPES.NAMESPACE,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
typeLabel:
|
||||
withCount:
|
||||
namespaces: Namespaces {n}
|
||||
applications: Applications {n}
|
||||
services: Services {n}
|
||||
namespaces: |-
|
||||
{count, plural,
|
||||
one { Namespaces }
|
||||
|
|
@ -42,12 +46,27 @@ epinio:
|
|||
allPackages: See all packages
|
||||
getBinaries: Get binaries
|
||||
intro:
|
||||
dashboard: Dashboard
|
||||
welcome: Welcome to Epinio
|
||||
blurb: The Application Development Engine for Kubernetes
|
||||
description: Epinio takes your application from source code to deployment and allow for Developers and Operators to work better together!
|
||||
learnMoreLink: https://epinio.io/
|
||||
learnMore: Learn more
|
||||
noNamespaces: Create a Namespace, then create your Applications
|
||||
getStarted: Get started
|
||||
issues: Issues
|
||||
cards:
|
||||
namespaces:
|
||||
linkText: Create Namespace
|
||||
slotTitle: Newest Namespaces
|
||||
applications:
|
||||
linkText: Deploy Application
|
||||
running: Running
|
||||
services:
|
||||
title: Services
|
||||
description: Create instances of your services. Instances can be bound to your Applications to provide data.
|
||||
linkText: Create Instance
|
||||
slotTitle: Quick start with
|
||||
tableHeaders:
|
||||
namespace: Namespace
|
||||
instances:
|
||||
|
|
|
|||
|
|
@ -45,7 +45,12 @@ export default {
|
|||
},
|
||||
...mapState('action-menu', ['showPromptRemove']),
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Opens the create namespace modal if the query is passed as query param
|
||||
if (this.$route.query.mode === 'openModal') {
|
||||
this.openCreateModal();
|
||||
}
|
||||
},
|
||||
props: {
|
||||
schema: {
|
||||
type: Object,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,321 @@
|
|||
<script lang="ts">
|
||||
import { getVersionInfo } from '@shell/utils/version';
|
||||
import Vue from 'vue';
|
||||
import DashboardCard from '../../../components/dashboard/Cards.vue';
|
||||
import { createEpinioRoute } from '@/pkg/epinio/utils/custom-routing';
|
||||
import { EpinioApplicationResource, EpinioCatalogService, EPINIO_TYPES } from '@/pkg/epinio/types';
|
||||
import ConsumptionGauge from '@shell/components/ConsumptionGauge.vue';
|
||||
import Namespace from '~/shell/models/namespace';
|
||||
import EpinioServiceModel from '~/pkg/epinio/models/services';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { sortBy } from 'lodash';
|
||||
|
||||
export default Vue.extend<any, any, any, any>({
|
||||
components: { DashboardCard, ConsumptionGauge },
|
||||
async fetch() {
|
||||
await Promise.all([
|
||||
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.CATALOG_SERVICE }),
|
||||
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.NAMESPACE }),
|
||||
this.$store.dispatch(`epinio/findAll`, { type: EPINIO_TYPES.SERVICE_INSTANCE })
|
||||
]);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sectionContent: [
|
||||
{
|
||||
isEnable: true,
|
||||
isLoaded: false,
|
||||
icon: 'icon-namespace',
|
||||
cta: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.NAMESPACE }, { query: { mode: 'openModal' } }),
|
||||
link: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.NAMESPACE }),
|
||||
linkText: this.t('epinio.intro.cards.namespaces.linkText'),
|
||||
description: this.t('typeDescription.namespaces', {}, true),
|
||||
slotTitle: this.t('epinio.intro.cards.namespaces.slotTitle')
|
||||
},
|
||||
{
|
||||
isEnable: true,
|
||||
isLoaded: false,
|
||||
icon: 'icon-application',
|
||||
cta: createEpinioRoute('c-cluster-applications-createapp', { resource: EPINIO_TYPES.APP }),
|
||||
link: createEpinioRoute('c-cluster-applications', { resource: EPINIO_TYPES.APP }),
|
||||
linkText: this.t('epinio.intro.cards.applications.linkText'),
|
||||
description: this.t('typeDescription.applications'),
|
||||
slotTitle: '',
|
||||
},
|
||||
{
|
||||
isEnable: true,
|
||||
isLoaded: false,
|
||||
icon: 'icon-service',
|
||||
cta: createEpinioRoute('c-cluster-resource-create', { resource: EPINIO_TYPES.SERVICE_INSTANCE }),
|
||||
link: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.SERVICE_INSTANCE }),
|
||||
linkText: this.t('epinio.intro.cards.services.linkText'),
|
||||
description: this.t('epinio.intro.cards.services.description'), // INFO: typeDescription to long for the dashboard card.
|
||||
slotTitle: this.t('epinio.intro.cards.services.slotTitle')
|
||||
}],
|
||||
colorStops: {
|
||||
0: '--info', 30: '--info', 70: '--info'
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.redoCards();
|
||||
},
|
||||
watch: {
|
||||
namespaces(old, neu) {
|
||||
if (isEqual(old, neu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.redoCards();
|
||||
},
|
||||
apps(old, neu) {
|
||||
if (isEqual(old, neu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.redoCards();
|
||||
},
|
||||
services(old, neu) {
|
||||
if (isEqual(old, neu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.redoCards();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
redoCards() {
|
||||
// Handles titles
|
||||
this.sectionContent[0].title = this.t('typeLabel.withCount.namespaces', { n: this.namespaces.totalNamespaces });
|
||||
this.sectionContent[1].title = this.t('typeLabel.withCount.applications', { n: this.apps?.totalApps });
|
||||
this.sectionContent[2].title = this.t('typeLabel.withCount.services', { n: this.services?.servicesInstances });
|
||||
|
||||
// Handles descriptions
|
||||
if (this.namespaces?.totalNamespaces ) {
|
||||
this.sectionContent[0].isLoaded = true;
|
||||
}
|
||||
|
||||
if (this.apps?.totalApps || this.apps?.totalApps === 0) {
|
||||
this.sectionContent[1].isLoaded = true;
|
||||
}
|
||||
|
||||
if (this.services?.servicesCatalog.length) {
|
||||
this.sectionContent[2].isLoaded = true;
|
||||
this.sectionContent[2].isEnable = true;
|
||||
} else {
|
||||
this.sectionContent[2].isLoaded = false;
|
||||
this.sectionContent[2].isEnable = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
services() {
|
||||
const fetchServicesInstances: EpinioServiceModel[] = this.$store.getters['epinio/all'](EPINIO_TYPES.SERVICE_INSTANCE);
|
||||
const fetchServices: EpinioCatalogService[] = this.$store.getters['epinio/all'](EPINIO_TYPES.CATALOG_SERVICE);
|
||||
|
||||
// Try to find the desired services
|
||||
const findDesiredServices = fetchServices?.filter(service => service?.shortId === 'mysql-dev' || service?.shortId === 'redis-dev');
|
||||
|
||||
// if not found, return the first two services from the catalog
|
||||
const services: EpinioCatalogService[] | any =
|
||||
findDesiredServices.length ? findDesiredServices : fetchServices.slice(0, 2);
|
||||
|
||||
const s = services.reduce((acc: any[], service: { shortId: string; }) => {
|
||||
acc.push({
|
||||
link: createEpinioRoute('c-cluster-resource-create', { resource: EPINIO_TYPES.SERVICE_INSTANCE, name: service?.shortId }, { query: { service: service?.shortId } }),
|
||||
shortId: service?.shortId,
|
||||
isEnabled: true
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
return {
|
||||
servicesInstances: fetchServicesInstances.length,
|
||||
servicesCatalog: s,
|
||||
};
|
||||
},
|
||||
version() {
|
||||
const { displayVersion } = getVersionInfo(this.$store);
|
||||
|
||||
return displayVersion;
|
||||
},
|
||||
apps() {
|
||||
const allApps = this.$store.getters['epinio/all'](EPINIO_TYPES.APP) as EpinioApplicationResource[];
|
||||
|
||||
return allApps.reduce((acc, item) => {
|
||||
return {
|
||||
runningApps: acc.runningApps + (item.status === 'running' ? 1 : 0),
|
||||
stoppedApps: acc.stoppedApps + (item.status === 'error' ? 1 : 0),
|
||||
totalApps: acc.totalApps + 1,
|
||||
};
|
||||
}, {
|
||||
runningApps: 0, stoppedApps: 0, totalApps: 0
|
||||
});
|
||||
},
|
||||
namespaces() {
|
||||
const allNamespaces: Namespace[] = this.$store.getters['epinio/all'](EPINIO_TYPES.NAMESPACE);
|
||||
|
||||
return { totalNamespaces: allNamespaces.length, latestNamespaces: sortBy(allNamespaces, 'metadata.createdAt').reverse().slice(0, 2) };
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<div class="head">
|
||||
<div class="head-title">
|
||||
<h1>{{ t('epinio.intro.welcome') }}</h1>
|
||||
<span>{{ version }}</span>
|
||||
</div>
|
||||
|
||||
<p class="head-subheader">
|
||||
{{ t('epinio.intro.blurb') }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ t('epinio.intro.description') }}
|
||||
</p>
|
||||
|
||||
<div class="head-links">
|
||||
<a
|
||||
href="https://epinio.io/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
>{{ t('epinio.intro.getStarted') }}</a>
|
||||
<a
|
||||
href="https://github.com/epinio/epinio/issues"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
>{{ t('epinio.intro.issues') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="get-started">
|
||||
<div
|
||||
v-for="(card, index) in sectionContent"
|
||||
:key="index"
|
||||
>
|
||||
<DashboardCard
|
||||
v-if="card.isEnable"
|
||||
:is-loaded="card.isLoaded"
|
||||
:title="card.title"
|
||||
:icon="card.icon"
|
||||
:cta="card.cta"
|
||||
:link="card.link"
|
||||
:link-text="card.linkText"
|
||||
:description="card.description"
|
||||
:slot-title="card.slotTitle"
|
||||
>
|
||||
<span v-if="index === 0">
|
||||
<slot>
|
||||
<ul>
|
||||
<li
|
||||
v-for="(ns, i) in namespaces.latestNamespaces"
|
||||
:key="i"
|
||||
>
|
||||
{{ ns.id }}
|
||||
</li>
|
||||
</ul>
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span v-if="index === 1">
|
||||
<slot>
|
||||
<ConsumptionGauge
|
||||
:resource-name="t('epinio.intro.cards.applications.running')"
|
||||
:capacity="apps.totalApps"
|
||||
:used-as-resource-name="true"
|
||||
:color-stops="colorStops"
|
||||
:used="apps.runningApps"
|
||||
units="Apps"
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span v-if="index === 2">
|
||||
<slot>
|
||||
<ul>
|
||||
<li
|
||||
v-for="(service, i) in services.servicesCatalog"
|
||||
:key="i"
|
||||
>
|
||||
<n-link
|
||||
v-if="service.isEnabled"
|
||||
:to="service.link"
|
||||
class="link"
|
||||
>
|
||||
{{ service.shortId }}
|
||||
<span>+</span>
|
||||
</n-link>
|
||||
|
||||
<span
|
||||
v-if="!service.isEnabled"
|
||||
class="link disabled"
|
||||
>
|
||||
{{ service.shortId }}
|
||||
<span>+</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</slot>
|
||||
</span>
|
||||
</DashboardCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: $space-m;
|
||||
outline: 1px solid var(--border);
|
||||
border-radius: var(--border-radius);
|
||||
margin: 0 0 20px 0;
|
||||
padding: $space-m;
|
||||
gap: $space-m;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
background: var(--primary);
|
||||
color: var(--default);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 4px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&-subheader {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
&-links {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.get-started {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
grid-gap: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -5,6 +5,7 @@ import { EPINIO_PRODUCT_NAME } from '../types';
|
|||
import CreateApp from '../pages/c/_cluster/applications/createapp/index.vue';
|
||||
import ListApp from '../pages/c/_cluster/applications/index.vue';
|
||||
import ListEpinio from '../pages/index.vue';
|
||||
import Dashboard from '../pages/c/_cluster/dashboard.vue';
|
||||
import AboutEpinio from '../pages/about.vue';
|
||||
import ListEpinioResource from '../pages/c/_cluster/_resource/index.vue';
|
||||
import CreateEpinioResource from '../pages/c/_cluster/_resource/create.vue';
|
||||
|
|
@ -12,6 +13,11 @@ import ViewEpinioResource from '../pages/c/_cluster/_resource/_id.vue';
|
|||
import ViewEpinioNsResource from '../pages/c/_cluster/_resource/_namespace/_id.vue';
|
||||
|
||||
const routes: RouteConfig[] = [{
|
||||
name: `${ EPINIO_PRODUCT_NAME }-c-cluster-dashboard`,
|
||||
path: `/:product/c/:cluster/dashboard`,
|
||||
component: Dashboard,
|
||||
},
|
||||
{
|
||||
name: `${ EPINIO_PRODUCT_NAME }-c-cluster-applications-createapp`,
|
||||
path: `/:product/c/:cluster/applications/createapp`,
|
||||
component: CreateApp,
|
||||
|
|
@ -20,8 +26,8 @@ const routes: RouteConfig[] = [{
|
|||
path: `/:product/c/:cluster/applications`,
|
||||
component: ListApp,
|
||||
}, {
|
||||
name: `${ EPINIO_PRODUCT_NAME }`,
|
||||
path: `/:product`,
|
||||
name: `${ EPINIO_PRODUCT_NAME }-applications`,
|
||||
path: `/:product/application`,
|
||||
component: ListEpinio,
|
||||
}, {
|
||||
name: `${ EPINIO_PRODUCT_NAME }-about`,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export const EPINIO_TYPES = {
|
|||
CATALOG_SERVICE: 'catalogservices',
|
||||
SERVICE_INSTANCE: 'services',
|
||||
// Internal
|
||||
DASHBOARD: 'dashboard',
|
||||
INSTANCE: 'instance',
|
||||
APP_ACTION: 'application-action',
|
||||
APP_INSTANCE: 'application-instance',
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ export const rootEpinioRoute = () => ({
|
|||
params: { product: EPINIO_PRODUCT_NAME }
|
||||
});
|
||||
|
||||
export const createEpinioRoute = (name: string, params: Object) => ({
|
||||
export const createEpinioRoute = (name: string, params: Object, query?: Object) => ({
|
||||
name: `${ rootEpinioRoute().name }-${ name }`,
|
||||
params: {
|
||||
...rootEpinioRoute().params,
|
||||
...params
|
||||
}
|
||||
},
|
||||
...query
|
||||
});
|
||||
|
|
|
|||
|
|
@ -106,7 +106,10 @@ export default {
|
|||
{{ resourceName }}
|
||||
</h4>
|
||||
<span v-else>{{ t('node.detail.glance.consumptionGauge.used') }}</span>
|
||||
<span>{{ t('node.detail.glance.consumptionGauge.amount', amountTemplateValues) }} <span class="ml-10 percentage">/ {{ formattedPercentage }}</span></span>
|
||||
<span class="numbers-stats">
|
||||
{{ t('node.detail.glance.consumptionGauge.amount', amountTemplateValues) }}
|
||||
<span class="percentage"><i>/ </i>{{ formattedPercentage }}</span>
|
||||
</span>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="mt-10">
|
||||
|
|
@ -125,8 +128,20 @@ export default {
|
|||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
&-stats {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
align-self: baseline;
|
||||
|
||||
}
|
||||
|
||||
.percentage {
|
||||
font-weight: bold;
|
||||
i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14515,9 +14515,9 @@ queue-microtask@^1.2.2:
|
|||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
rancher-icons@rancher/icons#v2.0.9:
|
||||
version "2.0.9"
|
||||
resolved "https://codeload.github.com/rancher/icons/tar.gz/09048239918c9eccf49f7770948efef63fb04f24"
|
||||
rancher-icons@rancher/icons#v2.0.12:
|
||||
version "2.0.12"
|
||||
resolved "https://codeload.github.com/rancher/icons/tar.gz/fa899fecced43835926ad6607b10a9f0c9c163da"
|
||||
|
||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
|
||||
version "2.1.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue