Skip to content

Add institutions, contributions, and third party information to the About window#229

Merged
alexanderbock merged 9 commits into
masterfrom
feature/about-page
Jul 9, 2026
Merged

Add institutions, contributions, and third party information to the About window#229
alexanderbock merged 9 commits into
masterfrom
feature/about-page

Conversation

@alexanderbock

Copy link
Copy Markdown
Member

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:

image

After:
image
image
image

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.ts generator 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.

Comment thread src/redux/contributors/contributorsMiddleware.ts
Comment thread src/components/About/About.tsx
Comment thread src/components/About/About.tsx Outdated
Comment thread src/components/About/About.tsx Outdated
Comment thread src/components/About/About.tsx Outdated
Comment thread scripts/generateThirdParty.ts
Comment thread scripts/generateThirdParty.ts Outdated
Comment thread scripts/generateThirdParty.ts
Comment thread src/data/ThirdPartyDependencies.ts
Comment on lines +17 to +20
import { Collapsable } from '@/components/Collapsable/Collapsable';
import { ThirdPartyDependencies } from '@/data/ThirdPartyDependencies';
import { getContributors } from '@/redux/contributors/contributorsMiddleware';
import { useAppDispatch, useAppSelector } from '@/redux/hooks';

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ehm.. Help?

@WeirdRubberDuck WeirdRubberDuck Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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

alexanderbock and others added 5 commits June 25, 2026 01:39
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
WeirdRubberDuck self-requested a review July 3, 2026 10:59

@WeirdRubberDuck WeirdRubberDuck left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good to me overall but needs some minor fixes

Comment thread src/components/About/About.tsx
Comment thread src/data/ThirdPartyDependencies.ts
Comment on lines +17 to +20
import { Collapsable } from '@/components/Collapsable/Collapsable';
import { ThirdPartyDependencies } from '@/data/ThirdPartyDependencies';
import { getContributors } from '@/redux/contributors/contributorsMiddleware';
import { useAppDispatch, useAppSelector } from '@/redux/hooks';

@WeirdRubberDuck WeirdRubberDuck Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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>
@alexanderbock
alexanderbock merged commit 1ebcad7 into master Jul 9, 2026
1 check failed
@alexanderbock
alexanderbock deleted the feature/about-page branch July 9, 2026 11:10
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.

3 participants