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 {
|
||||
ADD = "cluster-add",
|
||||
STOP = "cluster-stop",
|
||||
REFRESH = "cluster-refresh",
|
||||
REMOVE = "cluster-remove",
|
||||
REMOVE_WORKSPACE = "cluster-remove-all-from-workspace",
|
||||
FEATURE_INSTALL = "cluster-feature-install",
|
||||
|
||||
@ -143,20 +143,12 @@ export class ClusterManager {
|
||||
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) {
|
||||
const handlers = {
|
||||
[ClusterIpcMessage.ADD]: clusterManager.addCluster,
|
||||
[ClusterIpcMessage.STOP]: clusterManager.stopCluster,
|
||||
[ClusterIpcMessage.REMOVE]: clusterManager.removeCluster,
|
||||
[ClusterIpcMessage.REMOVE_WORKSPACE]: clusterManager.removeAllByWorkspace,
|
||||
[ClusterIpcMessage.REFRESH]: clusterManager.refreshCluster,
|
||||
[ClusterIpcMessage.FEATURE_INSTALL]: clusterManager.installFeature,
|
||||
[ClusterIpcMessage.FEATURE_UPGRADE]: clusterManager.upgradeFeature,
|
||||
[ClusterIpcMessage.FEATURE_REMOVE]: clusterManager.uninstallFeature,
|
||||
|
||||
@ -160,18 +160,15 @@ export class Cluster implements ClusterModel {
|
||||
}
|
||||
|
||||
async installFeature(name: string, config: any) {
|
||||
await installFeature(name, this, config)
|
||||
await this.refreshStatus()
|
||||
return await installFeature(name, this, config)
|
||||
}
|
||||
|
||||
async upgradeFeature(name: string, config: any) {
|
||||
await upgradeFeature(name, this, config)
|
||||
await this.refreshStatus()
|
||||
return await upgradeFeature(name, this, config)
|
||||
}
|
||||
|
||||
async uninstallFeature(name: string) {
|
||||
await uninstallFeature(name, this)
|
||||
await this.refreshStatus()
|
||||
return await uninstallFeature(name, this)
|
||||
}
|
||||
|
||||
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