Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(xo-web): scoped tags #7270

Merged
merged 5 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

> Users must be able to say: “Nice enhancement, I'm eager to test it”

- [Tags] Implement scoped tags (PR [#7270](https://github.com/vatesfr/xen-orchestra/pull/7270))

### Bug fixes

> Users must be able to say: “I had this issue, happy to know it's fixed”
Expand All @@ -27,4 +29,6 @@

<!--packages-start-->

- xo-web minor

<!--packages-end-->
1 change: 1 addition & 0 deletions packages/xo-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"readable-stream": "^3.0.2",
"redux": "^4.0.0",
"redux-thunk": "^2.0.1",
"relative-luminance": "^2.0.1",
"reselect": "^2.5.4",
"rimraf": "^5.0.1",
"sass": "^1.38.1",
Expand Down
142 changes: 103 additions & 39 deletions packages/xo-web/src/common/tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import map from 'lodash/map'
import pFinally from 'promise-toolbox/finally'
import PropTypes from 'prop-types'
import React from 'react'
import relativeLuminance from 'relative-luminance'

import ActionButton from './action-button'
import Component from './base-component'
Expand All @@ -16,26 +17,12 @@ import { SelectTag } from './select-objects'
const INPUT_STYLE = {
maxWidth: '8em',
}
const TAG_STYLE = {
backgroundColor: '#2598d9',
borderRadius: '0.5em',
color: 'white',
fontSize: '0.6em',
margin: '0.2em',
marginTop: '-0.1em',
padding: '0.3em',
verticalAlign: 'middle',
}
const LINK_STYLE = {
cursor: 'pointer',
}
const ADD_TAG_STYLE = {
cursor: 'pointer',
display: 'inline-block',
fontSize: '0.8em',
marginLeft: '0.2em',
}
const REMOVE_TAG_STYLE = {
cursor: 'pointer',
verticalAlign: 'middle',
}

class SelectExistingTag extends Component {
Expand Down Expand Up @@ -128,19 +115,26 @@ export default class Tags extends Component {
const deleteTag = (onDelete || onChange) && this._deleteTag

return (
<span className='form-group' style={{ color: '#999' }}>
<Icon icon='tags' />{' '}
<span>
<div style={{ color: '#999', display: 'inline-block' }}>
<div style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Icon icon='tags' />
</div>
<div style={{ display: 'inline-block', fontSize: '0.6em', verticalAlign: 'middle' }}>
{map(labels.sort(), (label, index) => (
<Tag label={label} onDelete={deleteTag} key={index} onClick={onClick} />
))}
</span>
</div>
{(onAdd || onChange) && !this.state.editing ? (
<span onClick={this._startEdit} style={ADD_TAG_STYLE}>
<div onClick={this._startEdit} style={ADD_TAG_STYLE}>
<Icon icon='add-tag' />
</span>
</div>
) : (
<span className='form-inline' onBlur={this._closeEditionIfUnfocused} onFocus={this._focus}>
<div
style={{ display: 'inline-block', verticalAlign: 'middle' }}
className='form-inline'
onBlur={this._closeEditionIfUnfocused}
onFocus={this._focus}
>
<span className='input-group'>
<input autoFocus className='form-control' onKeyDown={this._onKeyDown} style={INPUT_STYLE} type='text' />
<span className='input-group-btn'>
Expand All @@ -149,27 +143,97 @@ export default class Tags extends Component {
</Tooltip>
</span>
</span>
</span>
</div>
)}
</span>
</div>
)
}
}

export const Tag = ({ type, label, onDelete, onClick }) => (
<span style={TAG_STYLE}>
<span onClick={onClick && (() => onClick(label))} style={onClick && LINK_STYLE}>
{label}
</span>{' '}
{onDelete ? (
<span onClick={onDelete && (() => onDelete(label))} style={REMOVE_TAG_STYLE}>
<Icon icon='remove-tag' />
</span>
) : (
[]
)}
</span>
)
export const Tag = ({
type,
label,
onDelete,
onClick,

// must be in format #rrggbb for luminance parsing
color = '#2598d9',
}) => {
const borderSize = '0.2em'
const padding = '0.2em'

const isLight =
relativeLuminance(
Array.from({ length: 3 }, (_, i) => {
const j = i * 2 + 1
return parseInt(color.slice(j, j + 2), 16)
})
) > 0.5

const i = label.indexOf('=')
const isScoped = i !== -1

return (
<div
style={{
background: color,
border: borderSize + ' solid ' + color,
borderRadius: '0.5em',
color: isLight ? '#000' : '#fff',
display: 'inline-block',
margin: '0.2em',

// prevent value background from breaking border radius
overflow: 'clip',
}}
>
<div
onClick={onClick && (() => onClick(label))}
style={{
cursor: onClick && 'pointer',
display: 'inline-block',
}}
>
<div
style={{
display: 'inline-block',
padding,
}}
>
{isScoped ? label.slice(0, i) : label}
</div>
{isScoped && (
<div
style={{
background: '#fff',
color: '#000',
display: 'inline-block',
padding,
}}
>
{label.slice(i + 1) || <i>N/A</i>}
</div>
)}
</div>
{onDelete && (
<div
onClick={onDelete && (() => onDelete(label))}
style={{
cursor: 'pointer',
display: 'inline-block',
padding,

// if isScoped, the display is a bit different
background: isScoped && '#fff',
color: isScoped && (isLight ? '#000' : color),
}}
>
<Icon icon='remove-tag' />
</div>
)}
</div>
)
}
Tag.propTypes = {
label: PropTypes.string.isRequired,
}
4 changes: 2 additions & 2 deletions packages/xo-web/src/xo-app/home/host-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,9 @@ export default class HostItem extends Component {
{host.productBrand} {host.version}
</Col>
<Col mediumSize={3} className={styles.itemExpanded}>
<span style={{ fontSize: '1.4em' }}>
<div style={{ fontSize: '1.4em' }}>
<HomeTags type='host' labels={host.tags} onDelete={this._removeTag} onAdd={this._addTag} />
</span>
</div>
</Col>
<Col mediumSize={6} className={styles.itemExpanded}>
<MiniStats fetch={this._fetchStats} />
Expand Down
4 changes: 2 additions & 2 deletions packages/xo-web/src/xo-app/home/pool-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,9 @@ export default class PoolItem extends Component {
{master.productBrand} {master.version}
</Col>
<Col mediumSize={5}>
<span style={{ fontSize: '1.4em' }}>
<div style={{ fontSize: '1.4em' }}>
<HomeTags type='pool' labels={pool.tags} onDelete={this._removeTag} onAdd={this._addTag} />
</span>
</div>
</Col>
<Col mediumSize={3} className={styles.itemExpanded}>
<span>
Expand Down
4 changes: 2 additions & 2 deletions packages/xo-web/src/xo-app/home/sr-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ export default class SrItem extends Component {
{sr.VDIs.length}x <Icon icon='disk' />
</Col>
<Col mediumSize={4}>
<span style={{ fontSize: '1.4em' }}>
<div style={{ fontSize: '1.4em' }}>
<HomeTags type='SR' labels={sr.tags} onDelete={this._removeTag} onAdd={this._addTag} />
</span>
</div>
</Col>
</SingleLineRow>
)}
Expand Down
4 changes: 2 additions & 2 deletions packages/xo-web/src/xo-app/home/template-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ export default class TemplateItem extends Component {
))}
</Col>
<Col mediumSize={4}>
<span style={{ fontSize: '1.4em' }}>
<div style={{ fontSize: '1.4em' }}>
<HomeTags type='VM-template' labels={vm.tags} onDelete={this._removeTag} onAdd={this._addTag} />
</span>
</div>
</Col>
</Row>
)}
Expand Down
4 changes: 2 additions & 2 deletions packages/xo-web/src/xo-app/home/vm-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,9 @@ export default class VmItem extends Component {
))}
</Col>
<Col mediumSize={6}>
<span style={{ fontSize: '1.4em' }}>
<div style={{ fontSize: '1.4em' }}>
<HomeTags type='VM' labels={vm.tags} onDelete={this._removeTag} onAdd={this._addTag} />
</span>
</div>
</Col>
<Col mediumSize={6} className={styles.itemExpanded}>
{this._isRunning && <MiniStats fetch={this._fetchStats} />}
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9654,6 +9654,11 @@ eslint@^8.7.0:
strip-ansi "^6.0.1"
text-table "^0.2.0"

esm@^3.0.84:
version "3.2.25"
resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==

espree@^9.0.0, espree@^9.3.1, espree@^9.6.0, espree@^9.6.1:
version "9.6.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
Expand Down Expand Up @@ -18394,6 +18399,13 @@ [email protected], relateurl@^0.2.7:
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==

relative-luminance@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/relative-luminance/-/relative-luminance-2.0.1.tgz#2babddf3a5a59673227d6f02e0f68e13989e3d13"
integrity sha512-wFuITNthJilFPwkK7gNJcULxXBcfFZvZORsvdvxeOdO44wCeZnuQkf3nFFzOR/dpJNxYsdRZJLsepWbyKhnMww==
dependencies:
esm "^3.0.84"

release-zalgo@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730"
Expand Down
Loading