Add institutions, contributions, and third party information to the About window#229
Conversation
There was a problem hiding this comment.
Pull request overview
This PR expands the About modal to include stewarding institutions, GitHub contributors (across OpenSpace/OpenSpace, OpenSpace/Ghoul, and OpenSpace/OpenSpace-WebGui), and a third-party licenses section backed by a generated TypeScript data file.
Changes:
- Adds a new Redux slice + async thunk to fetch and aggregate GitHub contributors across multiple repos.
- Extends the About modal UI to render contributor avatars/links and third-party license details via collapsible sections.
- Introduces a
scripts/generateThirdParty.tsgenerator and its generated output (src/data/ThirdPartyDependencies.ts) plus new i18n strings.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/redux/store.ts | Registers the new contributors reducer in the Redux store. |
| src/redux/contributors/contributorsSlice.ts | Adds contributors slice state (contributors, status) wired to thunk lifecycle. |
| src/redux/contributors/contributorsMiddleware.ts | Implements GitHub API fetching, pagination, and contribution aggregation. |
| src/components/About/About.tsx | Updates About modal layout, triggers contributor fetch, and renders contributors + third-party licenses. |
| src/data/ThirdPartyDependencies.ts | Adds generated third-party dependency metadata including full license texts. |
| scripts/generateThirdParty.ts | Adds generator script to parse a markdown license file and emit ThirdPartyDependencies.ts. |
| public/locales/en/components.json | Adds new About modal translation strings (institutions, contributors, third-party labels). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { Collapsable } from '@/components/Collapsable/Collapsable'; | ||
| import { ThirdPartyDependencies } from '@/data/ThirdPartyDependencies'; | ||
| import { getContributors } from '@/redux/contributors/contributorsMiddleware'; | ||
| import { useAppDispatch, useAppSelector } from '@/redux/hooks'; |
There was a problem hiding this comment.
I don't know how much of a problem this actually is based on the size of the dependencies list, but it makes a good point.
The about page is rarely loaded, but now every user pays the "cost" of statically loading this data file. In this case, it seems to suggest loading this data as part of the useEffect (i.e. when the modal opens). This would mean doing something like this:
import { useEffect, useState } from "react";
export function About({ opened }) {
const [licenses, setLicenses] = useState(null);
useEffect(() => {
if (!opened || licenses) {
return;
}
async function load() {
const module = await import("@/data/ThirdPartyDependencies");
setLicenses(module.ThirdPartyDependencies);
}
load();
}, [opened, licenses]);
return (
// Other rendering code...
<Title order={3} mt={'md'} mb={'xs'}>
{t('third-party-title')}
</Title>
{ licenses && /** Render the licence list **/ }
);
}An alternative could be to move the third-party licences part into a separate component, and then use React. lazy to lazily load that entire component:
// This component statically loads a large json file containing all third party
// dependencies and their licenses. To avoid loading this file when the About modal is
// not open, we lazy load the component that renders the list of dependencies
const ThirdPartyDependenciesList = React.lazy(() =>
import('./ThirdPartyDependenciesList').then((module) => ({
default: module.ThirdPartyDependenciesList
}))
);
// In the render function:
<Title order={3} mt={'md'} mb={'xs'}>
{t('third-party-title')}
</Title>
<Suspense fallback={<Loader />}>
<ThirdPartyDependenciesList />
</Suspense>There was a problem hiding this comment.
If it is not that big of a deal (file is about 200 lines and not going to grow that much more), I guess we can keep it as it is as well
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
WeirdRubberDuck
left a comment
There was a problem hiding this comment.
Looks good to me overall but needs some minor fixes
| import { Collapsable } from '@/components/Collapsable/Collapsable'; | ||
| import { ThirdPartyDependencies } from '@/data/ThirdPartyDependencies'; | ||
| import { getContributors } from '@/redux/contributors/contributorsMiddleware'; | ||
| import { useAppDispatch, useAppSelector } from '@/redux/hooks'; |
There was a problem hiding this comment.
I don't know how much of a problem this actually is based on the size of the dependencies list, but it makes a good point.
The about page is rarely loaded, but now every user pays the "cost" of statically loading this data file. In this case, it seems to suggest loading this data as part of the useEffect (i.e. when the modal opens). This would mean doing something like this:
import { useEffect, useState } from "react";
export function About({ opened }) {
const [licenses, setLicenses] = useState(null);
useEffect(() => {
if (!opened || licenses) {
return;
}
async function load() {
const module = await import("@/data/ThirdPartyDependencies");
setLicenses(module.ThirdPartyDependencies);
}
load();
}, [opened, licenses]);
return (
// Other rendering code...
<Title order={3} mt={'md'} mb={'xs'}>
{t('third-party-title')}
</Title>
{ licenses && /** Render the licence list **/ }
);
}An alternative could be to move the third-party licences part into a separate component, and then use React. lazy to lazily load that entire component:
// This component statically loads a large json file containing all third party
// dependencies and their licenses. To avoid loading this file when the About modal is
// not open, we lazy load the component that renders the list of dependencies
const ThirdPartyDependenciesList = React.lazy(() =>
import('./ThirdPartyDependenciesList').then((module) => ({
default: module.ThirdPartyDependenciesList
}))
);
// In the render function:
<Title order={3} mt={'md'} mb={'xs'}>
{t('third-party-title')}
</Title>
<Suspense fallback={<Loader />}>
<ThirdPartyDependenciesList />
</Suspense>Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Adds additional information into the About window. Stewarding institutions are now mentioned as well as contributors to the main repos (OpenSpace/OpenSpace, OpenSpace/Ghoul, and OpenSpace-WebGui). The contributors are sorted by numbre of contributions and contain the GitHub logo and a link to the GitHub page.
Also adds a new script that parses OpenSpace's THIRD_PARTY_LIBRARIES file to add that information to the About panel as well.
Before:
After:


