-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Migrate Parameters component to React #4006
Changes from 38 commits
0408f28
3cdc232
15419f6
61541d4
d9dbef5
2fe9a16
1d51a66
0ede83a
cf49952
f2ab142
33db3bc
cdac798
5f81f3f
3fb3e3f
01bca17
2c73726
9f0d1ab
7499226
0b928c0
00d633d
95f1a42
9598d95
dab94d5
dfa60b6
2082493
0c0bf6e
649aaf5
ed848ab
aab7058
9e679b9
6cfb271
5baf71e
69fe667
efc987f
8b7eec1
cad5ff0
542f650
f2be99b
58b1b72
aa097e3
5d22e49
2a28a18
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 |
---|---|---|
|
@@ -5,9 +5,15 @@ | |
.parameter-input { | ||
display: inline-block; | ||
position: relative; | ||
width: 100%; | ||
|
||
.@{ant-prefix}-input[type="text"] { | ||
width: 195px; | ||
.@{ant-prefix}-input, | ||
.@{ant-prefix}-input-number { | ||
min-width: 100% !important; | ||
} | ||
|
||
.@{ant-prefix}-select { | ||
ranbena marked this conversation as resolved.
Show resolved
Hide resolved
|
||
width: 100%; | ||
gabrieldutra marked this conversation as resolved.
Show resolved
Hide resolved
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. 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. Select doesn't have minWidth 60px? 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. Yes, previously we were replacing that with the |
||
} | ||
|
||
&[data-dirty] { | ||
|
@@ -18,65 +24,3 @@ | |
} | ||
} | ||
} | ||
|
||
.parameter-container { | ||
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. Moved to |
||
position: relative; | ||
|
||
.parameter-apply-button { | ||
display: none; // default for mobile | ||
|
||
// "floating" on desktop | ||
@media (min-width: 768px) { | ||
position: absolute; | ||
bottom: -42px; | ||
left: -15px; | ||
border-radius: 2px; | ||
z-index: 1; | ||
transition: opacity 150ms ease-out; | ||
box-shadow: 0 4px 9px -3px rgba(102, 136, 153, 0.15); | ||
background-color: #ffffff; | ||
padding: 4px; | ||
padding-left: 16px; | ||
opacity: 0; | ||
display: block; | ||
pointer-events: none; // so tooltip doesn't remain after button hides | ||
} | ||
|
||
&[data-show="true"] { | ||
opacity: 1; | ||
display: block; | ||
pointer-events: auto; | ||
} | ||
|
||
button { | ||
padding: 0 8px 0 6px; | ||
color: #2096f3; | ||
border-color: #50acf6; | ||
|
||
// smaller on desktop | ||
@media (min-width: 768px) { | ||
font-size: 12px; | ||
height: 27px; | ||
} | ||
|
||
&:hover, &:focus, &:active { | ||
background-color: #eef7fe; | ||
} | ||
|
||
i { | ||
margin-right: 3px; | ||
} | ||
} | ||
|
||
.ant-badge-count { | ||
min-width: 15px; | ||
height: 15px; | ||
padding: 0 5px; | ||
font-size: 10px; | ||
line-height: 15px; | ||
background: #f77b74; | ||
border-radius: 7px; | ||
box-shadow: 0px 0px 0 1px white, -1px 1px 0 1px #5d6f7d85; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { size, filter, forEach, extend } from 'lodash'; | ||
import { react2angular } from 'react2angular'; | ||
import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc'; | ||
import { $location } from '@/services/ng'; | ||
import { Parameter } from '@/services/query'; | ||
import ParameterApplyButton from '@/components/ParameterApplyButton'; | ||
import ParameterValueInput from '@/components/ParameterValueInput'; | ||
import EditParameterSettingsDialog from './EditParameterSettingsDialog'; | ||
|
||
import './Parameters.less'; | ||
|
||
const DragHandle = sortableHandle(({ parameterName }) => ( | ||
<div className="drag-handle" data-test={`DragHandle-${parameterName}`} /> | ||
)); | ||
|
||
const SortableItem = sortableElement(({ className, parameterName, disabled, children }) => ( | ||
<div className={className} data-editable={!disabled || null}> | ||
{!disabled && <DragHandle parameterName={parameterName} />} | ||
{children} | ||
</div> | ||
)); | ||
const SortableContainer = sortableContainer(({ children }) => children); | ||
|
||
function updateUrl(parameters) { | ||
const params = extend({}, $location.search()); | ||
parameters.forEach((param) => { | ||
extend(params, param.toUrlParams()); | ||
}); | ||
Object.keys(params).forEach(key => params[key] == null && delete params[key]); | ||
$location.search(params); | ||
} | ||
|
||
export class Parameters extends React.Component { | ||
static propTypes = { | ||
parameters: PropTypes.arrayOf(PropTypes.instanceOf(Parameter)), | ||
editable: PropTypes.bool, | ||
disableUrlUpdate: PropTypes.bool, | ||
onValuesChange: PropTypes.func, | ||
onParametersEdit: PropTypes.func, | ||
}; | ||
|
||
static defaultProps = { | ||
parameters: [], | ||
editable: false, | ||
disableUrlUpdate: false, | ||
onValuesChange: () => {}, | ||
onParametersEdit: () => {}, | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
const { parameters } = props; | ||
this.state = { parameters, dragging: false }; | ||
if (!props.disableUrlUpdate) { | ||
updateUrl(parameters); | ||
} | ||
} | ||
|
||
componentDidUpdate = (prevProps) => { | ||
const { parameters, disableUrlUpdate } = this.props; | ||
if (prevProps.parameters !== parameters) { | ||
this.setState({ parameters }); | ||
if (!disableUrlUpdate) { | ||
updateUrl(parameters); | ||
} | ||
} | ||
}; | ||
|
||
handleKeyDown = (e) => { | ||
// Cmd/Ctrl/Alt + Enter | ||
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey || e.altKey)) { | ||
e.stopPropagation(); | ||
gabrieldutra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.applyChanges(); | ||
} | ||
}; | ||
|
||
setPendingValue = (param, value, isDirty) => { | ||
this.setState(({ parameters }) => { | ||
if (isDirty) { | ||
param.setPendingValue(value); | ||
} else { | ||
param.clearPendingValue(); | ||
} | ||
return { parameters }; | ||
}); | ||
}; | ||
|
||
moveParameter = ({ oldIndex, newIndex }) => { | ||
const { onParametersEdit } = this.props; | ||
if (oldIndex !== newIndex) { | ||
this.setState(({ parameters }) => { | ||
parameters.splice(newIndex, 0, parameters.splice(oldIndex, 1)[0]); | ||
onParametersEdit(); | ||
return { parameters }; | ||
}); | ||
} | ||
this.setState({ dragging: false }); | ||
}; | ||
|
||
onBeforeSortStart = () => { | ||
this.setState({ dragging: true }); | ||
}; | ||
|
||
applyChanges = () => { | ||
const { onValuesChange, disableUrlUpdate } = this.props; | ||
this.setState(({ parameters }) => { | ||
forEach(parameters, p => p.applyPendingValue()); | ||
onValuesChange(); | ||
if (!disableUrlUpdate) { | ||
updateUrl(parameters); | ||
} | ||
return { parameters }; | ||
}); | ||
}; | ||
|
||
showParameterSettings = (parameter, index) => { | ||
const { onParametersEdit } = this.props; | ||
EditParameterSettingsDialog | ||
.showModal({ parameter }) | ||
.result.then((updated) => { | ||
this.setState(({ parameters }) => { | ||
const updatedParameter = extend(parameter, updated); | ||
parameters[index] = new Parameter(updatedParameter, updatedParameter.parentQueryId); | ||
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. Same idea here, but reconstructing the Parameter instead. |
||
onParametersEdit(); | ||
return { parameters }; | ||
}); | ||
}); | ||
}; | ||
|
||
renderParameter(param, index) { | ||
const { editable } = this.props; | ||
return ( | ||
<div | ||
key={param.name} | ||
className="di-block" | ||
data-test={`ParameterName-${param.name}`} | ||
> | ||
<div className="parameter-heading"> | ||
<label>{param.title || param.name}</label> | ||
{editable && ( | ||
<button | ||
className="btn btn-default btn-xs m-l-5" | ||
onClick={() => this.showParameterSettings(param, index)} | ||
data-test={`ParameterSettings-${param.name}`} | ||
type="button" | ||
> | ||
<i className="fa fa-cog" /> | ||
</button> | ||
)} | ||
</div> | ||
<ParameterValueInput | ||
type={param.type} | ||
value={param.normalizedValue} | ||
parameter={param} | ||
enumOptions={param.enumOptions} | ||
queryId={param.queryId} | ||
allowMultipleValues={!!param.multiValuesOptions} | ||
onSelect={(value, isDirty) => this.setPendingValue(param, value, isDirty)} | ||
/> | ||
</div> | ||
); | ||
} | ||
|
||
render() { | ||
const { parameters, dragging } = this.state; | ||
const { editable } = this.props; | ||
const dirtyParamCount = size(filter(parameters, 'hasPendingValue')); | ||
return ( | ||
<SortableContainer | ||
axis="xy" | ||
useDragHandle | ||
lockToContainerEdges | ||
helperClass="parameter-dragged" | ||
updateBeforeSortStart={this.onBeforeSortStart} | ||
onSortEnd={this.moveParameter} | ||
> | ||
<div | ||
className="parameter-container" | ||
onKeyDown={dirtyParamCount ? this.handleKeyDown : null} | ||
data-draggable={editable || null} | ||
data-dragging={dragging || null} | ||
> | ||
{parameters.map((param, index) => ( | ||
<SortableItem className="parameter-block" key={param.name} index={index} parameterName={param.name} disabled={!editable}> | ||
{this.renderParameter(param, index)} | ||
</SortableItem> | ||
))} | ||
|
||
<ParameterApplyButton onClick={this.applyChanges} paramCount={dirtyParamCount} /> | ||
</div> | ||
</SortableContainer> | ||
); | ||
} | ||
} | ||
|
||
export default function init(ngModule) { | ||
ngModule.component('parameters', react2angular(Parameters)); | ||
} | ||
|
||
init.init = true; |
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.
Removed
isApplying
as it was not affecting anything.