refactor: restrict WikiTree integration to the apps.wikitree.com domain and add helper utilities

This commit is contained in:
Przemek Więch
2026-07-05 20:35:44 +02:00
parent aeb73aced7
commit b285fe349f
6 changed files with 49 additions and 15 deletions

View File

@@ -38,7 +38,7 @@ Here is an example from the Web:
* [J. F. Kennedy](https://pewu.github.io/topola-viewer/#/view?url=https%3A%2F%2Fchronoplexsoftware.com%2Fmyfamilytree%2Fsamples%2FThe%2520Kennedy%2520Family.gdz) (from [chronoplexsoftware.com](https://chronoplexsoftware.com/myfamilytree/samples/)) * [J. F. Kennedy](https://pewu.github.io/topola-viewer/#/view?url=https%3A%2F%2Fchronoplexsoftware.com%2Fmyfamilytree%2Fsamples%2FThe%2520Kennedy%2520Family.gdz) (from [chronoplexsoftware.com](https://chronoplexsoftware.com/myfamilytree/samples/))
* [Shakespeare](https://pewu.github.io/topola-viewer/#/view?url=https%3A%2F%2Fwebtreeprint.com%2Ftp_downloader.php%3Fpath%3Dfamous_gedcoms%2Fshakespeare.ged%26file%3Dshakespeare.ged) (from [webtreeprint.com](https://webtreeprint.com/tp_famous_gedcoms.php)) * [Shakespeare](https://pewu.github.io/topola-viewer/#/view?url=https%3A%2F%2Fwebtreeprint.com%2Ftp_downloader.php%3Fpath%3Dfamous_gedcoms%2Fshakespeare.ged%26file%3Dshakespeare.ged) (from [webtreeprint.com](https://webtreeprint.com/tp_famous_gedcoms.php))
* [Maria Skłodowska-Curie](https://pewu.github.io/topola-viewer/#/view?indi=Sk%C5%82odowska-2&source=wikitree) (from [WikiTree](https://www.wikitree.com/wiki/Sk%C5%82odowska-2)) * [Maria Skłodowska-Curie](https://apps.wikitree.com/apps/wiech13/topola-viewer/#/view?indi=Sk%C5%82odowska-2&source=wikitree) (from [WikiTree](https://www.wikitree.com/wiki/Sk%C5%82odowska-2))
If you have data in a genealogy database, you can export your data in GEDCOM format and load it using the "Load from file" menu. If you have data in a genealogy database, you can export your data in GEDCOM format and load it using the "Load from file" menu.

View File

@@ -6,6 +6,7 @@ import {
Person, Person,
} from 'wikitree-js'; } from 'wikitree-js';
import {TopolaError} from '../util/error'; import {TopolaError} from '../util/error';
import {isOnWikitreeDomain} from '../util/wikitree_util';
const WIKITREE_APP_ID = 'topola-viewer'; const WIKITREE_APP_ID = 'topola-viewer';
/** Prefix for IDs of private individuals. */ /** Prefix for IDs of private individuals. */
@@ -270,7 +271,7 @@ export async function loadData(
authcode?: string, authcode?: string,
): Promise<Person[]> { ): Promise<Person[]> {
// Work around CORS if not in apps.wikitree.com domain. // Work around CORS if not in apps.wikitree.com domain.
const handleCors = window.location.hostname !== 'apps.wikitree.com'; const handleCors = !isOnWikitreeDomain();
await logInIfNeeded(authcode, handleCors); await logInIfNeeded(authcode, handleCors);

View File

@@ -6,6 +6,7 @@ import {Card, Grid, Image} from 'semantic-ui-react';
import {getChangelog, updateSeenVersion} from './changelog'; import {getChangelog, updateSeenVersion} from './changelog';
import logo from './topola.jpg'; import logo from './topola.jpg';
import {Media} from './util/media'; import {Media} from './util/media';
import {isOnWikitreeDomain, WIKITREE_TOPOLA_URL} from './util/wikitree_util';
/** Link that loads a view. */ /** Link that loads a view. */
function ViewLink(props: {params: {[key: string]: string}; text: string}) { function ViewLink(props: {params: {[key: string]: string}; text: string}) {
@@ -82,13 +83,23 @@ function Contents() {
) )
</li> </li>
<li> <li>
<ViewLink {isOnWikitreeDomain() ? (
params={{ <ViewLink
indi: 'Skłodowska-2', params={{
source: 'wikitree', indi: 'Skłodowska-2',
}} source: 'wikitree',
text="Maria Skłodowska-Curie" }}
/>{' '} text="Maria Skłodowska-Curie"
/>
) : (
<a
href={`${WIKITREE_TOPOLA_URL}/#/view?source=wikitree&indi=Sk%C5%82odowska-2`}
target="_blank"
rel="noopener noreferrer"
>
Maria Skłodowska-Curie
</a>
)}{' '}
(<FormattedMessage id="intro.from" defaultMessage="from" />{' '} (<FormattedMessage id="intro.from" defaultMessage="from" />{' '}
<a href="https://www.wikitree.com/wiki/Sk%C5%82odowska-2"> <a href="https://www.wikitree.com/wiki/Sk%C5%82odowska-2">
wikitree.com wikitree.com

View File

@@ -5,6 +5,7 @@ import {Dropdown, Icon, Menu} from 'semantic-ui-react';
import {IndiInfo, JsonGedcomData} from 'topola'; import {IndiInfo, JsonGedcomData} from 'topola';
import {isGoogleDriveConfigured} from '../datasource/google_drive_service'; import {isGoogleDriveConfigured} from '../datasource/google_drive_service';
import {Media} from '../util/media'; import {Media} from '../util/media';
import {isOnWikitreeDomain} from '../util/wikitree_util';
import {GoogleDriveMenu} from './google_drive_menu'; import {GoogleDriveMenu} from './google_drive_menu';
import {MenuItem, MenuType} from './menu_item'; import {MenuItem, MenuType} from './menu_item';
import {SearchBar} from './search'; import {SearchBar} from './search';
@@ -50,6 +51,11 @@ export function TopBar(props: Props) {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
// WikiTree menus only work when hosted on apps.wikitree.com because
// WikiTree's API requires same-origin access. The CORS proxy workaround is
// no longer functional.
const showWikiTree = props.showWikiTreeMenus && isOnWikitreeDomain();
const {searchResults, searchString, setSearchString, handleResultSelect} = const {searchResults, searchString, setSearchString, handleResultSelect} =
useSearch({ useSearch({
data: props.data, data: props.data,
@@ -246,7 +252,7 @@ export function TopBar(props: Props) {
<> <>
<UploadMenu menuType={menuType} {...props} /> <UploadMenu menuType={menuType} {...props} />
<UrlMenu menuType={menuType} {...props} /> <UrlMenu menuType={menuType} {...props} />
<WikiTreeMenu menuType={menuType} {...props} /> {showWikiTree && <WikiTreeMenu menuType={menuType} {...props} />}
<GoogleDriveMenu <GoogleDriveMenu
menuType={menuType} menuType={menuType}
onTokenAcquired={props.onGoogleTokenAcquired} onTokenAcquired={props.onGoogleTokenAcquired}
@@ -257,7 +263,7 @@ export function TopBar(props: Props) {
function fileMenus(screenSize: ScreenSize) { function fileMenus(screenSize: ScreenSize) {
// In standalone WikiTree mode, show only the "Select WikiTree ID" menu. // In standalone WikiTree mode, show only the "Select WikiTree ID" menu.
if (!props.standalone && props.showWikiTreeMenus) { if (!props.standalone && showWikiTree) {
switch (screenSize) { switch (screenSize) {
case ScreenSize.LARGE: case ScreenSize.LARGE:
return <WikiTreeMenu menuType={MenuType.Menu} {...props} />; return <WikiTreeMenu menuType={MenuType.Menu} {...props} />;
@@ -307,7 +313,7 @@ export function TopBar(props: Props) {
} }
function wikiTreeLoginMenu(screenSize: ScreenSize) { function wikiTreeLoginMenu(screenSize: ScreenSize) {
if (!props.showWikiTreeMenus) { if (!showWikiTree) {
return null; return null;
} }
return ( return (

View File

@@ -5,6 +5,7 @@ import {useLocation, useNavigate} from 'react-router';
import {Button, Form, Header, Input, Modal} from 'semantic-ui-react'; import {Button, Form, Header, Input, Modal} from 'semantic-ui-react';
import {getLoggedInUserName, navigateToLoginPage} from 'wikitree-js'; import {getLoggedInUserName, navigateToLoginPage} from 'wikitree-js';
import {analyticsEvent} from '../util/analytics'; import {analyticsEvent} from '../util/analytics';
import {WIKITREE_TOPOLA_URL} from '../util/wikitree_util';
import {MenuItem, MenuType} from './menu_item'; import {MenuItem, MenuType} from './menu_item';
import wikitreeLogo from './wikitree.png'; import wikitreeLogo from './wikitree.png';
@@ -157,10 +158,8 @@ export function WikiTreeLoginMenu(props: Props) {
* Topola Viewer hosted on apps.wikitree.com. * Topola Viewer hosted on apps.wikitree.com.
*/ */
function login() { function login() {
const wikiTreeTopolaUrl =
'https://apps.wikitree.com/apps/wiech13/topola-viewer';
// TODO: remove authcode if it is in the current URL. // TODO: remove authcode if it is in the current URL.
const returnUrl = `${wikiTreeTopolaUrl}${window.location.hash}`; const returnUrl = `${WIKITREE_TOPOLA_URL}${window.location.hash}`;
navigateToLoginPage(returnUrl); navigateToLoginPage(returnUrl);
} }

17
src/util/wikitree_util.ts Normal file
View File

@@ -0,0 +1,17 @@
/**
* Base URL for Topola Viewer hosted on apps.wikitree.com.
* WikiTree API calls only work when the app is served from this domain.
*/
export const WIKITREE_TOPOLA_URL =
'https://apps.wikitree.com/apps/wiech13/topola-viewer';
/**
* Returns true if the app is currently hosted on the apps.wikitree.com domain.
*
* WikiTree's API requires being served from this domain due to authentication
* and CORS restrictions. When not on this domain, WikiTree data loading does
* not work.
*/
export function isOnWikitreeDomain(): boolean {
return window.location.hostname === 'apps.wikitree.com';
}