Skip to content

Commit 55495a6

Browse files
committed
feat(plugins/plugin-openwhisk): add grid widget
Fixes #71
1 parent 2ec1caa commit 55495a6

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

plugins/plugin-openwhisk/src/preload.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,10 @@ export default async (registrar: PreloadRegistrar) => {
2020
if (!isHeadless()) {
2121
const preloader = (await import('./non-headless-preload')).default
2222
await preloader(registrar)
23+
24+
// register meter widgets
25+
Promise.all([import('./views/status-stripe/grid-widget')]).then(widgets =>
26+
widgets.map(_ => registrar.registerMeter(_.default()))
27+
)
2328
}
2429
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright 2019-2020 IBM Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Tab, StatusStripeController, StatusTextWithIcon } from '@kui-shell/core'
18+
import { Activation } from '../../models/resource'
19+
20+
/** number of activations to display in the widget */
21+
const nCells = 10
22+
23+
const enum Colors {
24+
empty = 'var(--color-ui-02)'
25+
}
26+
27+
/**
28+
* Construct the skeleton UI
29+
*
30+
*/
31+
function newWidget() {
32+
const container = document.createElement('div')
33+
container.style.display = 'flex'
34+
container.style.justifyContent = 'space-between'
35+
container.style.width = `calc(${nCells} * (1em + 1px) - 1px)`
36+
37+
for (let idx = 0; idx < nCells; idx++) {
38+
const cell = document.createElement('div')
39+
cell.style.width = '1em'
40+
cell.style.height = '1em'
41+
cell.style.backgroundColor = Colors.empty
42+
container.appendChild(cell)
43+
}
44+
45+
return container
46+
}
47+
48+
export const nLatencyBuckets = 6
49+
const n100 = 2
50+
const n1000 = 2
51+
const n7000 = 2
52+
export const latencyBuckets = [50, 100, 500, 1000, 3500, 3500]
53+
export const latencyBucket = (value: number) => {
54+
const nBuckets = latencyBuckets.length
55+
// return Math.min(nBuckets - 1, value < 100 ? ~~(value / (100/6)) : value < 1000 ? 6 + ~~(value / (1000/5)) : value < 7000 ? 11 + ~~(value / (6000/5)) : nBuckets - 1)
56+
return Math.min(
57+
nBuckets - 1,
58+
value < 100
59+
? ~~(value / (100 / n100))
60+
: value < 1000
61+
? n100 + ~~(value / (900 / n1000))
62+
: value < 7000
63+
? n100 + n1000 + ~~(value / (6000 / n7000))
64+
: nBuckets - 1
65+
)
66+
}
67+
68+
/**
69+
* On default events (new tab, tab switch, command execution), we
70+
* will update the text element.
71+
*
72+
*/
73+
function listener(tab: Tab, controller: StatusStripeController, fragment: StatusTextWithIcon) {
74+
setTimeout(async () => {
75+
try {
76+
// fetch both the current context name, and the list of KubeContext objects */
77+
const activations = (await tab.REPL.rexec<Activation[]>(`wsk activation list --limit ${nCells}`)).content
78+
79+
// render the current context into the UI
80+
activations.forEach((activation, idx) => {
81+
const latency = activation.duration
82+
const cell = fragment.text.children[idx] as HTMLElement
83+
84+
cell.classList.add('clickable')
85+
cell.onclick = () => tab.REPL.pexec(`wsk activation get ${activation.activationId}`)
86+
cell.style.backgroundColor =
87+
activation.statusCode === 0 ? `var(--color-latency-${latencyBucket(latency)})` : `var(--color-error)`
88+
})
89+
90+
// backfill as empty
91+
for (let idx = activations.length; idx < nCells; idx++) {
92+
const cell = fragment.text.children[idx] as HTMLElement
93+
cell.style.backgroundColor = Colors.empty
94+
cell.classList.remove('clickable')
95+
}
96+
97+
// only show normally if we succeed; see https://github.com/IBM/kui/issues/3537
98+
controller.showAs('normal')
99+
} catch (err) {
100+
controller.showAs('hidden')
101+
}
102+
}, 500)
103+
}
104+
105+
/**
106+
* @return our fragment spec: an icon, a text container, and onclick
107+
* handlers
108+
*
109+
*/
110+
export default function() {
111+
const fragment = {
112+
id: 'kui--plugin-openwhisk--grid-widget',
113+
icon: '',
114+
iconIsNarrow: true,
115+
text: newWidget()
116+
}
117+
118+
return {
119+
fragment,
120+
listener
121+
}
122+
}

0 commit comments

Comments
 (0)