added sorting feature
This commit is contained in:
32
app.py
32
app.py
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import gevent.monkey
|
import gevent.monkey
|
||||||
|
|
||||||
gevent.monkey.patch_all()
|
gevent.monkey.patch_all()
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
@@ -17,7 +18,6 @@ from flask import Flask, redirect
|
|||||||
from flask_oauthlib.client import OAuth, OAuthRemoteApp
|
from flask_oauthlib.client import OAuth, OAuthRemoteApp
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CLUSTERS = 'http://localhost:8001/'
|
DEFAULT_CLUSTERS = 'http://localhost:8001/'
|
||||||
CREDENTIALS_DIR = os.getenv('CREDENTIALS_DIR', '')
|
CREDENTIALS_DIR = os.getenv('CREDENTIALS_DIR', '')
|
||||||
AUTHORIZE_URL = os.getenv('AUTHORIZE_URL')
|
AUTHORIZE_URL = os.getenv('AUTHORIZE_URL')
|
||||||
@@ -119,15 +119,20 @@ def generate_mock_cluster_data(index: int):
|
|||||||
phase = pod_phases[hash_int((index + 1) * (i + 1) * (j + 1)) % len(pod_phases)]
|
phase = pod_phases[hash_int((index + 1) * (i + 1) * (j + 1)) % len(pod_phases)]
|
||||||
containers = []
|
containers = []
|
||||||
for k in range(1):
|
for k in range(1):
|
||||||
containers.append({'name': 'myapp', 'image': 'foo/bar/{}'.format(j), 'resources': {'requests': {'cpu': '100m', 'memory': '100Mi'}}})
|
containers.append({'name': 'myapp', 'image': 'foo/bar/{}'.format(j),
|
||||||
|
'resources': {'requests': {'cpu': '100m', 'memory': '100Mi'}}})
|
||||||
status = {'phase': phase}
|
status = {'phase': phase}
|
||||||
if phase == 'Running':
|
if phase == 'Running':
|
||||||
if j % 13 == 0:
|
if j % 13 == 0:
|
||||||
status['containerStatuses'] = [{'ready': False, 'state': {'waiting': {'reason': 'CrashLoopBackOff'}}}]
|
status['containerStatuses'] = [
|
||||||
|
{'ready': False, 'state': {'waiting': {'reason': 'CrashLoopBackOff'}}}]
|
||||||
elif j % 7 == 0:
|
elif j % 7 == 0:
|
||||||
status['containerStatuses'] = [{'ready': True, 'state': {'running': {}}, 'restartCount': 3}]
|
status['containerStatuses'] = [{'ready': True, 'state': {'running': {}}, 'restartCount': 3}]
|
||||||
pods.append({'name': 'my-pod-{}'.format(j), 'namespace': 'kube-system' if j < 3 else 'default', 'labels': labels, 'status': status, 'containers': containers})
|
pods.append(
|
||||||
nodes.append({'name': 'node-{}'.format(i), 'labels': labels, 'status': {'capacity': {'cpu': '4', 'memory': '32Gi', 'pods': '110'}}, 'pods': pods})
|
{'name': 'my-pod-{}'.format(j), 'namespace': 'kube-system' if j < 3 else 'default', 'labels': labels,
|
||||||
|
'status': status, 'containers': containers})
|
||||||
|
nodes.append({'name': 'node-{}'.format(i), 'labels': labels,
|
||||||
|
'status': {'capacity': {'cpu': '4', 'memory': '32Gi', 'pods': '110'}}, 'pods': pods})
|
||||||
unassigned_pods = []
|
unassigned_pods = []
|
||||||
return {
|
return {
|
||||||
'api_server_url': 'https://kube-{}.example.org'.format(index),
|
'api_server_url': 'https://kube-{}.example.org'.format(index),
|
||||||
@@ -156,7 +161,8 @@ def get_kubernetes_clusters():
|
|||||||
pods_by_namespace_name = {}
|
pods_by_namespace_name = {}
|
||||||
unassigned_pods = []
|
unassigned_pods = []
|
||||||
for node in response.json()['items']:
|
for node in response.json()['items']:
|
||||||
obj = {'name': node['metadata']['name'], 'labels': node['metadata']['labels'], 'status': node['status'], 'pods': []}
|
obj = {'name': node['metadata']['name'], 'labels': node['metadata']['labels'], 'status': node['status'],
|
||||||
|
'pods': []}
|
||||||
nodes.append(obj)
|
nodes.append(obj)
|
||||||
nodes_by_name[obj['name']] = obj
|
nodes_by_name[obj['name']] = obj
|
||||||
response = session.get(urljoin(api_server_url, '/api/v1/pods'), timeout=5)
|
response = session.get(urljoin(api_server_url, '/api/v1/pods'), timeout=5)
|
||||||
@@ -164,9 +170,15 @@ def get_kubernetes_clusters():
|
|||||||
for pod in response.json()['items']:
|
for pod in response.json()['items']:
|
||||||
obj = {'name': pod['metadata']['name'],
|
obj = {'name': pod['metadata']['name'],
|
||||||
'namespace': pod['metadata']['namespace'],
|
'namespace': pod['metadata']['namespace'],
|
||||||
'labels': pod['metadata'].get('labels', {}), 'status': pod['status'], 'containers': []}
|
'labels': pod['metadata'].get('labels', {}),
|
||||||
|
'status': pod['status'],
|
||||||
|
'startTime': pod['status']['startTime'] if 'startTime' in pod['status'] else '',
|
||||||
|
'containers': []
|
||||||
|
}
|
||||||
if 'deletionTimestamp' in pod['metadata']:
|
if 'deletionTimestamp' in pod['metadata']:
|
||||||
obj['deleted'] = datetime.datetime.strptime(pod['metadata']['deletionTimestamp'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=datetime.timezone.utc).timestamp()
|
obj['deleted'] = datetime.datetime.strptime(pod['metadata']['deletionTimestamp'],
|
||||||
|
'%Y-%m-%dT%H:%M:%SZ').replace(
|
||||||
|
tzinfo=datetime.timezone.utc).timestamp()
|
||||||
for cont in pod['spec']['containers']:
|
for cont in pod['spec']['containers']:
|
||||||
obj['containers'].append({'name': cont['name'], 'image': cont['image'], 'resources': cont['resources']})
|
obj['containers'].append({'name': cont['name'], 'image': cont['image'], 'resources': cont['resources']})
|
||||||
pods_by_namespace_name[(obj['namespace'], obj['name'])] = obj
|
pods_by_namespace_name[(obj['namespace'], obj['name'])] = obj
|
||||||
@@ -183,7 +195,9 @@ def get_kubernetes_clusters():
|
|||||||
except:
|
except:
|
||||||
logging.exception('Failed to get metrics')
|
logging.exception('Failed to get metrics')
|
||||||
try:
|
try:
|
||||||
response = session.get(urljoin(api_server_url, '/api/v1/namespaces/kube-system/services/heapster/proxy/apis/metrics/v1alpha1/pods'), timeout=5)
|
response = session.get(urljoin(api_server_url,
|
||||||
|
'/api/v1/namespaces/kube-system/services/heapster/proxy/apis/metrics/v1alpha1/pods'),
|
||||||
|
timeout=5)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
for metrics in response.json()['items']:
|
for metrics in response.json()['items']:
|
||||||
pod = pods_by_namespace_name.get((metrics['metadata']['namespace'], metrics['metadata']['name']))
|
pod = pods_by_namespace_name.get((metrics['metadata']['namespace'], metrics['metadata']['name']))
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import Tooltip from './tooltip.js'
|
import Tooltip from './tooltip.js'
|
||||||
import Cluster from './cluster.js'
|
import Cluster from './cluster.js'
|
||||||
import {Pod, ALL_PODS} from './pod.js'
|
import {Pod, ALL_PODS, sortByName, sortByMemory, sortByCPU, sortByAge} from './pod.js'
|
||||||
import SelectBox from './selectbox'
|
import SelectBox from './selectbox'
|
||||||
import { PRIMARY_VIOLET } from './colors.js'
|
import { PRIMARY_VIOLET } from './colors.js'
|
||||||
import 'pixi-display'
|
import 'pixi-display'
|
||||||
|
|
||||||
const PIXI = require('pixi.js')
|
const PIXI = require('pixi.js')
|
||||||
|
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ export default class App {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.filterString = ''
|
this.filterString = ''
|
||||||
this.seenPods = {}
|
this.seenPods = {}
|
||||||
|
this.sorterFn = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
filter() {
|
filter() {
|
||||||
@@ -54,13 +56,13 @@ export default class App {
|
|||||||
|
|
||||||
const menuBar = new PIXI.Graphics()
|
const menuBar = new PIXI.Graphics()
|
||||||
menuBar.beginFill(PRIMARY_VIOLET, 1)
|
menuBar.beginFill(PRIMARY_VIOLET, 1)
|
||||||
menuBar.drawRect(0, 0, window.innerWidth, 25)
|
menuBar.drawRect(0, 0, window.innerWidth, 35)
|
||||||
menuBar.endFill()
|
menuBar.endFill()
|
||||||
stage.addChild(menuBar)
|
stage.addChild(menuBar)
|
||||||
|
|
||||||
const searchPrompt = new PIXI.Text('>', {fontFamily: 'ShareTechMono', fontSize: 18})
|
const searchPrompt = new PIXI.Text('>', {fontFamily: 'ShareTechMono', fontSize: 18})
|
||||||
searchPrompt.x = 20
|
searchPrompt.x = 20
|
||||||
searchPrompt.y = 5
|
searchPrompt.y = 10
|
||||||
PIXI.ticker.shared.add(function (_) {
|
PIXI.ticker.shared.add(function (_) {
|
||||||
var v = Math.sin((PIXI.ticker.shared.lastTime % 2000) / 2000. * Math.PI)
|
var v = Math.sin((PIXI.ticker.shared.lastTime % 2000) / 2000. * Math.PI)
|
||||||
searchPrompt.alpha = v
|
searchPrompt.alpha = v
|
||||||
@@ -74,22 +76,23 @@ export default class App {
|
|||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
text: 'Name', sorterFn: () => {}
|
text: 'Name', sorterFn: sortByName
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Age', sorterFn: () => {}
|
text: 'Age', sorterFn: sortByAge
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Memory', sorterFn: () => {}
|
text: 'Memory', sorterFn: sortByMemory
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'CPU', sorterFn: () => {}
|
text: 'CPU', sorterFn: sortByCPU
|
||||||
},
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
//setting default sort
|
||||||
|
this.sorterFn = items[0].sorterFn
|
||||||
const selectBox = new SelectBox(items)
|
const selectBox = new SelectBox(items)
|
||||||
selectBox.x = 265
|
selectBox.x = 265
|
||||||
selectBox.y = 5
|
selectBox.y = 3
|
||||||
const mainLayer = new PIXI.DisplayGroup(1, true)
|
const mainLayer = new PIXI.DisplayGroup(1, true)
|
||||||
selectBox.displayGroup = mainLayer
|
selectBox.displayGroup = mainLayer
|
||||||
stage.addChild(selectBox.draw())
|
stage.addChild(selectBox.draw())
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {Pod} from './pod.js'
|
import {Pod} from './pod.js'
|
||||||
import Bars from './bars.js'
|
import Bars from './bars.js'
|
||||||
import {parseResource} from './utils.js'
|
import {parseResource} from './utils.js'
|
||||||
|
import App from './app'
|
||||||
const PIXI = require('pixi.js')
|
const PIXI = require('pixi.js')
|
||||||
|
|
||||||
export default class Node extends PIXI.Graphics {
|
export default class Node extends PIXI.Graphics {
|
||||||
@@ -44,8 +45,8 @@ export default class Node extends PIXI.Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
var nodeBox = this
|
const nodeBox = this
|
||||||
var topHandle = new PIXI.Graphics()
|
const topHandle = new PIXI.Graphics()
|
||||||
topHandle.beginFill(0xaaaaff, 1)
|
topHandle.beginFill(0xaaaaff, 1)
|
||||||
topHandle.drawRect(0, 0, 105, 15)
|
topHandle.drawRect(0, 0, 105, 15)
|
||||||
topHandle.endFill()
|
topHandle.endFill()
|
||||||
@@ -62,8 +63,8 @@ export default class Node extends PIXI.Graphics {
|
|||||||
nodeBox.lineStyle(2, 0xaaaaaa, 1)
|
nodeBox.lineStyle(2, 0xaaaaaa, 1)
|
||||||
topHandle.interactive = true
|
topHandle.interactive = true
|
||||||
topHandle.on('mouseover', function () {
|
topHandle.on('mouseover', function () {
|
||||||
var s = nodeBox.node.name
|
let s = nodeBox.node.name
|
||||||
for (var key of Object.keys(nodeBox.node.labels)) {
|
for (const key of Object.keys(nodeBox.node.labels)) {
|
||||||
s += '\n' + key + ': ' + nodeBox.node.labels[key]
|
s += '\n' + key + ': ' + nodeBox.node.labels[key]
|
||||||
}
|
}
|
||||||
nodeBox.tooltip.setText(s)
|
nodeBox.tooltip.setText(s)
|
||||||
@@ -79,9 +80,16 @@ export default class Node extends PIXI.Graphics {
|
|||||||
bars.y = 1
|
bars.y = 1
|
||||||
nodeBox.addChild(bars.draw())
|
nodeBox.addChild(bars.draw())
|
||||||
|
|
||||||
var px = 24
|
nodeBox.addPods(App.sorterFn)
|
||||||
var py = 20
|
return nodeBox
|
||||||
for (const pod of this.node.pods) {
|
}
|
||||||
|
|
||||||
|
addPods(sorterFn) {
|
||||||
|
const nodeBox = this
|
||||||
|
let px = 24
|
||||||
|
let py = 20
|
||||||
|
const pods = sorterFn !== 'undefined' ? this.node.pods.sort(sorterFn) : this.node.pods
|
||||||
|
for (const pod of pods) {
|
||||||
if (pod.namespace != 'kube-system') {
|
if (pod.namespace != 'kube-system') {
|
||||||
const podBox = Pod.getOrCreate(pod, this.cluster, this.tooltip) //new Pod(pod, this.tooltip)
|
const podBox = Pod.getOrCreate(pod, this.cluster, this.tooltip) //new Pod(pod, this.tooltip)
|
||||||
podBox.x = px
|
podBox.x = px
|
||||||
@@ -93,11 +101,10 @@ export default class Node extends PIXI.Graphics {
|
|||||||
py += 13
|
py += 13
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
px = 24
|
px = 24
|
||||||
py = 100
|
py = 100
|
||||||
for (const pod of this.node.pods) {
|
for (const pod of pods) {
|
||||||
if (pod.namespace == 'kube-system') {
|
if (pod.namespace == 'kube-system') {
|
||||||
const podBox = Pod.getOrCreate(pod, this.cluster, this.tooltip) //new Pod(pod, this.tooltip)
|
const podBox = Pod.getOrCreate(pod, this.cluster, this.tooltip) //new Pod(pod, this.tooltip)
|
||||||
podBox.x = px
|
podBox.x = px
|
||||||
@@ -109,9 +116,6 @@ export default class Node extends PIXI.Graphics {
|
|||||||
py -= 13
|
py -= 13
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return nodeBox
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,36 @@
|
|||||||
const PIXI = require('pixi.js')
|
const PIXI = require('pixi.js')
|
||||||
import {FACTORS, parseResource, getBarColor} from './utils.js'
|
import {FACTORS, getBarColor, podResource} from './utils.js'
|
||||||
|
|
||||||
export const ALL_PODS = {}
|
const ALL_PODS = {}
|
||||||
|
|
||||||
|
const sortByName = (a, b) => {
|
||||||
|
return a.name.localeCompare(b.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortByAge = (a, b) => {
|
||||||
|
const dateA = new Date(a.status.startTime)
|
||||||
|
const dateB = new Date(b.status.startTime)
|
||||||
|
if (dateA.getTime() < dateB.getTime()) {
|
||||||
|
return -1
|
||||||
|
} else if (dateA.getTime() === dateB.getTime())
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortByMemory = (a, b) => {
|
||||||
|
const aMem = podResource('memory')(a.containers, 'usage')
|
||||||
|
const bMem = podResource('memory')(b.containers, 'usage')
|
||||||
|
return bMem - aMem
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortByCPU = (a, b) => {
|
||||||
|
const aCpu = podResource('cpu')(a.containers, 'usage')
|
||||||
|
const bCpu = podResource('cpu')(b.containers, 'usage')
|
||||||
|
return bCpu - aCpu
|
||||||
|
}
|
||||||
|
|
||||||
|
export {ALL_PODS, sortByAge, sortByCPU, sortByMemory, sortByName}
|
||||||
|
|
||||||
export class Pod extends PIXI.Graphics {
|
export class Pod extends PIXI.Graphics {
|
||||||
|
|
||||||
@@ -18,13 +47,6 @@ export class Pod extends PIXI.Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getResourceUsage() {
|
getResourceUsage() {
|
||||||
const metric = (metric, type) =>
|
|
||||||
metric ? (metric[type] ? parseResource(metric[type]) : 0) : 0
|
|
||||||
|
|
||||||
const podResource = type => (containers, resource) =>
|
|
||||||
containers
|
|
||||||
.map(({resources}) => metric(resources[resource], type))
|
|
||||||
.reduce((a, b) => a + b, 0)
|
|
||||||
|
|
||||||
const podCpu = podResource('cpu')
|
const podCpu = podResource('cpu')
|
||||||
const podMem = podResource('memory')
|
const podMem = podResource('memory')
|
||||||
@@ -82,9 +104,9 @@ export class Pod extends PIXI.Graphics {
|
|||||||
|
|
||||||
// pod.status.containerStatuses might be undefined!
|
// pod.status.containerStatuses might be undefined!
|
||||||
const containerStatuses = this.pod.status.containerStatuses || []
|
const containerStatuses = this.pod.status.containerStatuses || []
|
||||||
var ready = 0
|
let ready = 0
|
||||||
var running = 0
|
let running = 0
|
||||||
var restarts = 0
|
let restarts = 0
|
||||||
for (const containerStatus of containerStatuses) {
|
for (const containerStatus of containerStatuses) {
|
||||||
if (containerStatus.ready) {
|
if (containerStatus.ready) {
|
||||||
ready++
|
ready++
|
||||||
@@ -98,7 +120,7 @@ export class Pod extends PIXI.Graphics {
|
|||||||
const allRunning = running >= containerStatuses.length
|
const allRunning = running >= containerStatuses.length
|
||||||
const resources = this.getResourceUsage()
|
const resources = this.getResourceUsage()
|
||||||
|
|
||||||
var newTick = null
|
let newTick = null
|
||||||
|
|
||||||
const podBox = this
|
const podBox = this
|
||||||
podBox.interactive = true
|
podBox.interactive = true
|
||||||
@@ -108,6 +130,7 @@ export class Pod extends PIXI.Graphics {
|
|||||||
podBox.filters = [filter]
|
podBox.filters = [filter]
|
||||||
let s = this.pod.name
|
let s = this.pod.name
|
||||||
s += '\nStatus : ' + this.pod.status.phase + ' (' + ready + '/' + containerStatuses.length + ' ready)'
|
s += '\nStatus : ' + this.pod.status.phase + ' (' + ready + '/' + containerStatuses.length + ' ready)'
|
||||||
|
s += '\nStart Time: ' + this.pod.status.startTime
|
||||||
s += '\nLabels :'
|
s += '\nLabels :'
|
||||||
for (var key of Object.keys(this.pod.labels)) {
|
for (var key of Object.keys(this.pod.labels)) {
|
||||||
if (key !== 'pod-template-hash') {
|
if (key !== 'pod-template-hash') {
|
||||||
@@ -144,8 +167,8 @@ export class Pod extends PIXI.Graphics {
|
|||||||
this.tooltip.visible = false
|
this.tooltip.visible = false
|
||||||
})
|
})
|
||||||
podBox.lineStyle(2, 0xaaaaaa, 1)
|
podBox.lineStyle(2, 0xaaaaaa, 1)
|
||||||
var i = 0
|
let i = 0
|
||||||
var w = 10 / this.pod.containers.length
|
const w = 10 / this.pod.containers.length
|
||||||
for (const container of this.pod.containers) {
|
for (const container of this.pod.containers) {
|
||||||
podBox.drawRect(i * w, 0, w, 10)
|
podBox.drawRect(i * w, 0, w, 10)
|
||||||
i++
|
i++
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { PRIMARY_VIOLET } from './colors.js'
|
||||||
|
import App from './app'
|
||||||
|
|
||||||
const PIXI = require('pixi.js')
|
const PIXI = require('pixi.js')
|
||||||
|
|
||||||
export default class SelectBox extends PIXI.Graphics {
|
export default class SelectBox extends PIXI.Graphics {
|
||||||
@@ -8,11 +11,11 @@ export default class SelectBox extends PIXI.Graphics {
|
|||||||
this.text = new PIXI.Text(this.items[this.count].text, {
|
this.text = new PIXI.Text(this.items[this.count].text, {
|
||||||
fontFamily: 'ShareTechMono',
|
fontFamily: 'ShareTechMono',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fill: 0xaaaaff,
|
fill: 0x000000,
|
||||||
align: 'center'
|
align: 'center'
|
||||||
})
|
})
|
||||||
this.text.x = 10
|
this.text.x = 10
|
||||||
this.text.y = 10
|
this.text.y = 8
|
||||||
this.addChild(this.text)
|
this.addChild(this.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +27,7 @@ export default class SelectBox extends PIXI.Graphics {
|
|||||||
selectBox.count = 0
|
selectBox.count = 0
|
||||||
}
|
}
|
||||||
selectBox.text.text = selectBox.items[selectBox.count].text
|
selectBox.text.text = selectBox.items[selectBox.count].text
|
||||||
|
App.sorterFn = selectBox.items[selectBox.count].sorterFn
|
||||||
}
|
}
|
||||||
|
|
||||||
onBackPressed() {
|
onBackPressed() {
|
||||||
@@ -34,6 +38,7 @@ export default class SelectBox extends PIXI.Graphics {
|
|||||||
selectBox.count = selectBox.items.length - 1
|
selectBox.count = selectBox.items.length - 1
|
||||||
}
|
}
|
||||||
selectBox.text.text = selectBox.items[selectBox.count].text
|
selectBox.text.text = selectBox.items[selectBox.count].text
|
||||||
|
App.sorterFn = selectBox.items[selectBox.count].sorterFn
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
@@ -44,27 +49,27 @@ export default class SelectBox extends PIXI.Graphics {
|
|||||||
backArrow.interactive = true
|
backArrow.interactive = true
|
||||||
forwardArrow.interactive = true
|
forwardArrow.interactive = true
|
||||||
selectBox.interactive = true
|
selectBox.interactive = true
|
||||||
// set a fill and line style
|
|
||||||
|
|
||||||
// draw a triangle
|
// draw a triangle
|
||||||
backArrow.lineStyle(2, 0x000000, 1)
|
backArrow.lineStyle(2, 0x000000, 1)
|
||||||
backArrow.beginFill(0x1b7c87, 0.5)
|
backArrow.beginFill(PRIMARY_VIOLET, 0.5)
|
||||||
backArrow.moveTo(0, 2)
|
backArrow.moveTo(0, 2)
|
||||||
backArrow.lineTo(-20, 15)
|
backArrow.lineTo(-20, 14)
|
||||||
backArrow.lineTo(0, 28)
|
backArrow.lineTo(0, 26)
|
||||||
backArrow.lineTo(0, 2)
|
backArrow.lineTo(0, 2)
|
||||||
backArrow.endFill()
|
backArrow.endFill()
|
||||||
selectBox.addChild(backArrow)
|
selectBox.addChild(backArrow)
|
||||||
|
|
||||||
selectBox.lineStyle(2, 0x000000, 1)
|
selectBox.lineStyle(2, 0x000000, 1)
|
||||||
selectBox.beginFill(0x1b7c87, 0.5)
|
selectBox.beginFill(PRIMARY_VIOLET, 0.5)
|
||||||
selectBox.drawRoundedRect(4, 0, 100, 30, 10)
|
selectBox.drawRoundedRect(4, 0, 100, 28, 5)
|
||||||
selectBox.endFill()
|
selectBox.endFill()
|
||||||
|
|
||||||
forwardArrow.lineStyle(2, 0x000000, 1)
|
forwardArrow.lineStyle(2, 0x000000, 1)
|
||||||
forwardArrow.beginFill(0x1b7c87, 0.5)
|
forwardArrow.beginFill(PRIMARY_VIOLET, 0.5)
|
||||||
forwardArrow.moveTo(108, 2)
|
forwardArrow.moveTo(108, 2)
|
||||||
forwardArrow.lineTo(128, 15)
|
forwardArrow.lineTo(128, 14)
|
||||||
forwardArrow.lineTo(108, 28)
|
forwardArrow.lineTo(108, 26)
|
||||||
forwardArrow.lineTo(108, 2)
|
forwardArrow.lineTo(108, 2)
|
||||||
forwardArrow.endFill()
|
forwardArrow.endFill()
|
||||||
selectBox.addChild(forwardArrow)
|
selectBox.addChild(forwardArrow)
|
||||||
|
|||||||
@@ -68,4 +68,12 @@ function parseResource(v) {
|
|||||||
return parseInt(match[1]) * factor
|
return parseInt(match[1]) * factor
|
||||||
}
|
}
|
||||||
|
|
||||||
export {FACTORS, hsvToRgb, getBarColor, parseResource}
|
const metric = (metric, type) =>
|
||||||
|
metric ? (metric[type] ? parseResource(metric[type]) : 0) : 0
|
||||||
|
|
||||||
|
const podResource = type => (containers, resource) =>
|
||||||
|
containers
|
||||||
|
.map(({resources}) => metric(resources[resource], type))
|
||||||
|
.reduce((a, b) => a + b, 0)
|
||||||
|
|
||||||
|
export {FACTORS, hsvToRgb, getBarColor, parseResource, metric, podResource}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ module.exports = {
|
|||||||
{test: /\.html$/, exclude: /node_modules/, loader: 'file-loader?name=[path][name].[ext]'},
|
{test: /\.html$/, exclude: /node_modules/, loader: 'file-loader?name=[path][name].[ext]'},
|
||||||
{test: /\.jpe?g$|\.svg$|\.png$/, exclude: /node_modules/, loader: 'file-loader?name=[path][name].[ext]'},
|
{test: /\.jpe?g$|\.svg$|\.png$/, exclude: /node_modules/, loader: 'file-loader?name=[path][name].[ext]'},
|
||||||
{test: /\.json$/, exclude: /node_modules/, loader: 'json'},
|
{test: /\.json$/, exclude: /node_modules/, loader: 'json'},
|
||||||
|
{test: /\.(otf|eot|svg|ttf|woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=8192&mimetype=application/font-woff'},
|
||||||
{test: /\.json$/, include: path.join(__dirname, 'node_modules', 'pixi.js'), loader: 'json'}
|
{test: /\.json$/, include: path.join(__dirname, 'node_modules', 'pixi.js'), loader: 'json'}
|
||||||
],
|
],
|
||||||
postLoaders: [{
|
postLoaders: [{
|
||||||
|
|||||||
Reference in New Issue
Block a user