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

Tree component refactoring #1863

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open

Conversation

victorlin
Copy link
Member

@victorlin victorlin commented Oct 8, 2024

Description of proposed changes

Changes made while prepping for #1373. These can be considered independently from that PR. See individual commit messages.

Checklist

@victorlin victorlin self-assigned this Oct 8, 2024
@nextstrain-bot nextstrain-bot temporarily deployed to auspice-victorlin-prep--fjlw4s October 8, 2024 00:14 Inactive
@victorlin victorlin temporarily deployed to auspice-victorlin-prep--fjlw4s October 8, 2024 00:49 Inactive
@victorlin victorlin marked this pull request as ready for review October 8, 2024 00:52
Using ReturnType on all sub-states except for controls (which already
has a type to be used directly) and narrative (the compiler was not able
to resolve types between return values and default state). The next
commit will fix the narrative type.
@victorlin victorlin force-pushed the victorlin/prep-dynamic-yvalues branch from 9ecca22 to 8280aaa Compare October 8, 2024 18:00
@victorlin victorlin temporarily deployed to auspice-victorlin-prep--fjlw4s October 8, 2024 18:00 Inactive
@victorlin victorlin force-pushed the victorlin/prep-dynamic-yvalues branch from 8280aaa to 33277b5 Compare October 8, 2024 23:28
@victorlin victorlin temporarily deployed to auspice-victorlin-prep--fjlw4s October 8, 2024 23:28 Inactive
}

clearSelectedNode = () => {
callbacks.clearSelectedNode.bind(this);
Copy link
Member

@jameshadfield jameshadfield Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[reminder to me] - check this change, I remember binding callbacks in the constructor was "the right way" way back when I was writing this code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see:

// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md#es6-classes
this.fitMapBoundsToData = this.fitMapBoundsToData.bind(this);

I've replaced 1eedee4 with a1aec38.

@jameshadfield
Copy link
Member

@genehack could you take a look at the types added / used here if you have a chance? 🙏

@victorlin victorlin temporarily deployed to auspice-victorlin-prep--fjlw4s October 9, 2024 17:22 Inactive
This was necessary to properly type the root state.

Note: AnyAction is used for `action` which is only slightly better than
any. Ideally, each action type would come with its own TypeScript
interface but there is no good way to tightly couple those. I think the
right improvement here is to use Redux's createSlice but that is beyond
the scope of adding types.
This allows type checking on the new entries.
This does not provide much benefit as-is, but should facilitate future
usage of TypeScript within the component.
The commented out usage was removed in "Excise react-svg-pan-zoom"
(56fbb8a).
Keep consistent with other parts of the file.
Only the clearSelectedNode binding needs to be kept in the constructor.
@victorlin victorlin force-pushed the victorlin/prep-dynamic-yvalues branch from 6d65167 to ceec881 Compare October 9, 2024 21:40
@victorlin victorlin temporarily deployed to auspice-victorlin-prep--fjlw4s October 9, 2024 21:41 Inactive
Comment on lines 124 to 127
const anyTreeZoomed = this.props.tree.idxOfInViewRootNode !== 0 ||
this.props.treeToo.idxOfInViewRootNode !== 0;

const activeResetTreeButton = anyTreeZoomed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you're gonna make these two variables the same thing why not just go the one extra step and rename treeIsZoomed directly to activeResetTreeButton, and then update the ternaries below to also use activeResetTreeButton? Seems less confusing in the longer run.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, done: 4d8a2e0

I chose to go the other way around and drop activeResetTreeButton in favor of anyTreeZoomed to convey the condition rather than end state.

Comment on lines 43 to 54
interface Defaults {
distanceMeasure: string
layout: Layout
geoResolution: string
filters: Record<string, any>
filtersInFooter: string[]
colorBy: string
selectedBranchLabel: string
tipLabelKey: typeof strainSymbol
showTransmissionLines: boolean
sidebarOpen?: boolean
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd put this up around L15, so it's defined before being used in the (current) L18 -- was briefly confused where Defaults was even coming from.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done:

type Layout = "rect" | "radial" | "unrooted" | "clock" | "scatter"
interface Defaults {
distanceMeasure: string
layout: Layout
geoResolution: string
filters: Record<string, any>
filtersInFooter: string[]
colorBy: string
selectedBranchLabel: string
tipLabelKey: typeof strainSymbol
showTransmissionLines: boolean
sidebarOpen?: boolean
}
export interface BasicControlsState {
defaults: Defaults
layout: Layout

filtersInFooter: string[]
colorBy: string
selectedBranchLabel: string
tipLabelKey: typeof strainSymbol
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the advantage of doing this versus adding a proper type in ../utils/globals and exporting it from there?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to dig a deeper hole and convert src/utils/globals.js to TypeScript. Even if I were to do that, I'm not sure that adding a proper type would be useful in this case. In globals.ts it would simply be:

- export const strainSymbol = Symbol('strain');
+ export const strainSymbol: unique symbol = Symbol('strain');

and the same typeof strainSymbol would still be used here.

Comment on lines +35 to +36
state: NarrativeState = defaultState,
action: AnyAction,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you provide a default value to a positional param if there's a subsequent positional param without a default value? or do you need to switch the order here, or convert this to being passed an object?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point – ESLint and TypeScript clearly had no complaints about this so I searched to confirm – it is allowed in JavaScript. From MDN docs on default parameters:

Parameters are still set left-to-right, overwriting default parameters even if there are later parameters without defaults.

function f(x = 1, y) {
  return [x, y];
}

f(); // [1, undefined]
f(2); // [2, undefined]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a good pattern, but it is the pattern used for other files in src/reducers/ so I will keep it as-is.

- `treeIsZoomed` is ambiguous since the condition considers two trees.
  Rename to `anyTreeZoomed`.
- `activeResetTreeButton` has the same condition as `anyTreeZoomed`.
  Reuse the existing variable.
Partial<ControlsState> previously worked but has the side effect of
marking all keys as optional, which is not accurate and prone to cause
future type errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants