[WEB-3632] - Add Device Names to PDF Export#586
Conversation
|
|
||
| const isPageBreakAtTableStart = !_.isNil(tableLabel) && _.isNil(tableData); | ||
|
|
||
| if (isPageBreakAtTableStart) return; // prevent double header on new page |
There was a problem hiding this comment.
There was a problem hiding this comment.
Pull request overview
This pull request adds device name information to PDF exports in the Basics view, addressing ticket WEB-3632. The implementation extracts device names from upload data, provides a utility function to retrieve user-friendly device names with fallback logic, and renders them in a dedicated table section on the PDF.
Changes:
- Added
deviceNameproperty to the Upload data type and related data flow - Implemented
getDeviceName()utility function to retrieve render-friendly device names with fallback to labels - Added device names rendering section in the Basics PDF print view with automatic height calculation for line wrapping
- Enhanced
onPageAddedhandler to prevent duplicate headers when page breaks occur at table boundaries - Updated test fixtures with device name data
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| data/types.js | Added deviceName property to Upload class |
| src/utils/DataUtil.js | Extracted and stored deviceName from upload data in device objects |
| src/utils/device.js | Added getDeviceName utility function with fallback logic from deviceName to label |
| src/modules/print/PrintView.js | Added devices property extraction and improved onPageAdded handler to prevent double headers |
| src/modules/print/BasicsPrintView.js | Implemented renderDeviceNames method to display unique device names in PDF |
| test/utils/DataUtil.test.js | Updated test fixtures and assertions to include deviceName property |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
clintonium-119
left a comment
There was a problem hiding this comment.
I have a question about the rendering approach in the basics print view that needs addressing.
Also, I'm not seeing the device list additons to the bgLog and daily print views, though they seem to be required by the Jira ticket.
| }); | ||
| }); | ||
|
|
||
| describe('getDeviceName', () => { |
There was a problem hiding this comment.
Small nit - could add a check to make sure 'Unknown' is passed over as in the utility function for completeness
|
|
||
| if (!deviceNames.length) return; | ||
|
|
||
| const rows = [{ label: deviceNames.join('\n\n') }]; |
There was a problem hiding this comment.
This approach seems strange to me, combining all of the devices into a single table row and then having to calculate the heights, account for double-spacing, etc.
Is there a reason you didn't just have each one be a row, and then let the table work this all out natively?
I believe you should be able to set the table styling to match the figma for this, while using rows in a more idiomatic way.
There was a problem hiding this comment.
Okay, I was super close to giving up but managed to do it that way. Significant brute force may have been involved 8)
Prior to today, I was not able to make this work, because despite whatever text I put into the box, the container would not dynamically scale to the height of the text - it only added about one line's worth of height
Explanation of changes:
Per my understanding, the voilab-pdf-table library calls the renderer function twice - first with draw = false. The returned value from this call is used for measuring of the contents so the container can be drawn correctly. The second call with draw = true is then used for the actual drawing.
Prior to my changes to the custom renderer function, it would always return ' ' on the first call. This meant it was measuring the height of a whitespace (for a single line) no matter the input text.
Now, I have adjusted it to return the text itself on the first call. This means it will actually measure to get the necessary height of the container.
With due respect to the library creators, this was confusing as heck
|
|
||
| const isPageBreakAtTableStart = !_.isNil(tableLabel) && _.isNil(tableData); | ||
|
|
||
| if (isPageBreakAtTableStart) return; // prevent double header on new page |
| topEdge: this.margins.top, | ||
| }; | ||
|
|
||
| this.deviceNamesHeader = null; // if needed, call this.generateDeviceNamesHeader(); |
There was a problem hiding this comment.
I wanted the deviceNameHeader property to be shared logic, but I didn't want it to be initialized in reports that don't need it (e.g. if user is only printing AGP). This is just a funky little pattern so that we are only generating the deviceNameHeader data when it is needed, by calling it in the subclasses that use it
A better way to do this might be defining a fun getter property like
get deviceNamesHeader () {
if (!deviceNamesHeaderData) {
this.deviceNamesHeaderData = this.generateDeviceNamesHeader();
}
return this.deviceNamesHeaderData;
}but we don't use any getter properties throughout our codebase so I didn't go with that
There was a problem hiding this comment.
I'm fine with either approach.
| @@ -498,18 +503,30 @@ class PrintView { | |||
| } | |||
|
|
|||
| renderCustomTextCell(tb, data, draw, column, pos, padding, isHeader) { | |||
There was a problem hiding this comment.
Previously, in the pre-draw phase where the container sizes were measured, we were always returning ' '. This meant that we were always measuring the container to fit the height needed for a single whitespace character. We could override this by passing a number for the height, but if left to calculate the necessary height dynamically, voilab-pdf-table would measure based on the whitespace character. This is fine for single-line text cells (which is all we had before) but now, with dynamic-height text cells, we need to give the PDF library the actual string so it can dynamically set the height of the container.
| label, | ||
| content, | ||
| height, | ||
| }; |
There was a problem hiding this comment.
Unfortunately this is more complicated than I wanted it to be with all of the measurements. Per the requirements, the height needed to be dynamic to accommodate large device lists. This ensures that the daily and bgLog charts can adjust their content start positions based on the list length, like so.
There was a problem hiding this comment.
Has any product discussion come up about whether or not we should be filtering the devices list to only display those present in the data used for a given view?
It would seem to me to be ideal to only list BGM devices on this view, in particular.
But if you did go to the trouble of filtering, it's probably not too time-consuming to also filter the daily and basics device lists too.
There was a problem hiding this comment.
Thanks @clintonium-119 , I don't know why this eluded me or I didn't think about this.
I made a discussion thread here: https://tidepoolteam.slack.com/archives/C01ELEQUVRD/p1772666366797099
The way I see it, there are two sub-questions:
-
A) Do we filter only for devices for the patient that have data in the current time frame?
-
B) Do we only show BGM devices on BgLog report pages?
For Question A, if we do want to filter only for those, my intuition is to filter the devices array by looking to see if it exists in matchedDevices.
In your opinion, do you think that approach would work for Question A?
There was a problem hiding this comment.
@clintonium-119 okay, so the direction from product (slack thread):
Show all devices (regardless of bgm/cgm) but only those with data for the current time frame.
I've made the change to match those with matchedDevices here: 6380d15
|
@clintonium-119 I have revamped the entire PR. Please have another look, but code that you "already reviewed" may have been changed significantly. |
clintonium-119
left a comment
There was a problem hiding this comment.
This looks good, but I'd just like confirmation that the product intent is not to show the a filtered device list for each report section, so that, for instance, the BG Log view doesn't list CGMs and pumps that did not provide bg reading for that view, and so on.
| topEdge: this.margins.top, | ||
| }; | ||
|
|
||
| this.deviceNamesHeader = null; // if needed, call this.generateDeviceNamesHeader(); |
There was a problem hiding this comment.
I'm fine with either approach.
| label, | ||
| content, | ||
| height, | ||
| }; |
There was a problem hiding this comment.
Has any product discussion come up about whether or not we should be filtering the devices list to only display those present in the data used for a given view?
It would seem to me to be ideal to only list BGM devices on this view, in particular.
But if you did go to the trouble of filtering, it's probably not too time-consuming to also filter the daily and basics device lists too.
|
@clintonium-119 ready for another look. Added filtering by matchedDevices |
|
Hey @clintonium-119 , this is ready for another look |

WEB-3632
Blip: tidepool-org/blip#1851