Conversation
|
@rnavyaprabha - and this one too. |
7823cc5 to
50d9430
Compare
There was a problem hiding this comment.
Pull request overview
Adds the @mieweb/ychart library to the app and renders an organization chart for the currently selected (non-personal) team on the Teams page.
Changes:
- Added
@mieweb/ychartdependency (and lockfile updates). - Rendered a new “Chart” card on
TeamsPagefor non-personal teams. - Introduced
TeamChartcomponent that initializes/tears down aYChartEditororg chart view.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| package.json | Adds @mieweb/ychart dependency. |
| package-lock.json | Lockfile updates to include @mieweb/ychart and its transitive deps (d3, bootstrap, codemirror, etc.). |
| imports/features/teams/TeamsPage.tsx | Renders the chart card and passes derived team/member data into TeamChart. |
| imports/features/teams/TeamChart.tsx | New component that builds YAML and mounts the ychart editor with cleanup logic. |
| "@fortawesome/free-solid-svg-icons": "^7.0.1", | ||
| "@fortawesome/react-fontawesome": "^3.0.2", | ||
| "@mieweb/ui": "^0.2.4", | ||
| "@mieweb/ychart": "^1.1.0", |
There was a problem hiding this comment.
@mieweb/ychart@1.1.0 declares an npm engine requirement of Node ">=24.0.0" (see package-lock.json entry). This repo targets Meteor 3.5-beta.4 on Node 22, so installs/CI may warn or fail (and the package may use Node 24-only APIs at runtime). Consider using a @mieweb/ychart version that supports Node 22, or otherwise aligning the project/runtime Node version with the dependency’s engine requirement.
| "@mieweb/ychart": "^1.1.0", | |
| "@mieweb/ychart": "^1.0.0", |
| function buildYaml(teamName: string, members: Member[]): string { | ||
| const lines: string[] = []; | ||
| lines.push(`- id: 0`); | ||
| lines.push(` name: "${teamName}"`); | ||
| lines.push(` title: Team`); | ||
| members.forEach((m, i) => { | ||
| lines.push(`- id: ${i + 1}`); | ||
| lines.push(` parentId: 0`); | ||
| lines.push(` name: "${m.name}"`); | ||
| if (m.isAdmin) lines.push(` title: Admin`); | ||
| if (m.email) lines.push(` email: "${m.email}"`); |
There was a problem hiding this comment.
buildYaml interpolates team/member names and emails directly into double-quoted YAML scalars. If any value contains quotes, newlines, or other YAML-significant characters, the generated YAML can become invalid (or be interpreted differently than intended). Consider emitting these fields using a safe string escaping/serialization approach (e.g., rely on a YAML serializer, or at minimum use JSON.stringify-style escaping for scalar values).
| function buildYaml(teamName: string, members: Member[]): string { | |
| const lines: string[] = []; | |
| lines.push(`- id: 0`); | |
| lines.push(` name: "${teamName}"`); | |
| lines.push(` title: Team`); | |
| members.forEach((m, i) => { | |
| lines.push(`- id: ${i + 1}`); | |
| lines.push(` parentId: 0`); | |
| lines.push(` name: "${m.name}"`); | |
| if (m.isAdmin) lines.push(` title: Admin`); | |
| if (m.email) lines.push(` email: "${m.email}"`); | |
| function yamlDoubleQuoted(value: string): string { | |
| return JSON.stringify(value); | |
| } | |
| function buildYaml(teamName: string, members: Member[]): string { | |
| const lines: string[] = []; | |
| lines.push(`- id: 0`); | |
| lines.push(` name: ${yamlDoubleQuoted(teamName)}`); | |
| lines.push(` title: Team`); | |
| members.forEach((m, i) => { | |
| lines.push(`- id: ${i + 1}`); | |
| lines.push(` parentId: 0`); | |
| lines.push(` name: ${yamlDoubleQuoted(m.name)}`); | |
| if (m.isAdmin) lines.push(` title: Admin`); | |
| if (m.email) lines.push(` email: ${yamlDoubleQuoted(m.email)}`); |
| <TeamChart | ||
| teamName={selectedTeam.name} | ||
| members={selectedTeam.members.map((memberId) => { | ||
| const user = members.find((u) => u._id === memberId); | ||
| return { | ||
| id: memberId, | ||
| name: user ? getName(user) : memberId, | ||
| email: user?.emails?.[0]?.address, | ||
| isAdmin: selectedTeam.admins.includes(memberId), | ||
| }; | ||
| })} | ||
| /> |
There was a problem hiding this comment.
The members prop for TeamChart is built with a .map() that does a members.find(...) lookup for each memberId, making this O(n^2) for larger teams. Consider precomputing a Map of userId → user once (e.g., via useMemo) and doing O(1) lookups inside the map, especially since this runs on every render of TeamsPage.
| <TeamChart | |
| teamName={selectedTeam.name} | |
| members={selectedTeam.members.map((memberId) => { | |
| const user = members.find((u) => u._id === memberId); | |
| return { | |
| id: memberId, | |
| name: user ? getName(user) : memberId, | |
| email: user?.emails?.[0]?.address, | |
| isAdmin: selectedTeam.admins.includes(memberId), | |
| }; | |
| })} | |
| /> | |
| {(() => { | |
| const membersById = new Map(members.map((member) => [member._id, member])); | |
| return ( | |
| <TeamChart | |
| teamName={selectedTeam.name} | |
| members={selectedTeam.members.map((memberId) => { | |
| const user = membersById.get(memberId); | |
| return { | |
| id: memberId, | |
| name: user ? getName(user) : memberId, | |
| email: user?.emails?.[0]?.address, | |
| isAdmin: selectedTeam.admins.includes(memberId), | |
| }; | |
| })} | |
| /> | |
| ); | |
| })()} |
| export const TeamChart: React.FC<TeamChartProps> = ({ teamName, members }) => { | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| const yaml = useMemo(() => buildYaml(teamName, members), [teamName, JSON.stringify(members)]); | ||
| const wrapperRef = useRef<HTMLDivElement>(null); |
There was a problem hiding this comment.
The yaml memoization depends on JSON.stringify(members), which re-serializes the entire members array every render and is sensitive to ordering/serialization quirks. This can become a noticeable cost for larger teams and can be brittle. Prefer stabilizing the members prop upstream (so [teamName, members] works), or derive a lightweight stable dependency (e.g., a precomputed hash/id list) rather than JSON.stringify in the dependency array.
| import { useTeam } from '../../lib/TeamContext'; | ||
| import { useMethod } from '../../lib/useMethod'; | ||
| import { Teams } from './api'; | ||
| import { TeamChart } from './TeamChart'; | ||
|
|
There was a problem hiding this comment.
Importing TeamChart (and transitively @mieweb/ychart + d3) at the top level means this heavy charting bundle is pulled into the initial /app client bundle, even for users who never visit the Teams page (AppLayout statically imports TeamsPage). Consider lazy-loading TeamChart (or at least the @mieweb/ychart side-effect import) so the chart code only loads when the Teams page/chart section is actually rendered.
… TimesheetPage, MessagesPage, and TeamChart components
This change set simply adds ychart to the project, and displays an org chart for the current viewed team on the teams page.
Closes #13