-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
React: Visualize CreateOrDelete button in table header #10257
Changes from all commits
fc95a3c
700057d
f0187af
8c2d47f
045a674
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
--- | ||
extends: '@elastic/kibana' | ||
rules: | ||
no-unused-vars: off | ||
plugins: | ||
['react'] | ||
extends: | ||
['@elastic/kibana', | ||
'plugin:react/recommended'] | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from 'react'; | ||
|
||
import { CreateButtonLink } from 'ui_framework/components/button/create_button_link'; | ||
import { DeleteButton } from 'ui_framework/components/button/delete_button'; | ||
|
||
export function CreateOrDeleteButton({ showCreate, doDelete }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Next step would probably be to throw this into ui_framework and pass in createHref and objectType, so other types can re-use it. I don't love how there isn't symmetry between the create and delete process. e.g. one is an href one is an action. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we avoid destructuring There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree. I find destructuring much cleaner in most cases. |
||
if (showCreate) { | ||
return <CreateButtonLink | ||
href = "#/visualize/new" | ||
tooltip = "Create new visualization" | ||
/>; | ||
} else { | ||
return <DeleteButton | ||
onClick={() => doDelete() } | ||
tooltip="Delete selected visualizations" | ||
/>; | ||
} | ||
} | ||
|
||
CreateOrDeleteButton.propTypes = { | ||
showCreate: React.PropTypes.bool, | ||
doDelete: React.PropTypes.func | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we change this to |
||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import 'ngreact'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Should we collect all ui framework components in here, or try to keep this file updated with only those that are currently being used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO there would be no benefit in implementing but not exporting some components. We won't be able to consistently apply the "currently being used" criterion for long anyway - it'll probably degrade to a mish-mash after a while. |
||
|
||
import { | ||
CreateButtonLink, | ||
DeleteButton, | ||
CreateIcon, | ||
DeleteIcon | ||
} from 'ui_framework/components'; | ||
|
||
import uiModules from 'ui/modules'; | ||
const app = uiModules.get('app/kibana', ['react']); | ||
app.directive('createButtonLink', function (reactDirective) { | ||
return reactDirective(CreateButtonLink); | ||
}); | ||
app.directive('deleteButton', function (reactDirective) { | ||
return reactDirective(DeleteButton); | ||
}); | ||
app.directive('createIcon', function (reactDirective) { | ||
return reactDirective(CreateIcon); | ||
}); | ||
app.directive('deleteIcon', function (reactDirective) { | ||
return reactDirective(DeleteIcon); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React from 'react'; | ||
|
||
import classnames from 'classnames'; | ||
import { KuiButtonLink } from './kui_button_link'; | ||
import { CreateIcon } from '../icon'; | ||
|
||
export function CreateButtonLink(props) { | ||
const { className, ...rest } = props; | ||
const classes = classnames('kuiButton--primary', className); | ||
return <KuiButtonLink className={classes} {...rest}> | ||
<CreateIcon /> | ||
</KuiButtonLink>; | ||
} | ||
|
||
CreateButtonLink.propTypes = { | ||
tooltip: React.PropTypes.string, | ||
className: React.PropTypes.string, | ||
href: React.PropTypes.string | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React from 'react'; | ||
|
||
import { KuiButton } from './kui_button'; | ||
import { DeleteIcon } from '../icon'; | ||
|
||
export function DeleteButton(props) { | ||
return <KuiButton className="kuiButton--danger" {...props}> | ||
<DeleteIcon /> | ||
</KuiButton>; | ||
} | ||
|
||
DeleteButton.propTypes = { | ||
tooltip: React.PropTypes.string, | ||
className: React.PropTypes.string, | ||
onClick: React.PropTypes.func | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from 'react'; | ||
import classnames from 'classnames'; | ||
|
||
import { KuiTooltip } from '../tooltip/kui_tooltip'; | ||
|
||
export function KuiButton({ className, onClick, tooltip, children }) { | ||
const classes = classnames('kuiButton', className); | ||
const button = <button | ||
className={ classes } | ||
aria-label={ tooltip } | ||
onClick={ onClick } | ||
> | ||
{ children } | ||
</button>; | ||
|
||
return tooltip ? <KuiTooltip text={ tooltip }>{ button } </KuiTooltip> : button; | ||
} | ||
|
||
KuiButton.propTypes = { | ||
tooltip: React.PropTypes.string, | ||
className: React.PropTypes.string, | ||
onClick: React.PropTypes.func, | ||
children: React.PropTypes.array | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from 'react'; | ||
import classnames from 'classnames'; | ||
|
||
import { KuiTooltip } from '../tooltip/kui_tooltip'; | ||
|
||
export function KuiButtonLink({ className, href, tooltip, children }) { | ||
const classes = classnames('kuiButton', className); | ||
const buttonLink = <a | ||
className={ classes } | ||
href={ href } | ||
aria-label={ tooltip } | ||
data-tip={ tooltip } | ||
> | ||
{ children } | ||
</a>; | ||
|
||
return tooltip ? <KuiTooltip text={ tooltip }> { buttonLink } </KuiTooltip> : buttonLink; | ||
} | ||
|
||
KuiButtonLink.propTypes = { | ||
tooltip: React.PropTypes.string, | ||
href: React.PropTypes.string, | ||
className: React.PropTypes.string | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import React from 'react'; | ||
import { KuiIcon } from './kui_icon'; | ||
|
||
export const DeleteIcon = () => <KuiIcon className="fa-trash"/>; | ||
export const CreateIcon = () => <KuiIcon className="fa-plus"/>; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import React from 'react'; | ||
|
||
export function KuiIcon({ className }) { | ||
const classNames = ['kuiButton__icon', 'kuiIcon', className]; | ||
return <span aria-hidden="true" className={ classNames.join(' ') }/>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export * from './icon'; | ||
|
||
export { CreateButtonLink } from './button/create_button_link'; | ||
export { DeleteButton } from './button/delete_button'; | ||
|
||
export { KuiTooltip } from './tooltip/kui_tooltip'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from 'react'; | ||
|
||
import ReactTooltip from 'react-tooltip'; | ||
|
||
/** | ||
* Wrap elements inside KuiTooltip to provide a popup tooltip on hover. | ||
* | ||
* TODO: This has the unfortunate side affect of attaching a ReactTooltip to every element, when | ||
* it's not neccessary to do so. Unfortunately, because of our angular -> react migration, it's | ||
* not easy to have a single reference to ReactTooltip that every element can reference. | ||
* | ||
* @param text | ||
* @param children | ||
* @returns {XML} | ||
* @constructor | ||
*/ | ||
export function KuiTooltip({ text, children }) { | ||
return <div> | ||
<div data-tip={ text } data-for={ text }> | ||
{ children } | ||
</div> | ||
<ReactTooltip place="bottom" id={ text }>{ text }</ReactTooltip> | ||
</div>; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kjbekkelund added the react eslint here. Do you suggest the recommended list? or should I add more?
@spalger am I adding these rules the correct way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Good start. It doesn't include "stylistic errors". Unless too busy, maybe @cjcenizal can sync up which other options might be relevant based on the html styleguide? (see https://github.com/yannickcr/eslint-plugin-react#jsx-specific-rules, e.g. https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md)
In general, though, I think we should just start with this and fix that as we go. This is definitely a good start.