Conversation
remove the usage of redux's Connect from the vision page by using the PlainTable instead of the default Table (TableWithOptions). there are still performance issues, buut it is usable.
i've decided to not use a <table> anymore to host this data as it seems the material-ui table causes some issues with transitions and animating table row is hacky at best a simple <ul> implementation seems to be more performant
# Conflicts: # src/components/Match/Match.css # src/components/Match/VisionMap.jsx # src/components/Match/matchColumns.jsx # src/components/TabBar/TabBar.jsx # src/components/Table/Table.css # src/components/Table/Table.jsx # src/components/Visualizations/Table/HeroImage.jsx # webpack.config.js
src/components/Match/VisionMap.jsx
Outdated
| enabledIndex: {}, | ||
| }); | ||
| shouldComponentUpdate(newProps) { | ||
| if (newProps.wardsLog.length == this.props.wardsLog.length) return false; |
There was a problem hiding this comment.
This is a boolean so you can return it directly
src/components/Match/VisionMap.jsx
Outdated
| enabledIndex: {}, | ||
| }); | ||
| shouldComponentUpdate(newProps) { | ||
| if (newProps.wardsLog.length == this.props.wardsLog.length) return false; |
There was a problem hiding this comment.
This is a boolean so you can return it directly
src/components/Match/VisionMap.jsx
Outdated
| this.updateMap = this.updateMap.bind(this); | ||
|
|
||
| componentDidMount() { | ||
| window.addEventListener("resize", () => this.forceUpdate()); |
There was a problem hiding this comment.
I think @mike-robertson will advise that you use redux-responsive's state.browser.width for this
There was a problem hiding this comment.
Let's iterate on this once the component is shipped.
src/components/Match/VisionPage.jsx
Outdated
| class PlayerFilter extends React.PureComponent { | ||
| constructor(props) { | ||
| super(props); | ||
| this.getObserverCount = () => this.props.player.obs_log.length; |
There was a problem hiding this comment.
i'd advise making these functions outside the class, and take props as a parameter.
There was a problem hiding this comment.
This component will be refactored.
src/components/Match/VisionPage.jsx
Outdated
| <Col xs> | ||
| <Button {...this.getMuiThemeProps()} | ||
| label={obs_count} | ||
| disabled={obs_count == 0} |
src/components/Match/VisionPage.jsx
Outdated
| backgroundColor={this.generateFilterKey("observer") in this.props.activeFilters ? filterOff : filterOn} | ||
| style={{opacity: obs_count > 0 ? opacityOn : opacityOff}} | ||
| onClick={() => onFilterClick(this.generateFilterKey("observer"), player.player_slot, "observer")} | ||
| icon={<Avatar size={24} src="http://a19a1164.ngrok.io/apps/dota2/images/items/ward_observer_lg.png" />} |
src/components/Match/VisionPage.jsx
Outdated
|
|
||
| class VisionPage extends React.Component { | ||
| componentWillMount() { | ||
| Perf.start(); |
There was a problem hiding this comment.
should this be disabled for production?
There was a problem hiding this comment.
Isn't react-addons-perf already doing this under the hood?
src/components/Match/VisionPage.jsx
Outdated
| return _.rangeStep(interval, 0, this.props.match.duration); | ||
| } | ||
|
|
||
| _handleViewportChange(value) { |
There was a problem hiding this comment.
I think eslint will complain about the use of underscores since javascript doesn't really have any idea of private properties.
There was a problem hiding this comment.
Yeah that was to test quickly the debounce, I'll figure out a better name
src/components/Match/WardLog.jsx
Outdated
|
|
||
| // a simple functor that will call the correct function depending on value | ||
| const threshold = _.curry((start, limits, values, value) => { | ||
| if (limits.length != values.length) throw "Limits must be the same as functions."; |
There was a problem hiding this comment.
I need to extract this functor in utility
src/utility/components.jsx
Outdated
| } | ||
| }; | ||
|
|
||
| export const Pure = (Component) => class extends React.PureComponent { |
There was a problem hiding this comment.
what's the difference between this and a function component?
There was a problem hiding this comment.
There is no difference, it just reads better when using an existing component.
const PureRow = Pure(Row);
src/utility/components.jsx
Outdated
| @@ -0,0 +1,16 @@ | |||
| import React from 'react'; | |||
|
|
|||
| export const Fixed = (Component) => class extends React.Component { | |||
There was a problem hiding this comment.
Doesn't the Redux store take care of this kind of comparison already?
There was a problem hiding this comment.
The Vision filters are in the local state r/n.
# Conflicts: # src/components/Match/VisionMap.jsx # src/utility/index.jsx
|
I must lint this. |
|
I think this is ready to ship. |
|
Reviewers: |
blukai
left a comment
There was a problem hiding this comment.
Also it wont work for me VisionPage.jsx?6a5e:62 - Uncaught TypeError: Cannot assign to read only property 'key' of object '#<Object>'
src/components/Match/Match.css
Outdated
|
|
||
| :root { | ||
| --ward-log-height: 50px; | ||
| --slider-ticks-color: #757575; |
There was a problem hiding this comment.
I guess this colors should be defined in palette.css
package.json
Outdated
| "isomorphic-fetch": "2.2.1", | ||
| "lodash": "^4.16.4", | ||
| "material-ui": "0.16.1", | ||
| "moment-duration-format": "^1.3.0", |
There was a problem hiding this comment.
Do we need this new 7 dependencies?
There was a problem hiding this comment.
Let me explain why those have been added:
- Lodash: I don't feel like implementing my how flow() to compose my filters. I suggest we use the 'lodash/fp' import that is more geared toward functional programming. (I also use: inRange, sortByIndex, map/filter).
- moment-duration-format: I don't think I'm using it, so I guess I'll remove it. Good catch.
- react-addons-css-transition-group: de facto transition component for React
- react-measure: This is to deal with the resizing of the page. @howardchung suggested I use the Redux store size, but I don't see how that can integrate with the flexgrid sizing. @mike-robertson you are welcome to comment.
- seamless-immutable: okay that is a subject of its own, but this manage immutable Object/Array and make it so deeply nested values can be compared with a simple reference equality check. Having immutable objects in the Redux store is considered a good practice.
- react-addons-perf: That is very helpful to dig down React rendering and find performance issues
- react-perf-tool: I think that expose it to the Chrome extension
src/components/Match/Match.css
Outdated
|
|
||
| .ward-log { | ||
| width: 100%; | ||
| font-size: .8em; |
There was a problem hiding this comment.
We have some defined font sizes in palette.css. I guess 0.8em is somehing like 12px so u can use --fontSizeSmall
There was a problem hiding this comment.
I'll oblige but I think that using px as font size is a bad practice for mobility. I'd rather leave it that way or refactor to use em/rem all around.
There was a problem hiding this comment.
We should link it to --fontSizeSmall then convert that em then
blukai
left a comment
There was a problem hiding this comment.
👍 Some things that we should fix someday:
- team headings
<Heading title.. icon../>ex: https://github.com/odota/ui/blob/master/src/components/Match/matchPages.jsx#L55 - wrap this into table (maybe) and fix red

Also it can be done in this pr
| const [opacityOn, opacityOff] = [1, 0.4]; | ||
| return ( | ||
| <Row | ||
| className={styles['filter-row']} |
There was a problem hiding this comment.
We use camelcase in the css files so we don't need to do things like this. I know camelCase isn't standard css, but for css-modules, it is.
| }); | ||
| } | ||
|
|
||
| generateFilterKey(type) { |
There was a problem hiding this comment.
don't you need to bind this in the constructor so you don't lose 'this' context?
src/components/Match/VisionPage.jsx
Outdated
| {props.ticks.map((tick) => { | ||
| const [t, min, max] = [tick, props.min, props.max]; | ||
| const percent = 100 * ((t - min) / (max - min)); | ||
| const cls = [styles['slider-tick']]; |
There was a problem hiding this comment.
use camelCase to avoid this
src/components/Match/VisionPage.jsx
Outdated
| ); | ||
|
|
||
| const PipelineFilter = (filters, data, iter = Array.prototype.filter) => { | ||
| const filtered = filters.map(f => iter.call(data, f)) |
There was a problem hiding this comment.
const filteredData = filters.reduce(
(arr, filt) => arr.filter(filt),
data
);
return data.filter(obj => !filteredData.includes(obj));Doesn't this do the same thing but is easier to understand? Plus no lodash, and you don't need to have a reference to the Array.prototype.filter function.
There was a problem hiding this comment.
I'm not 100% sure the implementation is does exactly the same thing.
There was a problem hiding this comment.
I can remove the prototype reference.
| this.ticks = this.computeTick(); | ||
| this.findPivot = value => _.flow(_.map(x => x.entered.time), | ||
| _.sortedIndex(value))(this.state.wardsLog); | ||
| this.handleViewportChange = _.debounce(50, this.viewportChange); |
There was a problem hiding this comment.
why not just do:
this.handleViewportChange = () => setTimeout(this.viewportChange, 50);No reason to drag in a third party library for that, right?
There was a problem hiding this comment.
This is not debouncing, this is deferring. You'll still call on every change event, 50ms after the call stack has been emptied.
|
|
||
| const observers = extractWardLog('observer', player.obs_log, player.obs_left_log); | ||
| const sentries = extractWardLog('sentry', player.sen_log, player.sen_left_log); | ||
| return _.concat(observers, sentries); |
There was a problem hiding this comment.
observers.concat(sentries)| _.flatten, | ||
| _.sortBy(xs => xs.entered.time), | ||
| imap((x, i) => ({ ...x, key: i })), | ||
| ); |
There was a problem hiding this comment.
If this can avoid using lodash, I would prefer that, but I don't know exactly what 'convert' is doing here. It seems weird to me that we would need to flatten this array one level, but I don't know what the data looks like.
There was a problem hiding this comment.
The fp flavor cap the iteratee to a certain arrity, this removes that cap. It is basically to have the index in the iteratee function.
| newPlayer.objective_damage[identifier] + player.damage[key] : | ||
| player.damage[key]; | ||
| newPlayer.objective_damage[identifier] + player.damage[key] : | ||
| player.damage[key]; |
There was a problem hiding this comment.
not sure I am a fan of this tabbing, but if others are I won't fight it.
| return input; | ||
| } | ||
|
|
||
| export const threshold = _.curry((start, limits, values, value) => { |
There was a problem hiding this comment.
Same comment here, you could just invoke this function like threshold()()()() and manually curry the function definition but it you are against doing that (so you can do threshold(1, 2, 3)(4)), I'll defer to your judgement.
|
|
||
| const limitsWithStart = limits.slice(0); | ||
| limitsWithStart.unshift(start); | ||
| return findLast(values, (v, i) => _.inRange(limitsWithStart[i], limitsWithStart[i + 1], value)); |
There was a problem hiding this comment.
useful method, but I don't know if it is worth bringing in all of lodash for. Though if we can get away with the 4kb gzipped lodash and you want to use these, I'm down with that. I'm mostly against using lodash when we could instead use native implementations at essentially no extra cost.
|
will this integrate #445 ? |
|
Let's merge this first then iterate on it if you guys don't mind. #445 is easy to add after. |
|
I didn't remove lodash usage but I tried to use native methods when available and not changing the implementation. |
src/components/Match/renderMatch.js
Outdated
| }) | ||
| ; | ||
|
|
||
| const observers = extractWardLog('observer', player.obs_log, player.obs_left_log); |
There was a problem hiding this comment.
will this crash if !player.obs_log (unparsed match?)
There was a problem hiding this comment.
I fixed this, I really thought this was handled up in the Component hierarchy.
Match vision tab overhaul
fixes #342
This PR addresses #342 and will add a bunch of new features to the Vision Tab, including:
Keep in mind that this is a work in progress.
I've also refactored certain components while working on this page.
There are still refactoring/extracting that needs to be done.
Comments welcome.