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

Typescriptize reports files #5079

Open
wants to merge 11 commits into
base: beta
Choose a base branch
from
Open

Conversation

magicznyleszek
Copy link
Member

@magicznyleszek magicznyleszek commented Aug 26, 2024

Checklist

  1. If you've added code that should be tested, add tests
  2. If you've changed APIs, update (or create!) the documentation
  3. Ensure the tests pass
  4. Make sure that your code lints and that you've followed our coding style
  5. Write a title and, if necessary, a description of your work suitable for publishing in our release notes
  6. Mention any related issues in this repository (as #ISSUE) and in other repositories (as kobotoolbox/other#ISSUE)
  7. Open an issue in the docs if there are UI/UX changes

Description

Migrated all reports related code to TypeScript, so it's easier to improve it in future. Also changed the UI responsible for creating new reports, so it's clearer how to add new custom report.

Notes

I didn't want to go too far with refactoring the code, just the bare minimum to make the code work consistently and be mostly readable.

Changes here:

  • Migrated jsapp/js/components/common/modal.tsx to TypeScript
    • Also fixed the Esc key handling of Modal component (this is the old deprecated one). The unmount process wasn't really removing the listener.
  • Changed the topmost part of "Project > Data > Reports", so now it has a heading similar to other routes, and the reports selection/creation uses more friendly UX (now dropdown is just for selecting a report, and creation of new report is moved out of dropdown to a button next to the dropdown)
  • Moved all non-TS code from /jsapp/js/components/reports/ to TS.
  • Cleaned up reports related types from AssetResponse, and defined all the shared types of reports in reportsConstants.ts file
  • All partial components (the ones being used in reports modals) are now having pending state while things are being saved on Back End. Previously the main reports file was simply reacting to Reflux actions being started, not completed, and it was a weird thing. Part of this is still kinda there, as it would require a bigger refactor.
  • Added few TODO comments for things that I saw being bad, but didn't want to touch
  • Created reports.utils.ts file for keeping some reusable functions
  • Created new ReportsModalTabs component to remove duplicated code being used in two places
  • Fixed getReportData (from dataInterface.ts) function types, as paginated response doesn't follow our usual PaginatedResponse<T>
  • Moved txtid function from CoffeeScript file to utils.ts, so it was available for refactored reports code

Related issues

Build atop #5046

@magicznyleszek magicznyleszek changed the base branch from beta to task915-simplify-button-component August 26, 2024 06:55
@magicznyleszek magicznyleszek marked this pull request as ready for review August 26, 2024 07:15
…eports-files

# Conflicts:
#	jsapp/js/popoverMenu.scss
Base automatically changed from task915-simplify-button-component to beta September 3, 2024 22:15
Copy link
Member

@duvld duvld left a comment

Choose a reason for hiding this comment

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

Besides some questions and a tiny bug the functionality seems all intact. I have a suggestion though, do you think we can split a PR like this into multiple? A typescriptization IMO should be singular and (almost) trivial--if the compiler doesn't complain and we do a quick review then it should be merged. This would remove a lot of noise and confusion if there's a refactor that's coming as well.

jsapp/js/components/reports/reportsConstants.ts Outdated Show resolved Hide resolved
jsapp/js/components/reports/reportsConstants.ts Outdated Show resolved Hide resolved
* the Chart.js), the latter is the instance of a report style (as Back end
* understands it).
*/
export const REPORT_STYLES: ReportStyleDefinitions = Object.freeze({
Copy link
Member

Choose a reason for hiding this comment

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

I'm trying to understand this as I don't encounter using mapped types often and at first glace this feels very circular.

So ReportStyleName is just a union of strings that we get from Chart.js. ReportStyleDefinition is an interface that ties up the report style strings from Chart.js with a string label and a chartJsType. In essence the existence of ReportStyleDefinition is to combine together the type, label and Chart.js stuff for each graph type.

Then ReportStyleDefinitions is a mapped type that creates an instance which has each unioned string in ReportStyleName as a value and its type is ReportStyleDefinition. We then manually set REPORT_STYLES to fit this type?

Then we have a ReportStyle type, which by the looks of it are settings/configs that can be applied to each report and change the way it's presented. Do you think this could have a better name, such as ReportStyleSettings?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, this weird construct is needed so everything ties together in the places that use the const. I renamed REPORT_STYLES to CHART_STYLES (and all the other related things renamed to use "chart" word) to make it less confusing.


const reportData = this.props.reportData;

// TODO: the code below is very convoluted and hard to read/understand, even
Copy link
Member

Choose a reason for hiding this comment

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

Oh my 🥲 if you have some time I would love to know how this works--assuming you had time to figure it out while doing this typescriptization

defaultStyle: ReportStyle;
}

export default function ChartColorsPicker(props: ChartColorsPickerProps) {
Copy link
Member

Choose a reason for hiding this comment

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

Why do we switch this one to a functional component? Some of the other typescriptization files remained as class components

import type {FailResponse} from 'js/dataInterface';

interface QuestionGraphSettingsProps {
parentState: ReportsState;
Copy link
Member

Choose a reason for hiding this comment

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

Would it be hard to refactor this into a store of some kind? Maybe a good second issue for the furture

}
}

const tabs: ReportsModalTabName[] = ['chart-type', 'colors'];
Copy link
Member

Choose a reason for hiding this comment

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

Think we talked about this before but just quickly, do we think using enums here is too redundant?

// HACK: We no longer keep built PreparedTable in state, it's simply rebuilt
// during render. We keep this to ensure that re-render happens when props
// change.
static getDerivedStateFromProps() {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if I'm not reading the diffs correctly, but was this method never used? I don't see it removed anywhere except here

@@ -169,59 +169,6 @@
}
}

.popover-menu--custom-reports {
Copy link
Member

Choose a reason for hiding this comment

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

I didn't see this change mentioned in the description, were these just unused styles?

if (!this.props.disableEscClose && (evt.keyCode === KEY_CODES.ESC || evt.key === 'Escape')) {
this.props.onClose.call(evt);
}
}

backdropClick(evt) {
backdropClick(evt: TouchEvent) {
Copy link
Member

Choose a reason for hiding this comment

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

This error happens when clicking the backdrop now:

Uncaught TypeError: this is undefined
    backdropClick modal.tsx:72

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants