Skip to content

Commit

Permalink
feat: update Annotations and Labels tabs to use editor view for json …
Browse files Browse the repository at this point in the history
…values

1) Annotations tab DescriptionList->Editor
2) in that view, also attempt to parse out annotations that are json values, and fold them into the tree presented in the editor
3) Labels tab funky custom UI->Editor
4) in *that* view, try to map '10' -> 10
5) in YAML tab, don't show .metadata.annotations, .metadata.labels, and .metadata.managedFields
6) in Editor view, fold to depth 3; previously folded to depth 2 mostly because of messy managedFields
  • Loading branch information
starpit committed Oct 9, 2022
1 parent 2b7ba14 commit 4e4fa91
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ export default class Editor extends React.PureComponent<Props, State> {
editor.setValue(await Editor.extractValue(state.content, props.response, props.repl))

// initial default folding level; see https://github.com/kubernetes-sigs/kui/issues/8008
editor.getAction('editor.foldLevel2').run()
editor.getAction('editor.foldLevel3').run()
})

const onZoom = () => {
Expand Down
39 changes: 39 additions & 0 deletions plugins/plugin-client-common/web/scss/components/Sidecar/Tree.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2022 The Kubernetes Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@import 'mixins';

@include Sidecar {
.pf-c-tree-view {
--pf-global--spacer--md: 0.75rem;

dl,
dd {
margin: 0;
}
}
.pf-c-tree-view__node-toggle {
--pf-c-tree-view__node-toggle--Color: var(--color-base04);
&:hover {
--pf-c-tree-view__node-toggle--Color: var(--color-base05);
}
}
.pf-c-tree-view__node {
margin: 0;
--pf-c-tree-view__node--Color: var(--color-text-01);
--pf-c-tree-view__node--focus--BackgroundColor: var(--color-base02);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
*/

@import 'Base';
@import 'Tree';
@import 'Nested';
@import 'BottomToolbar';
46 changes: 26 additions & 20 deletions plugins/plugin-kubectl/src/lib/view/modes/Annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,38 @@
*/

import { i18n, ModeRegistration } from '@kui-shell/core'

import { KubeResource, hasAnnotations } from '../../model/resource'

const strings = i18n('plugin-kubectl')

/**
* Note: Presenting as a DescriptionList may work, if one of the
* annotation values is not a scalar
*
*/
function content(_, resource: KubeResource) {
const lastApplied = 'kubectl.kubernetes.io/last-applied-configuration'

export function tryParse(value: any) {
if (typeof value === 'object' || typeof value === 'number' || typeof value === 'boolean') {
return value
} else {
try {
return JSON.parse(value)
} catch (err) {
return value
}
}
}

async function content(_, resource: KubeResource) {
// this module is expensive to load, so we defer that expense
const { dump } = await import('js-yaml')

return {
apiVersion: 'kui-shell/v1' as const,
kind: 'DescriptionList' as const,
spec: {
groups: Object.keys(resource.metadata.annotations)
.filter(
term =>
term !== 'kubectl.kubernetes.io/last-applied-configuration' &&
resource.metadata.annotations[term].length > 0
contentType: 'yaml',
content: dump(
JSON.parse(
JSON.stringify(resource.metadata.annotations, (key, value) =>
key === lastApplied ? undefined : tryParse(value)
)
.sort((a, b) => a.length - b.length)
.map(term => ({
term,
description: resource.metadata.annotations[term]
}))
}
)
)
}
}

Expand Down
26 changes: 8 additions & 18 deletions plugins/plugin-kubectl/src/lib/view/modes/Labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,20 @@
* limitations under the License.
*/

import { i18n, ModeRegistration, DescriptionList } from '@kui-shell/core'
import { i18n, ModeRegistration } from '@kui-shell/core'

import { tryParse } from './Annotations'
import { KubeResource, hasLabels } from '../../model/resource'

const strings = i18n('plugin-kubectl')

/**
* Turn the Labels into a DescriptionList
*
*/
function content(_, resource: KubeResource): DescriptionList {
async function content(_, resource: KubeResource) {
// this module is expensive to load, so we defer that expense
const { dump } = await import('js-yaml')

return {
apiVersion: 'kui-shell/v1',
kind: 'DescriptionList',
spec: {
as: 'labels',
groups: Object.keys(resource.metadata.labels)
.filter(term => resource.metadata.labels[term].length > 0)
.sort((a, b) => a.length - b.length)
.map(term => ({
term,
description: resource.metadata.labels[term]
}))
}
contentType: 'yaml',
content: dump(JSON.parse(JSON.stringify(resource.metadata.labels, (key, value) => tryParse(value))))
}
}

Expand Down
25 changes: 20 additions & 5 deletions plugins/plugin-kubectl/src/lib/view/modes/yaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ export const label = 'YAML'
/** We want this to be placed as the last tab */
export const order = 999

async function content(_, resource: WithRawData) {
// this module is expensive to load, so we defer that expense
const { load, dump } = await import('js-yaml')

// why not also not-show labels? k8s4/edit.ts has some tests; we
// will need to update those tests if we want to remove labels from
// the yaml tab
return {
contentType: 'yaml',
content: dump(
JSON.parse(
JSON.stringify(load(resource.kuiRawData), (key, value) =>
key === 'managedFields' || key === 'annotations' /* || key === 'labels' */ ? undefined : value
)
)
)
}
}

/**
* The YAML mode applies to all KubeResources, and simply extracts the
* raw `data` field from the resource; note how we indicate that this
Expand All @@ -38,11 +57,7 @@ const yamlMode: ModeRegistration<WithRawData> = {
mode: {
mode,
label,

content: (_, resource: WithRawData) => ({
content: resource.kuiRawData,
contentType: 'yaml'
}),
content,

// traits:
order
Expand Down
4 changes: 2 additions & 2 deletions plugins/plugin-kubectl/src/test/k8s3/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ describe(`kubectl label handling ${process.env.MOCHA_RUN_TARGET || ''}`, functio
.then(ReplExpect.ok)
.then(SidecarExpect.open)
.then(SidecarExpect.showing('nginx', undefined, undefined, ns))
.then(Util.switchToTab('raw'))
.then(SidecarExpect.yaml({ metadata: { labels: { [key]: value } } }))
.then(Util.switchToTab('labels'))
.then(SidecarExpect.yaml({ [key]: value }))
} catch (err) {
await Common.oops(this, true)(err)
}
Expand Down
2 changes: 1 addition & 1 deletion plugins/plugin-kubectl/src/test/k8s4/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ commands.forEach(command => {
const parseError = modifyWithError.bind(undefined, 'parse error', Keys.End, 'could not find expected')

/** modify pod {name} so as to add a label of key=value */
const modify = (name: string, key = 'foo', value = 'bar', needsUnfold = true) => {
const modify = (name: string, key = 'foo', value = 'bar', needsUnfold = false) => {
it(`should modify the content by adding label ${key}=${value}`, async () => {
try {
const actualText = await Util.getValueFromMonaco(res)
Expand Down

0 comments on commit 4e4fa91

Please sign in to comment.