Skip to content

Commit a5f8b7c

Browse files
dbczumarZangr
andauthored
MLflow UI updates (mlflow#5346)
* Project import generated by Copybara. GitOrigin-RevId: aa07f148a58047d04ab2f41270abcdb171521d50 Signed-off-by: dbczumar <[email protected]> * Reintroduce missing yarn config Signed-off-by: dbczumar <[email protected]> * Undo tz removal Signed-off-by: dbczumar <[email protected]> * Comment Signed-off-by: dbczumar <[email protected]> * Expand comment Signed-off-by: dbczumar <[email protected]> * Pull comment out Signed-off-by: dbczumar <[email protected]> * Fix Signed-off-by: dbczumar <[email protected]> * Remove blank line Signed-off-by: dbczumar <[email protected]> * Add windows to linebreak style Signed-off-by: dbczumar <[email protected]> * Single quote Signed-off-by: dbczumar <[email protected]> * Try gitattr instead Signed-off-by: dbczumar <[email protected]> Co-authored-by: Richard Zang <[email protected]>
1 parent 1335164 commit a5f8b7c

File tree

8 files changed

+72
-30
lines changed

8 files changed

+72
-30
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

mlflow/server/js/.env

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
SKIP_PREFLIGHT_CHECK=true
2+
DISABLE_ESLINT_PLUGIN=true

mlflow/server/js/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,12 @@
8686
"redux-mock-store": "^1.5.4"
8787
},
8888
"scripts": {
89+
"//": "IMPORTANT: For compatibility with Windows in MLflow OSS, do NOT inline environment variables in scripts other than `start-web`. Environment variables can instead be set in `mlflow/server/js/scripts/global-setup.js`.",
8990
"start": "react-app-rewired start",
9091
"start-web": "SERVE_WEBAPP=true HIDE_HEADER=true HIDE_EXPERIMENT_LIST=true SHOW_GDPR_PURGING_MESSAGES=true USE_ABSOLUTE_AJAX_URLS=true SHOULD_REDIRECT_IFRAME=true PORT=3001 react-app-rewired start",
9192
"build": "react-app-rewired --max_old_space_size=8192 build",
92-
"test": "react-app-rewired test --env=jsdom --colors",
93-
"test:debug": "react-app-rewired --inspect-brk test --runInBand --no-cache --env=jsdom",
93+
"test": "eslint src && react-app-rewired test --env=jsdom --colors",
94+
"test:debug": "eslint src && react-app-rewired --inspect-brk test --runInBand --no-cache --env=jsdom",
9495
"eject": "react-scripts eject",
9596
"lint": "eslint src",
9697
"lint:fix": "eslint src --fix",

mlflow/server/js/src/common/components/CollapsibleTagsCell.js mlflow/server/js/src/common/components/CollapsibleTagsCell.jsx

+23-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import Utils from '../utils/Utils';
44
import { css } from 'emotion';
5+
import { Tooltip } from '@databricks/design-system';
56

67
// Number of tags shown when cell is collapsed
78
export const NUM_TAGS_ON_COLLAPSED = 3;
@@ -47,16 +48,21 @@ export class CollapsibleTagsCell extends React.Component {
4748
{tagsToDisplay.map((entry) => {
4849
const tagName = entry[0];
4950
const value = entry[1];
51+
const tooltipContent = value === '' ? tagName : `${tagName}: ${value}`;
5052
return (
5153
<div className='tag-cell-item truncate-text single-line' key={tagName}>
52-
{value === '' ? (
53-
<span className='tag-name'>{tagName}</span>
54-
) : (
55-
<span>
56-
<span className='tag-name'>{tagName}:</span>
57-
<span className='metric-param-value'>{value}</span>
58-
</span>
59-
)}
54+
<Tooltip title={tooltipContent} placement="bottom">
55+
<span className={overflowWithEllipsis}>
56+
{value === '' ? (
57+
<span className='tag-name'>{tagName}</span>
58+
) : (
59+
<span>
60+
<span className='tag-name'>{tagName}:</span>
61+
<span className='metric-param-value'>{value}</span>
62+
</span>
63+
)}
64+
</span>
65+
</Tooltip>
6066
</div>
6167
);
6268
})}
@@ -71,4 +77,13 @@ const expandableListClassName = css({
7177
textDecoration: 'underline',
7278
cursor: 'pointer',
7379
},
80+
'.tag-cell-item': {
81+
display: 'flex',
82+
}
83+
});
84+
85+
const overflowWithEllipsis = css({
86+
textOverflow: 'ellipsis',
87+
overflow: 'hidden',
88+
flexShrink: 1,
7489
});

mlflow/server/js/src/common/components/CollapsibleTagsCell.test.js

+11
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,15 @@ describe('unit tests', () => {
5151
instance.setState({ collapsed: false });
5252
expect(wrapper.find('.tag-cell-item')).toHaveLength(numTags);
5353
});
54+
55+
test('tooltip should contain tag name and value', () => {
56+
const numTags = 1;
57+
const props = setupProps(numTags);
58+
wrapper = shallow(<CollapsibleTagsCell {...props} />);
59+
instance = wrapper.instance();
60+
expect(wrapper.find('.tag-cell-item')).toHaveLength(1);
61+
const tooltip = wrapper.find('Tooltip');
62+
expect(tooltip).toHaveLength(1);
63+
expect(tooltip.props().title).toBe('tag0: value0');
64+
});
5465
});

mlflow/server/js/src/experiment-tracking/components/ExperimentPage.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export class ExperimentPage extends Component {
7474
constructor(props) {
7575
super(props);
7676
const store = ExperimentPage.getLocalStore(this.props.experimentId);
77+
const urlState = Utils.getSearchParamsFromUrl(props.location.search);
7778
this.state = {
7879
lastRunsRefreshTime: Date.now(),
7980
numberOfNewRuns: 0,
@@ -85,7 +86,7 @@ export class ExperimentPage extends Component {
8586
urlState: props.location.search,
8687
persistedState: new ExperimentPagePersistedState({
8788
...store.loadComponentState(),
88-
...Utils.getSearchParamsFromUrl(props.location.search),
89+
...urlState,
8990
}).toJSON(),
9091
pollingState: {
9192
newRuns: true,

mlflow/server/js/src/experiment-tracking/components/ExperimentView.js

+20-16
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ export class ExperimentView extends Component {
178178
};
179179
}
180180

181-
/* Returns a LocalStorageStore instance that can be used to persist data associated with the
181+
/**
182+
* Returns a LocalStorageStore instance that can be used to persist data associated with the
182183
* ExperimentView component (e.g. component state such as table sort settings), for the
183184
* specified experiment.
184185
*/
@@ -193,7 +194,8 @@ export class ExperimentView extends Component {
193194
return true;
194195
}
195196

196-
/* Returns true if search filter text was updated, e.g. if a user entered new text into the
197+
/**
198+
* Returns true if search filter text was updated, e.g. if a user entered new text into the
197199
* param filter, metric filter, or search text boxes.
198200
*/
199201
filtersDidUpdate(prevState) {
@@ -382,12 +384,19 @@ export class ExperimentView extends Component {
382384

383385
renderShareButton() {
384386
return (
385-
<HeaderButton onClick={this.onShare} className={css(styles.shareButton)}>
386-
<FormattedMessage
387-
defaultMessage='Share'
388-
description='String for the share button to share experiment view'
389-
/>
390-
</HeaderButton>
387+
<Tooltip
388+
title={this.props.intl.formatMessage({
389+
defaultMessage: 'Share experiment view',
390+
description: 'Label for the share experiment view button',
391+
})}
392+
>
393+
<HeaderButton onClick={this.onShare}>
394+
<FormattedMessage
395+
defaultMessage='Share'
396+
description='String for the share button to share experiment view'
397+
/>
398+
</HeaderButton>
399+
</Tooltip>
391400
);
392401
}
393402

@@ -514,10 +523,12 @@ export class ExperimentView extends Component {
514523
/* eslint-disable prefer-const */
515524
let breadcrumbs = [];
516525
let form;
526+
517527
const artifactLocationProps = {
518528
experiment: this.props.experiment,
519529
intl: this.props.intl,
520530
};
531+
521532
const ColumnSortByOrder = [COLUMN_SORT_BY_ASC, COLUMN_SORT_BY_DESC];
522533
let sortOptions = [];
523534
const attributesSortBy = Object.keys(ATTRIBUTE_COLUMN_SORT_LABEL).reduce(
@@ -604,14 +615,7 @@ export class ExperimentView extends Component {
604615
data-test-id='experiment-view-page-header'
605616
menu={this.getExperimentOverflowItems()}
606617
/>
607-
<Tooltip
608-
title={this.props.intl.formatMessage({
609-
defaultMessage: 'Share experiment view',
610-
description: 'Label for the share experiment view button',
611-
})}
612-
>
613-
{this.renderShareButton()}
614-
</Tooltip>
618+
{this.renderShareButton()}
615619
</PageHeader>
616620
{this.renderOnboardingContent()}
617621
<Descriptions className='metadata-list'>

mlflow/server/js/src/model-registry/components/SchemaTable.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ export class SchemaTableImpl extends React.PureComponent {
7676

7777
render() {
7878
const { schema } = this.props;
79-
const plusIcon = <i className='far fa-plus-square' />;
80-
const minusIcon = <i className='far fa-minus-square' />;
8179
const hasSchema = schema.inputs.length || schema.outputs.length;
8280
const sectionHeaders = hasSchema
8381
? [
@@ -123,7 +121,17 @@ export class SchemaTableImpl extends React.PureComponent {
123121
defaultExpandAllRows={this.props.defaultExpandAllRows}
124122
expandRowByClick
125123
expandedRowRender={(record) => record.table}
126-
expandIcon={({ expanded }) => (expanded ? minusIcon : plusIcon)}
124+
expandIcon={({ expanded, onExpand, record }) =>
125+
expanded ? (
126+
<span onClick={(e) => onExpand(record, e)}>
127+
<i className='far fa-minus-square' />
128+
</span>
129+
) : (
130+
<span onClick={(e) => onExpand(record, e)}>
131+
<i className='far fa-plus-square' />
132+
</span>
133+
)
134+
}
127135
locale={{
128136
emptyText: (
129137
<div>

0 commit comments

Comments
 (0)