mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
clean up reused vue-parts
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
10e68510c4
commit
2a818601f9
@ -4,7 +4,6 @@
|
|||||||
export enum ClusterIpcMessage {
|
export enum ClusterIpcMessage {
|
||||||
ADD = "cluster-add",
|
ADD = "cluster-add",
|
||||||
STOP = "cluster-stop",
|
STOP = "cluster-stop",
|
||||||
REFRESH = "cluster-refresh",
|
|
||||||
REMOVE = "cluster-remove",
|
REMOVE = "cluster-remove",
|
||||||
REMOVE_WORKSPACE = "cluster-remove-all-from-workspace",
|
REMOVE_WORKSPACE = "cluster-remove-all-from-workspace",
|
||||||
FEATURE_INSTALL = "cluster-feature-install",
|
FEATURE_INSTALL = "cluster-feature-install",
|
||||||
|
|||||||
@ -143,20 +143,12 @@ export class ClusterManager {
|
|||||||
return this.getCluster(clusterId)?.uninstallFeature(name);
|
return this.getCluster(clusterId)?.uninstallFeature(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async refreshCluster(clusterId: ClusterId) {
|
|
||||||
const cluster = this.getCluster(clusterId);
|
|
||||||
if (cluster) {
|
|
||||||
await cluster.refreshStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ipcListen(clusterManager: ClusterManager) {
|
static ipcListen(clusterManager: ClusterManager) {
|
||||||
const handlers = {
|
const handlers = {
|
||||||
[ClusterIpcMessage.ADD]: clusterManager.addCluster,
|
[ClusterIpcMessage.ADD]: clusterManager.addCluster,
|
||||||
[ClusterIpcMessage.STOP]: clusterManager.stopCluster,
|
[ClusterIpcMessage.STOP]: clusterManager.stopCluster,
|
||||||
[ClusterIpcMessage.REMOVE]: clusterManager.removeCluster,
|
[ClusterIpcMessage.REMOVE]: clusterManager.removeCluster,
|
||||||
[ClusterIpcMessage.REMOVE_WORKSPACE]: clusterManager.removeAllByWorkspace,
|
[ClusterIpcMessage.REMOVE_WORKSPACE]: clusterManager.removeAllByWorkspace,
|
||||||
[ClusterIpcMessage.REFRESH]: clusterManager.refreshCluster,
|
|
||||||
[ClusterIpcMessage.FEATURE_INSTALL]: clusterManager.installFeature,
|
[ClusterIpcMessage.FEATURE_INSTALL]: clusterManager.installFeature,
|
||||||
[ClusterIpcMessage.FEATURE_UPGRADE]: clusterManager.upgradeFeature,
|
[ClusterIpcMessage.FEATURE_UPGRADE]: clusterManager.upgradeFeature,
|
||||||
[ClusterIpcMessage.FEATURE_REMOVE]: clusterManager.uninstallFeature,
|
[ClusterIpcMessage.FEATURE_REMOVE]: clusterManager.uninstallFeature,
|
||||||
|
|||||||
@ -160,18 +160,15 @@ export class Cluster implements ClusterModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async installFeature(name: string, config: any) {
|
async installFeature(name: string, config: any) {
|
||||||
await installFeature(name, this, config)
|
return await installFeature(name, this, config)
|
||||||
await this.refreshStatus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async upgradeFeature(name: string, config: any) {
|
async upgradeFeature(name: string, config: any) {
|
||||||
await upgradeFeature(name, this, config)
|
return await upgradeFeature(name, this, config)
|
||||||
await this.refreshStatus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async uninstallFeature(name: string) {
|
async uninstallFeature(name: string) {
|
||||||
await uninstallFeature(name, this)
|
return await uninstallFeature(name, this)
|
||||||
await this.refreshStatus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getPrometheusApiPrefix() {
|
getPrometheusApiPrefix() {
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div id="app">
|
|
||||||
<div id="lens-container" />
|
|
||||||
<div class="draggable-top" />
|
|
||||||
<div class="main-view" :class="{ 'menu-visible': isMenuVisible }">
|
|
||||||
<main-menu v-if="isMenuVisible" />
|
|
||||||
<router-view />
|
|
||||||
</div>
|
|
||||||
<bottom-bar v-if="isMenuVisible" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import MainMenu from "@/_vue/components/MainMenu/MainMenu";
|
|
||||||
import BottomBar from "@/_vue/components/BottomBar/BottomBar";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Lens',
|
|
||||||
components: {
|
|
||||||
BottomBar,
|
|
||||||
MainMenu
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
isMenuVisible: function () { return this.$store.getters.isMenuVisible }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.draggable-top {
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
position: absolute;
|
|
||||||
height: 20px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
File diff suppressed because one or more lines are too long
@ -1,73 +0,0 @@
|
|||||||
// from Lens Dashboard
|
|
||||||
$lens-main-bg: #1e2124 !default; // dark bg
|
|
||||||
$lens-pane-bg: #262b2f !default; // all panels main bg
|
|
||||||
$lens-dock-bg: #2E3136 !default; // terminal and top menu bar
|
|
||||||
$lens-menu-bg: #36393E !default; // sidemenu on left
|
|
||||||
$lens-menu-hl: #414448 !default; // sidemenu on left, top left corner
|
|
||||||
$lens-text-color: #87909c !default;
|
|
||||||
$lens-text-color-light: #a0a0a0 !default;
|
|
||||||
$lens-primary: #3d90ce !default;
|
|
||||||
|
|
||||||
// export as css variables
|
|
||||||
:root {
|
|
||||||
--lens-main-bg: #{$lens-main-bg}; // dark bg
|
|
||||||
--lens-pane-bg: #{$lens-pane-bg}; // all panels main bg
|
|
||||||
--lens-dock-bg: #{$lens-dock-bg}; // terminal and top menu bar
|
|
||||||
--lens-menu-bg: #{$lens-menu-bg}; // sidemenu on left
|
|
||||||
--lens-menu-hl: #{$lens-menu-hl}; // sidemenu on left, top left corner
|
|
||||||
--lens-text-color: #{$lens-text-color};
|
|
||||||
--lens-text-color-light: #{$lens-text-color-light};
|
|
||||||
--lens-primary: #{$lens-primary};
|
|
||||||
--lens-bottom-bar-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base grayscale colors definitions
|
|
||||||
$white: #fff !default;
|
|
||||||
$gray-100: #f8f9fa !default;
|
|
||||||
$gray-200: #e9ecef !default;
|
|
||||||
$gray-300: #dee2e6 !default;
|
|
||||||
$gray-400: #ced4da !default;
|
|
||||||
$gray-500: #adb5bd !default;
|
|
||||||
$gray-600: #6c757d !default;
|
|
||||||
$gray-700: #495057 !default;
|
|
||||||
$gray-800: #343a40 !default;
|
|
||||||
$gray-900: #1e2124 !default;
|
|
||||||
$black: #000 !default;
|
|
||||||
|
|
||||||
// Base colors definitions
|
|
||||||
$blue: #3d90ce !default;
|
|
||||||
$indigo: #6610f2 !default;
|
|
||||||
$purple: #6f42c1 !default;
|
|
||||||
$pink: #e83e8c !default;
|
|
||||||
$red: #CE3933 !default;
|
|
||||||
$orange: #fd7e14 !default;
|
|
||||||
$yellow: #ffc107 !default;
|
|
||||||
$green: #4caf50 !default;
|
|
||||||
$teal: #20c997 !default;
|
|
||||||
$cyan: #6ca5b7 !default;
|
|
||||||
|
|
||||||
// Theme color default definitions
|
|
||||||
$primary: $lens-primary !default;
|
|
||||||
$secondary: $gray-600 !default;
|
|
||||||
$success: $green !default;
|
|
||||||
$info: $cyan !default;
|
|
||||||
$warning: $yellow !default;
|
|
||||||
$danger: $red !default;
|
|
||||||
$light: $gray-100 !default;
|
|
||||||
$dark: $gray-800 !default;
|
|
||||||
|
|
||||||
// This table defines the theme colors (variant names)
|
|
||||||
$theme-colors: () !default;
|
|
||||||
$theme-colors: map-merge(
|
|
||||||
(
|
|
||||||
'primary': $primary,
|
|
||||||
'secondary': $secondary,
|
|
||||||
'success': $success,
|
|
||||||
'info': $info,
|
|
||||||
'warning': $warning,
|
|
||||||
'danger': $danger,
|
|
||||||
'light': $light,
|
|
||||||
'dark': $dark
|
|
||||||
),
|
|
||||||
$theme-colors
|
|
||||||
);
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 242 KiB |
@ -1,88 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="bottom-bar">
|
|
||||||
<div id="workspace-area">
|
|
||||||
<i class="material-icons">layers</i> {{ currentWorkspace.name }}
|
|
||||||
</div>
|
|
||||||
<b-popover target="workspace-area" triggers="click" placement="top" :show.sync="show">
|
|
||||||
<template v-slot:title>
|
|
||||||
<a href="#" @click.prevent="goWorkspaces"><i class="material-icons">layers</i> Workspaces</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<ul
|
|
||||||
v-for="workspace in workspaces"
|
|
||||||
:key="workspace.id"
|
|
||||||
:workspace="workspace"
|
|
||||||
class="list-group list-group-flush"
|
|
||||||
>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<a href="#" @click.prevent="switchWorkspace(workspace)">{{ workspace.name }}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</b-popover>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "BottomBar",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
currentWorkspace: function() {
|
|
||||||
return this.$store.getters.currentWorkspace;
|
|
||||||
},
|
|
||||||
workspaces: function() {
|
|
||||||
return this.$store.getters.workspaces;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
switchWorkspace: function(workspace) {
|
|
||||||
this.show = false;
|
|
||||||
this.$store.commit("setCurrentWorkspace", workspace);
|
|
||||||
this.$store.dispatch("clearClusters");
|
|
||||||
this.$store.dispatch("refreshClusters", workspace);
|
|
||||||
this.$router.push({
|
|
||||||
name: "landing-page"
|
|
||||||
})
|
|
||||||
},
|
|
||||||
goWorkspaces: function() {
|
|
||||||
this.$router.push({
|
|
||||||
name: "workspaces-page"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.bottom-bar {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: var(--lens-bottom-bar-height);
|
|
||||||
background-color: var(--lens-primary);
|
|
||||||
z-index: 2000;
|
|
||||||
}
|
|
||||||
#workspace-area {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 2px;
|
|
||||||
right: 10px;
|
|
||||||
display: block;
|
|
||||||
color: #fff;
|
|
||||||
opacity: 0.9;
|
|
||||||
font-size: 11px;
|
|
||||||
cursor: pointer;
|
|
||||||
&.active{
|
|
||||||
opacity: 1.0;
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
position: relative;
|
|
||||||
top: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="loading">
|
|
||||||
<div class="CubeSpinner">
|
|
||||||
<p>{{ text }}</p>
|
|
||||||
<div class="sk-cube-grid">
|
|
||||||
<div class="sk-cube sk-cube1" />
|
|
||||||
<div class="sk-cube sk-cube2" />
|
|
||||||
<div class="sk-cube sk-cube3" />
|
|
||||||
<div class="sk-cube sk-cube4" />
|
|
||||||
<div class="sk-cube sk-cube5" />
|
|
||||||
<div class="sk-cube sk-cube6" />
|
|
||||||
<div class="sk-cube sk-cube7" />
|
|
||||||
<div class="sk-cube sk-cube8" />
|
|
||||||
<div class="sk-cube sk-cube9" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'CubeSpinner',
|
|
||||||
components: {},
|
|
||||||
methods: {},
|
|
||||||
props: {
|
|
||||||
text: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: "Connecting ..."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.loading {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
margin: -44px;
|
|
||||||
margin-top: -70px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* http://tobiasahlin.com/spinkit/ */
|
|
||||||
.CubeSpinner {
|
|
||||||
--size: 70px;
|
|
||||||
.sk-cube-grid {
|
|
||||||
width: 70px;
|
|
||||||
height: 70px;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
margin: 24px auto;
|
|
||||||
border-bottom-left-radius: 3px;
|
|
||||||
border-top-right-radius: 3px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube {
|
|
||||||
width: 33%;
|
|
||||||
height: 33%;
|
|
||||||
float: left;
|
|
||||||
-webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
|
|
||||||
animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube1 {
|
|
||||||
-webkit-animation-delay: 0.2s;
|
|
||||||
animation-delay: 0.2s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube2 {
|
|
||||||
-webkit-animation-delay: 0.3s;
|
|
||||||
animation-delay: 0.3s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube3 {
|
|
||||||
-webkit-animation-delay: 0.4s;
|
|
||||||
animation-delay: 0.4s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube4 {
|
|
||||||
-webkit-animation-delay: 0.1s;
|
|
||||||
animation-delay: 0.1s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube5 {
|
|
||||||
-webkit-animation-delay: 0.2s;
|
|
||||||
animation-delay: 0.2s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube6 {
|
|
||||||
-webkit-animation-delay: 0.3s;
|
|
||||||
animation-delay: 0.3s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube7 {
|
|
||||||
-webkit-animation-delay: 0s;
|
|
||||||
animation-delay: 0s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube8 {
|
|
||||||
-webkit-animation-delay: 0.1s;
|
|
||||||
animation-delay: 0.1s;
|
|
||||||
}
|
|
||||||
.sk-cube-grid .sk-cube9 {
|
|
||||||
-webkit-animation-delay: 0.2s;
|
|
||||||
animation-delay: 0.2s;
|
|
||||||
}
|
|
||||||
@-webkit-keyframes sk-cubeGridScaleDelay {
|
|
||||||
0%, 35% {
|
|
||||||
background-color: #36393e;
|
|
||||||
}
|
|
||||||
0%, 70%, 100% {
|
|
||||||
-webkit-transform: scale3D(1, 1, 1);
|
|
||||||
transform: scale3D(1, 1, 1);
|
|
||||||
}
|
|
||||||
35% {
|
|
||||||
-webkit-transform: scale3D(0, 0, 1);
|
|
||||||
transform: scale3D(0, 0, 1);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-color: #3d90ce;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="content">
|
|
||||||
<div class="landing-page">
|
|
||||||
<b-container fluid class="h-100">
|
|
||||||
<!-- wrapper for center/center align -->
|
|
||||||
<b-row class="h-100">
|
|
||||||
<b-col sm="12" class="my-auto">
|
|
||||||
<div>
|
|
||||||
<b-row align-h="center" class="banner">
|
|
||||||
<b-col sm="8">
|
|
||||||
<h1 v-if="clusters.length === 0" class="display-4 text-center">
|
|
||||||
Welcome!
|
|
||||||
</h1>
|
|
||||||
<p v-if="clusters.length === 0" class="text-center">
|
|
||||||
Get started by associating one or more clusters to Lens.
|
|
||||||
</p>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'LandingPage',
|
|
||||||
components: {},
|
|
||||||
methods: {},
|
|
||||||
computed: {
|
|
||||||
workspaces: function() {
|
|
||||||
return this.$store.getters.workspaces;
|
|
||||||
},
|
|
||||||
clusters: function() {
|
|
||||||
return this.$store.getters.clusters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.landing-page{
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background: #282b2f url(../../components/icon/crane.svg) no-repeat;
|
|
||||||
background-position: 0px 35%;
|
|
||||||
background-size: 85%;
|
|
||||||
background-clip: content-box;
|
|
||||||
.banner {
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
<template>
|
|
||||||
<span>
|
|
||||||
<a
|
|
||||||
id="add-cluster"
|
|
||||||
class="add-cluster menu-item"
|
|
||||||
:class="[{
|
|
||||||
'active':isActive(),
|
|
||||||
}]"
|
|
||||||
@click.prevent="addCluster"
|
|
||||||
v-b-tooltip.hover.right
|
|
||||||
title="Add clusters"
|
|
||||||
>
|
|
||||||
<i class="material-icons">add_box</i>
|
|
||||||
<span v-if="newContexts.length > 0" class="badge badge-success">{{ newContexts.length }}</span>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ClustersMixin from "@/_vue/mixins/ClustersMixin";
|
|
||||||
export default {
|
|
||||||
name: "AddClusterMenuItem",
|
|
||||||
mixins: [ClustersMixin],
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isActive: function( id ){
|
|
||||||
return "new" === this.$route.params.id;
|
|
||||||
},
|
|
||||||
addCluster: async function(){
|
|
||||||
this.$router.push({
|
|
||||||
name: "add-cluster-page",
|
|
||||||
params: {
|
|
||||||
id: "new"
|
|
||||||
},
|
|
||||||
}).catch(err => {})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.$store.dispatch("reloadAvailableKubeContexts");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.add-cluster{
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
color: #fff;
|
|
||||||
padding: 6px 8px 6px 9px;
|
|
||||||
opacity: 0.4;
|
|
||||||
cursor: pointer;
|
|
||||||
&.active{
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
font-size: 50px;
|
|
||||||
}
|
|
||||||
.badge {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10px;
|
|
||||||
right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a
|
|
||||||
class="menu-item"
|
|
||||||
:class="[{
|
|
||||||
'active':isActive,
|
|
||||||
'online':(activated && !isActive),
|
|
||||||
}]"
|
|
||||||
@click.prevent="openClusterPage()"
|
|
||||||
@contextmenu.prevent="openContextMenu()"
|
|
||||||
:title="preferences.clusterName"
|
|
||||||
v-b-tooltip.hover.right
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="icon-frame"
|
|
||||||
:class="[{
|
|
||||||
'active':isActive
|
|
||||||
}]"
|
|
||||||
>
|
|
||||||
<img v-if="preferences.icon" :src="preferences.icon">
|
|
||||||
<hashicon v-else :name="preferences.clusterName" size="38" />
|
|
||||||
<span v-if="isAdmin && eventCount > 0" class="badge badge-danger">{{ eventCount >= 1000 ? "1000+" : eventCount }}</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import hashicon from "../hashicon/hashicon";
|
|
||||||
import { setInterval, clearInterval } from "timers";
|
|
||||||
const { remote } = require('electron')
|
|
||||||
const { Menu, MenuItem } = remote
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "ClusterMenuItem",
|
|
||||||
components: {
|
|
||||||
hashicon
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
eventPoller: null,
|
|
||||||
eventCount: 0,
|
|
||||||
activated: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
cluster: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
preferences: function() {
|
|
||||||
return this.cluster.preferences;
|
|
||||||
},
|
|
||||||
clusterAccessible: function() {
|
|
||||||
return this.$store.getters.clusterById(this.cluster.id).accessible;
|
|
||||||
},
|
|
||||||
isActive: function() {
|
|
||||||
return this.cluster.id === this.$route.params.id;
|
|
||||||
},
|
|
||||||
isAdmin: function() {
|
|
||||||
return this.cluster.isAdmin;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
openClusterPage() {
|
|
||||||
this.activated = true;
|
|
||||||
this.$router.push({
|
|
||||||
name: "cluster-page",
|
|
||||||
params: {
|
|
||||||
id: this.cluster.id
|
|
||||||
},
|
|
||||||
}).catch(err => {})
|
|
||||||
},
|
|
||||||
openContextMenu(){
|
|
||||||
const self = this;
|
|
||||||
const menu = new Menu()
|
|
||||||
menu.append(new MenuItem({ label: 'Settings', click() {
|
|
||||||
self.$router.push({
|
|
||||||
name: "cluster-settings-page",
|
|
||||||
params: {
|
|
||||||
id: self.cluster.id
|
|
||||||
},
|
|
||||||
}).catch(err => {})
|
|
||||||
} }))
|
|
||||||
if (this.activated) {
|
|
||||||
menu.append(new MenuItem({ label: 'Disconnect', click() {
|
|
||||||
self.activated = false;
|
|
||||||
self.stopPolling();
|
|
||||||
self.$store.dispatch("stopCluster", self.cluster.id);
|
|
||||||
if (self.isActive) {
|
|
||||||
self.$router.push({
|
|
||||||
name: "landing-page"
|
|
||||||
}).catch(err => {})
|
|
||||||
}
|
|
||||||
} }))
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.popup({ window: remote.getCurrentWindow() })
|
|
||||||
},
|
|
||||||
toggleEventPolling: function() {
|
|
||||||
if(this.clusterAccessible && !this.eventPoller && this.activated && !this.isActive) {
|
|
||||||
this.fetchEvents()
|
|
||||||
this.eventPoller = setInterval(async () => {
|
|
||||||
await this.fetchEvents()
|
|
||||||
}, 30 * 1000);
|
|
||||||
} else {
|
|
||||||
this.eventCount = 0;
|
|
||||||
this.stopPolling()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fetchEvents: async function() {
|
|
||||||
try {
|
|
||||||
this.eventCount = await this.$promiseIpc.send("getClusterEvents", this.cluster.id);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to get event count for cluster:", error)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stopPolling: function() {
|
|
||||||
if (this.eventPoller) {
|
|
||||||
clearInterval(this.eventPoller)
|
|
||||||
this.eventPoller = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
clusterAccessible: "toggleEventPolling",
|
|
||||||
isActive: "toggleEventPolling"
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
this.stopPolling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.badge {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10px;
|
|
||||||
right: 10px;
|
|
||||||
padding: 4px;
|
|
||||||
i {
|
|
||||||
font-size: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
width: 38px;
|
|
||||||
max-height: 42px;
|
|
||||||
}
|
|
||||||
span.hashicon {
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
div.icon-frame {
|
|
||||||
width: 44px;
|
|
||||||
height: 44px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&.active, &:hover {
|
|
||||||
margin-left: -3px;
|
|
||||||
padding: 0px 0px 0px 3px;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,107 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :style="{ paddingTop: computedPaddingTop }" class="main-menu">
|
|
||||||
<draggable v-model="clusters">
|
|
||||||
<ClusterMenuItem
|
|
||||||
v-for="cluster in clusters" :key="cluster.id"
|
|
||||||
:cluster="cluster"
|
|
||||||
/>
|
|
||||||
</draggable>
|
|
||||||
<AddClusterMenuItem />
|
|
||||||
<b-tooltip v-if="clusters.length === 0" show target="add-cluster" placement="rightbottom">
|
|
||||||
<p class="text-left">
|
|
||||||
This is the quick launch menu.
|
|
||||||
</p>
|
|
||||||
<p class="text-left">
|
|
||||||
Associate clusters and choose the ones you want to access via quick launch menu by clicking the + button.
|
|
||||||
</p>
|
|
||||||
</b-tooltip>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ClusterMenuItem from "@/_vue/components/MainMenu/ClusterMenuItem";
|
|
||||||
import AddClusterMenuItem from "@/_vue/components/MainMenu/AddClusterMenuItem";
|
|
||||||
import draggable from 'vuedraggable'
|
|
||||||
import { isMac } from "../../../../common/vars"
|
|
||||||
|
|
||||||
const {remote} = require('electron')
|
|
||||||
const {Menu, MenuItem} = remote
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "MainMenu",
|
|
||||||
components: {
|
|
||||||
ClusterMenuItem,
|
|
||||||
AddClusterMenuItem,
|
|
||||||
draggable
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
computedPaddingTop: "15px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
clusters: {
|
|
||||||
get: function () {
|
|
||||||
return this.$store.getters.clusters;
|
|
||||||
},
|
|
||||||
set: function (clusters) {
|
|
||||||
this.$store.commit("updateClusters", clusters);
|
|
||||||
// clusterStore.storeClusters(clusters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isActive: function (id) {
|
|
||||||
return id === this.$route.params.id;
|
|
||||||
},
|
|
||||||
addCluster: async function () {
|
|
||||||
this.$router.push({
|
|
||||||
name: "add-cluster-page",
|
|
||||||
params: {
|
|
||||||
id: "new"
|
|
||||||
},
|
|
||||||
}).catch(err => {})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted: function () {
|
|
||||||
if (isMac) {
|
|
||||||
this.computedPaddingTop = "25px";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.main-menu {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 20px;
|
|
||||||
width: 70px;
|
|
||||||
padding-top: 15px;
|
|
||||||
background: #252729;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-item {
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
padding: 6px 15px 6px 15px;
|
|
||||||
color: #87909c;
|
|
||||||
opacity: 0.3;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.online {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,114 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="content">
|
|
||||||
<div class="container-fluid whats-new">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md whats-new-text-wrapper">
|
|
||||||
<div class="logo">
|
|
||||||
<img src="../../components/icon/lens-logo.svg">
|
|
||||||
</div>
|
|
||||||
<!-- Safe to use v-html as we self generate the html locally only -->
|
|
||||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
|
||||||
<div class="whats-new-text" v-html="content">
|
|
||||||
<!-- What's new content -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md whats-new-actions-wrapper">
|
|
||||||
<div class="whats-new-actions">
|
|
||||||
<button type="button" class="btn btn-primary" @click="toLanding">
|
|
||||||
Ok, got it!
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import marked from 'marked'
|
|
||||||
import {readFileSync} from 'fs'
|
|
||||||
import { userStore } from "../../../common/user-store"
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'WhatsNewPage',
|
|
||||||
data() {
|
|
||||||
// todo: check if "fs" can work with custom protocols
|
|
||||||
let fileContents = readFileSync("static://RELEASE_NOTES.md", 'utf8');
|
|
||||||
let content = marked(fileContents);
|
|
||||||
return {
|
|
||||||
error: "",
|
|
||||||
content: content,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {},
|
|
||||||
computed: {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toLanding: async function() {
|
|
||||||
userStore.saveLastSeenAppVersion();
|
|
||||||
this.$router.push({
|
|
||||||
name: "landing-page",
|
|
||||||
}).catch(err => {})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
|
|
||||||
.content {
|
|
||||||
background: #282b2f url(../../components/icon/crane.svg) no-repeat;
|
|
||||||
background-position: 0px 35%;
|
|
||||||
background-size: 85%;
|
|
||||||
background-clip: content-box;
|
|
||||||
}
|
|
||||||
.content > .whats-new{
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color:rgba(0, 0, 0, 0.3);
|
|
||||||
|
|
||||||
.whats-new-text-wrapper{
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
bottom: 77px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
overflow-y: scroll;
|
|
||||||
.logo {
|
|
||||||
padding: 30px 30px;
|
|
||||||
max-width: 1000px;
|
|
||||||
img {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.whats-new-text{
|
|
||||||
padding: 10px 30px;
|
|
||||||
max-width: 1000px;
|
|
||||||
h1{
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
h2{
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.whats-new-actions-wrapper{
|
|
||||||
position: absolute;
|
|
||||||
height: 77px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
border-top: 1px solid #333;
|
|
||||||
background: var(--lens-pane-bg);
|
|
||||||
.whats-new-actions{
|
|
||||||
padding: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="close-page-button">
|
|
||||||
<a @click.prevent="navigateBack" href="#">
|
|
||||||
<i class="material-icons">close</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "ClosePageButton",
|
|
||||||
data() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
navigateBack: () => {
|
|
||||||
window.history.back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
div.close-page-button {
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
right: 25px;
|
|
||||||
z-index: 1100;
|
|
||||||
a {
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
color: #fff;
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
font-size: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
<template>
|
|
||||||
<span class="hashicon" ref="hashicon" />
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import hashicon from 'hashicon'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name:'Hashicon',
|
|
||||||
props:{
|
|
||||||
name: {
|
|
||||||
default: null,
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
default: null,
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
const params = {
|
|
||||||
size: this.size || 48,
|
|
||||||
lightness: { min: 45, max: 65 },
|
|
||||||
saturation: { min: 30, max: 60 }
|
|
||||||
}
|
|
||||||
this.$refs.hashicon.appendChild(hashicon(this.name, params))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
// todo: remove, currently not used in runtime
|
|
||||||
|
|
||||||
import "../../common/system-ca"
|
|
||||||
import "./assets/css/app.scss"
|
|
||||||
import { PromiseIpc } from 'electron-promise-ipc'
|
|
||||||
import Vue from 'vue'
|
|
||||||
import BootstrapVue from 'bootstrap-vue'
|
|
||||||
import App from './App'
|
|
||||||
import router from './router'
|
|
||||||
import store from './store'
|
|
||||||
|
|
||||||
const promiseIpc = new PromiseIpc({maxTimeoutMs: 6000});
|
|
||||||
|
|
||||||
promiseIpc.on('navigate', async (view) => {
|
|
||||||
router.push(view).catch(err => {})
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
|
||||||
Vue.use(BootstrapVue)
|
|
||||||
|
|
||||||
Vue.mixin({
|
|
||||||
created: function () {
|
|
||||||
this.$promiseIpc = promiseIpc;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
setTimeout(async () => {
|
|
||||||
await store.dispatch('init')
|
|
||||||
new Vue({
|
|
||||||
components: {App},
|
|
||||||
store,
|
|
||||||
router,
|
|
||||||
template: '<App/>'
|
|
||||||
}).$mount('#app')
|
|
||||||
})
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
export default {
|
|
||||||
computed: {
|
|
||||||
clusters: function () {
|
|
||||||
return this.$store.getters.clusters
|
|
||||||
},
|
|
||||||
newContexts: function () {
|
|
||||||
const seenContexts = this.seenContexts ? Array.from(this.seenContexts) : this.$store.getters.seenContexts
|
|
||||||
const contextNamesFromKubeconfig = this.availableContexts.map(item => item.currentContext)
|
|
||||||
return contextNamesFromKubeconfig.filter((item) => seenContexts.indexOf(item) < 0)
|
|
||||||
},
|
|
||||||
availableContexts: function () {
|
|
||||||
// read available kubeconfigs from store on filter out configs already found in added clusters
|
|
||||||
return this.$store.getters.availableKubeContexts.filter(item => !this.clusters.find((cluster) => cluster.contextName == item.currentContext));
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Router from 'vue-router'
|
|
||||||
import store from "../store";
|
|
||||||
import { whatsNew } from './routeguard'
|
|
||||||
|
|
||||||
Vue.use(Router);
|
|
||||||
|
|
||||||
const router = new Router({
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'landing-page',
|
|
||||||
component: require('@/_vue/components/LandingPage').default,
|
|
||||||
meta: {
|
|
||||||
routeguard: [
|
|
||||||
// guards in priority order; the first one to catch will trigger something
|
|
||||||
whatsNew,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/preferences',
|
|
||||||
name: 'preferences-page',
|
|
||||||
component: require('@/_vue/components/PreferencesPage').default,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/workspaces',
|
|
||||||
name: 'workspaces-page',
|
|
||||||
component: require('@/_vue/components/WorkspacesPage').default,
|
|
||||||
props: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/add-workspace',
|
|
||||||
name: 'add-workspace-page',
|
|
||||||
component: require('@/_vue/components/AddWorkspacePage').default,
|
|
||||||
props: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/edit-workspace',
|
|
||||||
name: 'edit-workspace-page',
|
|
||||||
component: require('@/_vue/components/EditWorkspacePage').default,
|
|
||||||
props: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/clusters/:id',
|
|
||||||
name: 'cluster-page',
|
|
||||||
component: require('@/_vue/components/ClusterPage').default,
|
|
||||||
props: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/clusters/:id/settings',
|
|
||||||
name: 'cluster-settings-page',
|
|
||||||
component: require('@/_vue/components/ClusterSettings').default,
|
|
||||||
props: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/add-cluster",
|
|
||||||
name: "add-cluster-page",
|
|
||||||
component: require('@/_vue/components/AddClusterPage').default,
|
|
||||||
props: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "/whats-new",
|
|
||||||
name: "whats-new-page",
|
|
||||||
component: require('@/_vue/components/WhatsNewPage').default,
|
|
||||||
props: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '*',
|
|
||||||
redirect: '/'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
|
|
||||||
// guard routes
|
|
||||||
if(to.meta && to.meta.routeguard && to.meta.routeguard.length > 0){
|
|
||||||
|
|
||||||
let guardNext;
|
|
||||||
to.meta.routeguard.forEach(guard => {
|
|
||||||
if(!guardNext) guardNext = guard(to, from, store);
|
|
||||||
});
|
|
||||||
|
|
||||||
if(guardNext) {
|
|
||||||
next(guardNext);
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { userStore } from "../../../../common/user-store"
|
|
||||||
|
|
||||||
export function whatsNew() {
|
|
||||||
if(userStore.hasNewAppVersion){
|
|
||||||
console.log("router: guard: whatsNew: activated");
|
|
||||||
return {
|
|
||||||
path: '/whats-new'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Vuex from 'vuex'
|
|
||||||
import { userStore } from "../../../common/user-store"
|
|
||||||
import { getAppVersion } from "../../../common/utils/app-version"
|
|
||||||
import KubeContexts from './modules/kube-contexts'
|
|
||||||
import Clusters from './modules/clusters'
|
|
||||||
import HelmRepos from './modules/helm-repos'
|
|
||||||
import Workspaces from './modules/workspaces'
|
|
||||||
import { tracker } from "../../../common/tracker"
|
|
||||||
import { PromiseIpc } from 'electron-promise-ipc'
|
|
||||||
|
|
||||||
Vue.use(Vuex);
|
|
||||||
|
|
||||||
const promiseIpc = new PromiseIpc({maxTimeoutMs: 120000});
|
|
||||||
|
|
||||||
export default new Vuex.Store({
|
|
||||||
modules: {
|
|
||||||
Clusters,
|
|
||||||
HelmRepos,
|
|
||||||
KubeContexts,
|
|
||||||
Workspaces
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
preferences: {},
|
|
||||||
hud: {
|
|
||||||
isMenuVisible: true,
|
|
||||||
},
|
|
||||||
seenContexts: userStore.seenContexts,
|
|
||||||
lastSeenAppVersion: userStore.lastSeenAppVersion,
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
storeSeenContexts(state, contexts) {
|
|
||||||
contexts.forEach(ctx => userStore.seenContexts.add(ctx));
|
|
||||||
state.seenContexts = contexts;
|
|
||||||
},
|
|
||||||
updateLastSeenAppVersion(state, appVersion) {
|
|
||||||
state.lastSeenAppVersion = appVersion;
|
|
||||||
userStore.lastSeenAppVersion = appVersion
|
|
||||||
},
|
|
||||||
loadPreferences(state) {
|
|
||||||
this.commit("savePreferences", userStore.preferences);
|
|
||||||
},
|
|
||||||
savePreferences(state, prefs) {
|
|
||||||
state.preferences = prefs;
|
|
||||||
userStore.preferences = prefs;
|
|
||||||
this.dispatch("destroyWebviews")
|
|
||||||
promiseIpc.send("preferencesSaved")
|
|
||||||
},
|
|
||||||
hideMenu(state) {
|
|
||||||
state.hud.isMenuVisible = false;
|
|
||||||
},
|
|
||||||
showMenu(state) {
|
|
||||||
state.hud.isMenuVisible = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
async init({commit, getters}) {
|
|
||||||
commit("loadPreferences");
|
|
||||||
await this.dispatch('refreshClusters', getters.currentWorkspace);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
async addSeenContexts({commit}, data) {
|
|
||||||
commit('storeSeenContexts', data);
|
|
||||||
},
|
|
||||||
async updateLastSeenAppVersion({commit, state}) {
|
|
||||||
tracker.event("app", "whats-new-seen")
|
|
||||||
commit("updateLastSeenAppVersion", getAppVersion())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
seenContexts: state => state.seenContexts,
|
|
||||||
hud: state => state.hud,
|
|
||||||
isMenuVisible: function (state, getters) {
|
|
||||||
if (userStore.hasNewAppVersion) return false;
|
|
||||||
return state.hud.isMenuVisible;
|
|
||||||
},
|
|
||||||
showWhatsNew: function (state) {
|
|
||||||
return userStore.hasNewAppVersion;
|
|
||||||
},
|
|
||||||
preferences: state => state.preferences,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,299 +0,0 @@
|
|||||||
import Vue from "vue"
|
|
||||||
import { ActionTree, GetterTree, MutationTree } from "vuex"
|
|
||||||
import { PromiseIpc } from 'electron-promise-ipc'
|
|
||||||
import { ClusterModel } from "../../../../common/cluster-store"
|
|
||||||
import { Workspace } from "../../../../common/workspace-store"
|
|
||||||
import { tracker } from "../../../../common/tracker";
|
|
||||||
import { FeatureStatusMap } from "../../../../main/feature";
|
|
||||||
import { Kubectl } from "../../../../main/kubectl";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
export interface ClusterInfo extends ClusterModel {
|
|
||||||
url: string;
|
|
||||||
apiUrl: string;
|
|
||||||
online?: boolean;
|
|
||||||
accessible?: boolean;
|
|
||||||
failureReason?: string;
|
|
||||||
nodes?: number;
|
|
||||||
version?: string;
|
|
||||||
distribution?: string;
|
|
||||||
isAdmin?: boolean;
|
|
||||||
features?: FeatureStatusMap;
|
|
||||||
kubeCtl?: Kubectl;
|
|
||||||
contextName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LensWebview {
|
|
||||||
id: string;
|
|
||||||
loaded: boolean;
|
|
||||||
webview?: HTMLIFrameElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClusterState {
|
|
||||||
lenses: LensWebview[];
|
|
||||||
clusters: ClusterInfo[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const promiseIpc = new PromiseIpc({ maxTimeoutMs: 120000 });
|
|
||||||
|
|
||||||
const state: ClusterState = {
|
|
||||||
lenses: [],
|
|
||||||
clusters: []
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions: ActionTree<ClusterState, any> = {
|
|
||||||
async refreshClusters({ commit }, currentWorkspace: Workspace) {
|
|
||||||
const clusters: ClusterInfo[] = await promiseIpc.send('getClusters', currentWorkspace.id).catch((error: Error) => {
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
if (!clusters) return false;
|
|
||||||
commit('updateClusters', clusters);
|
|
||||||
clusters.forEach((cluster: ClusterInfo) => {
|
|
||||||
const lens: LensWebview = {
|
|
||||||
id: cluster.id,
|
|
||||||
webview: null,
|
|
||||||
loaded: false
|
|
||||||
};
|
|
||||||
commit("updateLens", lens)
|
|
||||||
})
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
async getCluster({ commit, getters }, id: string) {
|
|
||||||
const cluster: ClusterInfo = getters.clusters.find((c: ClusterInfo) => c.id === id)
|
|
||||||
if (!cluster) return null;
|
|
||||||
|
|
||||||
const remoteCluster = await promiseIpc.send("getCluster", cluster.id)
|
|
||||||
if (!remoteCluster) return null;
|
|
||||||
|
|
||||||
Object.assign(cluster, remoteCluster)
|
|
||||||
commit('updateCluster', cluster);
|
|
||||||
|
|
||||||
return cluster;
|
|
||||||
},
|
|
||||||
async refineCluster({ commit }, id: string) {
|
|
||||||
console.log("VUEX: ACTION: REFINE CLUSTER", id);
|
|
||||||
|
|
||||||
const remoteCluster = await promiseIpc.send("getCluster", id)
|
|
||||||
if (!remoteCluster) return null;
|
|
||||||
|
|
||||||
commit('updateCluster', remoteCluster);
|
|
||||||
|
|
||||||
return remoteCluster;
|
|
||||||
},
|
|
||||||
async stopCluster({ dispatch, getters }, id: string) {
|
|
||||||
const cluster: ClusterInfo = getters.clusters.find((c: ClusterInfo) => c.id === id)
|
|
||||||
if (!cluster) return;
|
|
||||||
|
|
||||||
const lens = getters.lensById(cluster.id)
|
|
||||||
if (lens) {
|
|
||||||
await dispatch("detachWebview", lens)
|
|
||||||
await promiseIpc.send("stopCluster", cluster.id)
|
|
||||||
tracker.event("cluster", "stop")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async removeCluster({ getters, dispatch }, id: string) {
|
|
||||||
const cluster: ClusterInfo = getters.clusters.find((c: ClusterInfo) => c.id === id)
|
|
||||||
if (!cluster) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const lens = this.getters.lensById(cluster.id)
|
|
||||||
if (lens) {
|
|
||||||
dispatch("detachWebview", lens)
|
|
||||||
}
|
|
||||||
await promiseIpc.send("removeCluster", cluster.id).catch((error: Error) => {
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
tracker.event("cluster", "remove");
|
|
||||||
await dispatch("refreshClusters", getters.currentWorkspace)
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
async addCluster({ commit, getters, dispatch }, data) {
|
|
||||||
const res = await promiseIpc.send("addCluster", data)
|
|
||||||
if (!res) return null;
|
|
||||||
|
|
||||||
tracker.event("cluster", "add");
|
|
||||||
commit('updateClusters', res.allClusters);
|
|
||||||
await dispatch("refreshClusters", getters.currentWorkspace);
|
|
||||||
return res.addedCluster;
|
|
||||||
},
|
|
||||||
async clearClusters({ commit, getters, dispatch }) {
|
|
||||||
// todo: clean from main process as well?
|
|
||||||
getters.lenses.forEach((lens: LensWebview) => {
|
|
||||||
if (lens.webview) {
|
|
||||||
dispatch("detachWebview", lens)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
commit('updateLenses', []);
|
|
||||||
commit('updateClusters', []);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
async uploadClusterIcon({ commit }, data) {
|
|
||||||
const res = await promiseIpc.send("saveClusterIcon", data)
|
|
||||||
tracker.event("cluster", "upload-icon")
|
|
||||||
if (res.cluster) commit("updateCluster", res.cluster)
|
|
||||||
return res
|
|
||||||
},
|
|
||||||
|
|
||||||
async resetClusterIcon({ commit }, data) {
|
|
||||||
const res = await promiseIpc.send("resetClusterIcon", data.clusterId)
|
|
||||||
tracker.event("cluster", "reset-icon")
|
|
||||||
if (res.cluster) commit("updateCluster", res.cluster)
|
|
||||||
return res
|
|
||||||
},
|
|
||||||
|
|
||||||
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
|
||||||
async installClusterFeature({ commit }, data) {
|
|
||||||
// Custom no timeout IPC as install can take very variable time
|
|
||||||
const ipc = new PromiseIpc();
|
|
||||||
const response = await ipc.send('installFeature', data)
|
|
||||||
console.log("installer result:", response);
|
|
||||||
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
|
||||||
|
|
||||||
tracker.event("cluster", "install-feature")
|
|
||||||
commit("updateCluster", cluster)
|
|
||||||
return response
|
|
||||||
},
|
|
||||||
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
|
||||||
async upgradeClusterFeature({ commit }, data) {
|
|
||||||
// Custom no timeout IPC as install can take very variable time
|
|
||||||
const ipc = new PromiseIpc();
|
|
||||||
const response = await ipc.send('upgradeFeature', data)
|
|
||||||
console.log("upgrade result:", response);
|
|
||||||
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
|
||||||
|
|
||||||
tracker.event("cluster", "upgrade-feature")
|
|
||||||
commit("updateCluster", cluster)
|
|
||||||
return response
|
|
||||||
},
|
|
||||||
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
|
||||||
async uninstallClusterFeature({ commit }, data) {
|
|
||||||
// Custom no timeout IPC as uninstall can take very variable time
|
|
||||||
const ipc = new PromiseIpc();
|
|
||||||
const response = await ipc.send('uninstallFeature', data)
|
|
||||||
console.log("uninstaller result:", response);
|
|
||||||
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
|
||||||
|
|
||||||
tracker.event("cluster", "uninstall-feature")
|
|
||||||
commit("updateCluster", cluster)
|
|
||||||
return response
|
|
||||||
},
|
|
||||||
|
|
||||||
attachWebview({ commit }, lens: LensWebview) {
|
|
||||||
const container: any = document.getElementById("lens-container");
|
|
||||||
if (!container || !lens.webview) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container.style = "display: block;"
|
|
||||||
let webview = null
|
|
||||||
container.childNodes.forEach((child: any) => {
|
|
||||||
if (child === lens.webview) {
|
|
||||||
webview = child
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (!webview) {
|
|
||||||
container.appendChild(lens.webview)
|
|
||||||
}
|
|
||||||
container.childNodes.forEach((child: any) => {
|
|
||||||
if (child !== lens.webview) {
|
|
||||||
child.style = "display: none;"
|
|
||||||
} else {
|
|
||||||
child.style = "top: 0; bottom: 20px; position: absolute; width: 100%;"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
promiseIpc.send("enableClusterSettingsMenuItem", lens.id)
|
|
||||||
},
|
|
||||||
detachWebview({ commit }, lens: LensWebview) {
|
|
||||||
const container: any = document.getElementById("lens-container");
|
|
||||||
if (!container) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container.childNodes.forEach((child: any) => {
|
|
||||||
if (child === lens.webview) {
|
|
||||||
container.removeChild(lens.webview)
|
|
||||||
lens.webview = null
|
|
||||||
lens.loaded = false
|
|
||||||
commit("updateLens", lens)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
promiseIpc.send("disableClusterSettingsMenuItem")
|
|
||||||
},
|
|
||||||
hideWebviews({ commit }) {
|
|
||||||
const container: any = document.getElementById("lens-container");
|
|
||||||
if (!container) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container.style = "display: none;"
|
|
||||||
container.childNodes.forEach((child: any) => {
|
|
||||||
child.style = "display: none;"
|
|
||||||
})
|
|
||||||
promiseIpc.send("disableClusterSettingsMenuItem")
|
|
||||||
},
|
|
||||||
destroyWebviews({ commit }) {
|
|
||||||
state.lenses.forEach((lens) => {
|
|
||||||
this.dispatch("detachWebview", lens)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
storeCluster({ commit }, cluster: ClusterInfo) {
|
|
||||||
// clusterStore.saveCluster(cluster);
|
|
||||||
commit("updateCluster", cluster)
|
|
||||||
promiseIpc.send("clusterStored", cluster.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getters: GetterTree<ClusterState, any> = {
|
|
||||||
clusters: state => state.clusters,
|
|
||||||
clusterById: state => (id: string) => {
|
|
||||||
const cluster = state.clusters.find(c => c.id === id);
|
|
||||||
if (cluster) {
|
|
||||||
return cluster;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
lenses: state => state.lenses,
|
|
||||||
lensById: state => (id: string) => {
|
|
||||||
const lens = state.lenses.find(c => c.id === id);
|
|
||||||
if (lens) {
|
|
||||||
return lens;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const mutations: MutationTree<ClusterState> = {
|
|
||||||
updateClusters(state, clusters: ClusterInfo[]) {
|
|
||||||
Vue.set(state, 'clusters', [...clusters])
|
|
||||||
},
|
|
||||||
updateCluster(state, cluster) {
|
|
||||||
state.clusters.forEach((c, index) => {
|
|
||||||
if (c.id === cluster.id) {
|
|
||||||
Vue.set(state.clusters, index, cluster)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateLenses(state, data) {
|
|
||||||
Vue.set(state, 'lenses', [...data])
|
|
||||||
},
|
|
||||||
updateLens(state, lens: LensWebview) {
|
|
||||||
const lensIndex = state.lenses.findIndex(l => l.id == lens.id);
|
|
||||||
if (lensIndex >= 0) {
|
|
||||||
state.lenses[lensIndex] = lens
|
|
||||||
Vue.set(state.lenses, lensIndex, lens)
|
|
||||||
} else {
|
|
||||||
console.log("update new lens")
|
|
||||||
state.lenses.push(lens)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: false,
|
|
||||||
state,
|
|
||||||
getters,
|
|
||||||
mutations,
|
|
||||||
actions
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
import Vue from "vue"
|
|
||||||
import { MutationTree, ActionTree, GetterTree } from "vuex"
|
|
||||||
import { HelmRepo, repoManager } from "../../../../main/helm/helm-repo-manager"
|
|
||||||
|
|
||||||
export interface HelmRepoState {
|
|
||||||
repos: HelmRepo[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const state: HelmRepoState = {
|
|
||||||
repos: []
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions: ActionTree<HelmRepoState, any> = {
|
|
||||||
async addHelmRepo({ commit }, data){
|
|
||||||
const res = await repoManager.addRepo(data).catch((error: Error) => {
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
if(!res) return false;
|
|
||||||
return await this.dispatch("refreshHelmRepos")
|
|
||||||
},
|
|
||||||
async removeHelmRepo({ commit }, data){
|
|
||||||
const res = await repoManager.removeRepo(data).catch((error: Error) => {
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
if(!res) return false;
|
|
||||||
return await this.dispatch("refreshHelmRepos")
|
|
||||||
},
|
|
||||||
async refreshHelmRepos({commit}){
|
|
||||||
const repos: HelmRepo[] = await repoManager.repositories().catch((error: Error) => {
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
if(!repos) return false;
|
|
||||||
commit('updateRepos', repos);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getters: GetterTree<HelmRepoState, any> = {
|
|
||||||
repos: state => state.repos
|
|
||||||
}
|
|
||||||
|
|
||||||
const mutations: MutationTree<HelmRepoState> = {
|
|
||||||
updateRepos(state, repos: HelmRepo[]) {
|
|
||||||
Vue.set(state, 'repos', [...repos])
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: false,
|
|
||||||
state,
|
|
||||||
getters,
|
|
||||||
mutations,
|
|
||||||
actions
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
import * as k8s from "@kubernetes/client-node"
|
|
||||||
import { splitConfig, dumpConfigYaml } from "../../../../main/k8s"
|
|
||||||
|
|
||||||
const state = {
|
|
||||||
availableKubeContexts: []
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
reloadAvailableKubeContexts({commit}, file) {
|
|
||||||
if(!file) return;
|
|
||||||
let kc = new k8s.KubeConfig();
|
|
||||||
try {
|
|
||||||
kc.loadFromFile(file);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to read default kubeconfig: " + error.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the default setup the client makes if it does not find anything in the default config
|
|
||||||
// See: https://github.com/kubernetes-client/javascript/blob/2fc8fbc956ca89bf425ca3ea045d46ee7b75296b/src/config.ts#L253
|
|
||||||
// It defaults to loadFromClusterAndUser() when no config file can be found
|
|
||||||
if(kc.currentContext === "loaded-context") {
|
|
||||||
kc = new k8s.KubeConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
commit("saveAvailableKubeContexts", splitConfig(kc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getters = {
|
|
||||||
availableKubeContexts: function(state){
|
|
||||||
return state.availableKubeContexts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mutations = {
|
|
||||||
saveAvailableKubeContexts(state, contexts) {
|
|
||||||
state.availableKubeContexts = contexts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: false,
|
|
||||||
state,
|
|
||||||
getters,
|
|
||||||
mutations,
|
|
||||||
actions
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
import { ActionTree, GetterTree, MutationTree } from "vuex"
|
|
||||||
import { Workspace, workspaceStore } from "../../../../common/workspace-store"
|
|
||||||
|
|
||||||
export interface WorkspaceState {
|
|
||||||
workspaces: Array<Workspace>;
|
|
||||||
currentWorkspace: Workspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
const state: WorkspaceState = {
|
|
||||||
workspaces: workspaceStore.workspaces,
|
|
||||||
currentWorkspace: workspaceStore.workspaces.find((w) => w.id === "default")
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions: ActionTree<WorkspaceState, any> = {}
|
|
||||||
|
|
||||||
const getters: GetterTree<WorkspaceState, any> = {
|
|
||||||
workspaces: state => state.workspaces,
|
|
||||||
currentWorkspace: state => state.currentWorkspace,
|
|
||||||
workspaceById: state => (id: string) => {
|
|
||||||
return state.workspaces.find((ws) => ws.id == id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mutations: MutationTree<WorkspaceState> = {
|
|
||||||
setCurrentWorkspace(state, workspace: Workspace) {
|
|
||||||
state.currentWorkspace = workspace
|
|
||||||
},
|
|
||||||
addWorkspace(state, workspace: Workspace) {
|
|
||||||
workspaceStore.saveWorkspace({ ...workspace })
|
|
||||||
state.workspaces = workspaceStore.workspaces
|
|
||||||
},
|
|
||||||
updateWorkspace(state, workspace: Workspace) {
|
|
||||||
workspaceStore.saveWorkspace({ ...workspace })
|
|
||||||
state.workspaces = workspaceStore.workspaces
|
|
||||||
},
|
|
||||||
removeWorkspace(state, workspace: Workspace) {
|
|
||||||
workspaceStore.removeWorkspace(workspace.id)
|
|
||||||
state.workspaces = workspaceStore.workspaces
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: false,
|
|
||||||
state,
|
|
||||||
getters,
|
|
||||||
mutations,
|
|
||||||
actions
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user