Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit f01c002

Browse files
committed
feat(plugins/plugin-client-common): kubectl labels ui should be more easily copy/pasteable
1) our dom structure is not easy to copy/paste; e.g. triple click does not work, and our text has a key | value, which is not standard 2) we should add a click-to-copy feature this pr changes key | value to key=value, and enables triple-click select and adds a click-to-copy
1 parent f6dc8d0 commit f01c002

File tree

2 files changed

+99
-19
lines changed

2 files changed

+99
-19
lines changed

plugins/plugin-client-common/src/components/spi/DescriptionList/impl/PatternFlyLabelList.tsx

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,59 @@
1717
import React from 'react'
1818
import { LabelGroup, Label } from '@patternfly/react-core'
1919

20-
import Props from '../model'
20+
import BaseProps from '../model'
21+
22+
import Tooltip from '../../Tooltip'
2123

2224
import '../../../../../web/scss/components/DescriptionList/PatternFlyLabelList.scss'
2325

24-
export default function PatternFlyDescriptionList(props: Omit<Props, 'as'>) {
25-
return (
26-
<div
27-
className={[props.className, 'kui--description-list', 'kui--label-list', 'flex-fill', 'padding-content'].join(
28-
' '
29-
)}
30-
>
31-
<LabelGroup className="kui--description-list-group" numLabels={10}>
32-
{props.groups.map((group, idx) => (
33-
<Label key={idx} className="kui--description-list-term" data-term={group.term}>
34-
<span className="kui--description-list-label-key">{group.term}</span>
35-
<strong className="slightly-deemphasize small-left-pad small-right-pad">|</strong>
36-
<span className="map-value">{group.description}</span>
37-
</Label>
38-
))}
39-
</LabelGroup>
40-
</div>
41-
)
26+
type Props = Omit<BaseProps, 'as'>
27+
type State = {
28+
className: string
29+
}
30+
31+
export default class PatternFlyDescriptionList extends React.PureComponent<Props, State> {
32+
public constructor(props: Props) {
33+
super(props)
34+
this.state = {
35+
className: [
36+
this.props.className,
37+
'kui--description-list',
38+
'kui--label-list',
39+
'flex-fill',
40+
'padding-content'
41+
].join(' ')
42+
}
43+
}
44+
45+
private readonly _onClick = (evt: React.MouseEvent<HTMLSpanElement>) => {
46+
const key = evt.currentTarget.getAttribute('data-term')
47+
const value = evt.currentTarget.getAttribute('data-description')
48+
navigator.clipboard.writeText(`${key}=${value}`)
49+
}
50+
51+
public render() {
52+
return (
53+
<div className={this.state.className}>
54+
<LabelGroup className="kui--description-list-group" numLabels={10}>
55+
{this.props.groups.map((group, idx) => (
56+
<Tooltip key={idx} content="Click to copy" position="bottom">
57+
<Label
58+
className="kui--description-list-term"
59+
data-term={group.term}
60+
data-description={group.description}
61+
onClick={this._onClick}
62+
>
63+
<div>
64+
<span className="kui--description-list-label-key">{group.term}</span>
65+
<span className="slightly-deemphasize">=</span>
66+
<span className="map-value">{group.description}</span>
67+
</div>
68+
</Label>
69+
</Tooltip>
70+
))}
71+
</LabelGroup>
72+
</div>
73+
)
74+
}
4275
}

plugins/plugin-client-common/web/scss/components/DescriptionList/PatternFlyLabelList.scss

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,57 @@
2727

2828
@include DescriptionListTerm {
2929
background-color: var(--color-base02);
30+
31+
&:hover {
32+
cursor: pointer;
33+
background-color: var(--color-base03);
34+
}
3035
}
3136
}
3237

3338
@include LabelKey {
3439
font-weight: 500;
3540
color: var(--color-base0D);
3641
}
42+
43+
/** click effect, adapted from https://codepen.io/ash_s_west/pen/GRZbvym @starpit 20220903 */
44+
@include DescriptionListTerm {
45+
& {
46+
position: relative;
47+
cursor: pointer;
48+
user-select: none;
49+
text-align: center;
50+
text-decoration: none;
51+
cursor: pointer;
52+
transition-duration: 0.4s;
53+
-webkit-transition-duration: 0.4s; /* Safari */
54+
}
55+
56+
&:after {
57+
content: '';
58+
display: block;
59+
position: absolute;
60+
border-radius: 2em;
61+
left: 0;
62+
top: 0;
63+
width: 100%;
64+
height: 100%;
65+
opacity: 0;
66+
transition: all 0.5s;
67+
box-shadow: 0 0 1em 0.5em var(--color-text-01);
68+
}
69+
70+
&:active:after {
71+
box-shadow: 0 0 0 0 var(--color-text-01);
72+
position: absolute;
73+
border-radius: 2em;
74+
left: 0;
75+
top: 0;
76+
opacity: 1;
77+
transition: 0s;
78+
}
79+
80+
&:active {
81+
top: 1px;
82+
}
83+
}

0 commit comments

Comments
 (0)