Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d5f95e1
Add DGGS plugin
thangqd Aug 2, 2026
33da50a
Add DGGS plugin - fix oxfmt
thangqd Aug 2, 2026
1357bad
Merge branch 'opengeos:main' into feat/dggs-support
thangqd Aug 2, 2026
7be6704
Update packages/plugins/src/plugins/maplibre-dggal.ts
thangqd Aug 3, 2026
2c54449
Update packages/plugins/src/plugins/maplibre-dggrid.ts
thangqd Aug 3, 2026
0e80214
Update tests/a5-plugin.test.ts
thangqd Aug 3, 2026
73ff794
Update apps/geolibre-desktop/src/i18n/locales/en.json
thangqd Aug 3, 2026
885ba68
Update tests/dggal-plugin.test.ts
thangqd Aug 3, 2026
afdb072
Update tests/olc-plugin.test.ts
thangqd Aug 3, 2026
f468e07
Update packages/plugins/src/plugins/maplibre-dggrid.ts
thangqd Aug 3, 2026
3b4042b
Merge upstream/main into feat/dggs-support
thangqd Aug 3, 2026
feafcf1
Merge branch 'feat/dggs-support' of https://github.com/opengeoshub/Ge…
thangqd Aug 3, 2026
6b71094
Update maplibre-dggrid.ts
thangqd Aug 3, 2026
f6d9e25
Update tests/dggrid-plugin.test.ts
thangqd Aug 3, 2026
5825a51
Update maplibre-dggal.ts
thangqd Aug 3, 2026
a7e89eb
Merge branch 'feat/dggs-support' of https://github.com/opengeoshub/Ge…
thangqd Aug 3, 2026
088f894
Update TopToolbar.tsx
thangqd Aug 3, 2026
10295bd
fix coderabbitai requested changes
thangqd Aug 3, 2026
6f4fa15
fix coderabbit requested changes
thangqd Aug 3, 2026
47e17c3
oxfmt fix
thangqd Aug 3, 2026
dac9547
Handle DGGS WASM load failures and fix stale panel comments.
thangqd Aug 3, 2026
37894b3
Restore open-data plugins and address remaining CodeRabbit DGGS notes.
thangqd Aug 3, 2026
77b0cc0
Fix DGGAL full-world span and GitHub raw proxy URL validation.
thangqd Aug 3, 2026
39237e3
Harden GitHub raw proxy URL checks and assert unique full-world DGGAL…
thangqd Aug 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
425 changes: 259 additions & 166 deletions apps/geolibre-desktop/src/components/layout/TopToolbar.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
COMPONENTS_PLUGIN_ID,
DECK_VIZ_PLUGIN_ID,
DGGS_PLUGIN_IDS,
DIRECTIONS_PLUGIN_ID,
type GeoLibreMapControlPosition,
GRATICULE_PLUGIN_ID,
Expand Down Expand Up @@ -37,6 +38,9 @@ type RegisteredPlugin = PluginRegistry["plugins"][number];
// Plugins grouped under the "Web Services" submenu of the Plugins menu.
const WEB_SERVICE_PLUGIN_ID_SET = new Set<string>(WEB_SERVICE_PLUGIN_IDS);

// The discrete global grids (H3, S2, A5) grouped under the "DGGS" submenu.
const DGGS_PLUGIN_ID_SET = new Set<string>(DGGS_PLUGIN_IDS);

interface PluginsMenuProps {
chrome: ToolbarChrome;
appApi: AppApi;
Expand Down Expand Up @@ -117,6 +121,13 @@ export function PluginsMenu({
// first of them appears in registration order (just above Historical Imagery).
let webServicesRendered = false;

const dggsPlugins = plugins.filter(
(p) => DGGS_PLUGIN_ID_SET.has(p.id) && !hiddenPluginIds.has(p.id),
);
// The DGGS grid plugins (H3, S2, A5) render as one grouped submenu, placed
// where the first of them appears in registration order.
let dggsRendered = false;

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
Expand Down Expand Up @@ -161,6 +172,24 @@ export function PluginsMenu({
if (hiddenPluginIds.has(p.id)) {
return null;
}
if (DGGS_PLUGIN_ID_SET.has(p.id)) {
// Same one-shot pattern as the Web Services submenu below: the
// submenu renders at the first visible DGGS plugin's position and
// later ones are skipped.
if (dggsRendered) return null;
dggsRendered = true;
return (
<DropdownMenuSub key="dggs">
<DropdownMenuSubTrigger>
{t("toolbar.item.dggs")}
{dggsPlugins.some((plugin) => isActive(plugin.id)) ? " ✓" : ""}
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
{dggsPlugins.map(renderPluginMenuItem)}
</DropdownMenuSubContent>
</DropdownMenuSub>
);
}
if (!WEB_SERVICE_PLUGIN_ID_SET.has(p.id)) {
return renderPluginMenuItem(p);
}
Expand Down
72 changes: 16 additions & 56 deletions apps/geolibre-desktop/src/hooks/usePlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ import {
maplibreNasaEarthdataPlugin,
maplibreNationalMapPlugin,
maplibreOpenAerialMapPlugin,
maplibreArcGisHubPlugin,
maplibreCkanPlugin,
maplibreSocrataPlugin,
maplibreStacCatalogsPlugin,
maplibreSourceCoopPlugin,
maplibreNaturalEarthPlugin,
Expand All @@ -48,6 +45,13 @@ import {
queryOvertureFeatures,
maplibreGraticulePlugin,
maplibreH3Plugin,
maplibreS2Plugin,
maplibreA5Plugin,
maplibreDggridPlugin,
maplibreDggalPlugin,
maplibreOlcPlugin,
maplibreGeohashPlugin,
maplibreTilecodePlugin,
maplibreCloudsPlugin,
maplibrePrecipitationPlugin,
maplibreMapillaryPlugin,
Expand Down Expand Up @@ -176,9 +180,6 @@ manager.registerAll([
maplibreNationalMapPlugin,
maplibreEarthdataGisPlugin,
maplibreOpenAerialMapPlugin,
maplibreArcGisHubPlugin,
maplibreSocrataPlugin,
maplibreCkanPlugin,
maplibreStacCatalogsPlugin,
maplibreSourceCoopPlugin,
maplibreNaturalEarthPlugin,
Expand All @@ -195,7 +196,16 @@ manager.registerAll([
maplibreElevationProfilePlugin,
maplibreSwipePlugin,
maplibreGraticulePlugin,
// The DGGS grid plugins (grouped into the Plugins menu's "DGGS" submenu,
// rendered where the first of them appears in this order).
maplibreH3Plugin,
maplibreS2Plugin,
maplibreA5Plugin,
maplibreDggridPlugin,
maplibreDggalPlugin,
maplibreOlcPlugin,
maplibreGeohashPlugin,
maplibreTilecodePlugin,
maplibreCloudsPlugin,
maplibrePrecipitationPlugin,
maplibreEffectsPlugin,
Expand Down Expand Up @@ -1017,35 +1027,6 @@ export function createAppAPI(mapControllerRef?: RefObject<MapController | null>)
// presence to auto-discover shapefile sidecars instead of forcing the user
// to select every component, and to capture the file's path for restore.
pickVectorFilesWithSidecars: isTauriRuntime() ? pickVectorFilesWithSidecars : undefined,
fetchVectorUrl: async (url: string) => {
if (isTauriRuntime()) {
try {
const bytes = await fetchUrlBytes(url, { context: "Add Vector Layer" });
const array = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
return new Blob([array as Uint8Array<ArrayBuffer>]);
} catch {
// The shared native command has a short, tile-oriented timeout.
// Preserve the former browser path for large CORS-enabled datasets.
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status} ${response.statusText}`);
}
return response.blob();
} catch {
// GitHub's /raw route rejects browser CORS, so fall through to the
// same guarded proxy used by the web build.
}
}
}
const proxyUrl = githubRawVectorProxyUrl(url);
if (!proxyUrl) return null;
const response = await fetch(proxyUrl);
if (!response.ok) {
throw new Error(`HTTP ${response.status} ${response.statusText}`);
}
return response.blob();
},
readLocalVectorFile: readVectorFileWithSidecars,
exportTextFile: (filename: string, content: string, options?: GeoLibreFileDialogOptions) => {
const description = options?.description ?? "GeoJSON";
Expand Down Expand Up @@ -1315,27 +1296,6 @@ function isTauriRuntime(): boolean {
return Boolean((window as TauriRuntimeWindow).__TAURI_INTERNALS__);
}

const GITHUB_RAW_VECTOR_PROXY = "https://tiles.geolibre.app/github-raw";

function githubRawVectorProxyUrl(value: string): string | null {
let url: URL;
try {
url = new URL(value);
} catch {
return null;
}
if (
url.protocol !== "https:" ||
url.hostname !== "github.com" ||
!/^\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/raw\/.+$/.test(url.pathname)
) {
return null;
}
const proxy = new URL(GITHUB_RAW_VECTOR_PROXY);
proxy.searchParams.set("url", url.href);
return proxy.href;
}

function setExternalPluginsLoaded(loaded: boolean): void {
if (externalPluginsLoaded === loaded) return;
externalPluginsLoaded = loaded;
Expand Down
Loading