mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-12 23:31:02 +00:00
86513fda0d
On a managed install the operator runs place search and routing, the plugin runtime, the integrations and the documentation, so the admin and the users no longer see switches and guides for them: - The place search and routing card, the transit provider and the search log are gone from the admin settings (desktop and mobile). places_provider is a managed-locked setting, and the transit provider, search log and wanderer routes refuse writes there. Share place details stays the admin's, as a card of its own, hidden when TREK_PLACES_CONTRIBUTE switches it off. - File types and trip reminders move to the right column, so the columns stay balanced. - Plugins disappear from the admin and the user settings, wanderer from Tours. - The Help & Docs page and its links are not offered. The help center stays and leaves out guides about what the operator runs (keys, OIDC, backups, storage, releases, plugins, document sync) and about integrations that are off. - Mapbox GL is offered only with the operator's token, Amap tiles only where the operator set Amap up. - The mobile admin no longer shows OIDC and the WebAuthn relying party fields, matching the desktop tab. For every install: - Notification matrices list only events the install can raise: no plugin row without the plugin runtime, no Vacay, collection, photo, Synology, wanderer or packing rows while those are off. On a managed install the release and replica alerts are left out. - The journey entry editor offers External photos only where a photo provider is switched on, as the phone already did. - app-config is asked again after a failed answer. A page opened while the server restarted kept every default for the session, which on a managed install brought back the operator's settings.
114 lines
4.5 KiB
TypeScript
114 lines
4.5 KiB
TypeScript
import { AMAP_ROAD, AMAP_SATELLITE } from '../../constants/mapDefaults';
|
|
import type { Place } from '../../types';
|
|
import {
|
|
MAPBOX_DEFAULT_STYLE,
|
|
isOpenFreeMapStyle,
|
|
normalizeStyleForProvider,
|
|
type GlMapProvider,
|
|
} from '../Map/glProviders';
|
|
|
|
/**
|
|
* The map settings both shells share: the tile presets, the provider and style rules,
|
|
* and the preview place. The user's map settings and the admin's defaults for users
|
|
* read the same presets, so the two can never offer a different list by accident.
|
|
*/
|
|
|
|
export interface MapPreset {
|
|
name: string;
|
|
url: string;
|
|
}
|
|
|
|
/**
|
|
* The tile presets a user picks from in their own map settings, and the same list
|
|
* an admin picks the default for every user from.
|
|
*/
|
|
export const MAP_PRESETS: MapPreset[] = [
|
|
{ name: 'OpenStreetMap', url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png' },
|
|
{ name: 'OpenStreetMap DE', url: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png' },
|
|
// The app default, and a vector style rather than a {z}/{x}/{y} template: no
|
|
// key, no registration, no request limits.
|
|
{ name: 'OpenFreeMap Positron', url: 'https://tiles.openfreemap.org/styles/positron' },
|
|
{ name: 'OpenFreeMap Bright', url: 'https://tiles.openfreemap.org/styles/bright' },
|
|
// CARTO watermarks keyless tiles since 26.08.2026 and issues keys by mail, so
|
|
// these two need one; without it the map falls back to the default (#2054).
|
|
{ name: 'CartoDB Light', url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png' },
|
|
{ name: 'CartoDB Dark', url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png' },
|
|
{ name: 'Stadia Smooth', url: 'https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png' },
|
|
// Amap (高德). GCJ-02 tiles: the map switches to a shifted projection for
|
|
// these so markers still land on the right street (see gcj02Crs.ts). The only
|
|
// basemap here that is genuinely good inside mainland China.
|
|
{ name: '高德地图 (Amap)', url: AMAP_ROAD },
|
|
{ name: '高德卫星 (Amap Satellite)', url: AMAP_SATELLITE },
|
|
];
|
|
|
|
/**
|
|
* The presets this install offers. On a managed install Amap is the operator's
|
|
* service like every other keyed one: its tiles are offered only where the
|
|
* operator set Amap up (has_amap_key), so a hosted user is never pointed at a
|
|
* provider the instance does not use.
|
|
*/
|
|
export function mapPresetsFor(managed: boolean, hasAmapKey: boolean): MapPreset[] {
|
|
if (!managed || hasAmapKey) return MAP_PRESETS;
|
|
return MAP_PRESETS.filter((p) => p.url !== AMAP_ROAD && p.url !== AMAP_SATELLITE);
|
|
}
|
|
|
|
/**
|
|
* Whether Mapbox GL can be picked. A managed install brings the token with the
|
|
* instance and offers no field for one, so without an operator token the
|
|
* choice would only lead to a map that never loads.
|
|
*/
|
|
export function mapboxOffered(managed: boolean, token: string | null | undefined): boolean {
|
|
return !managed || !!token;
|
|
}
|
|
|
|
export type MapProvider = 'leaflet' | GlMapProvider;
|
|
|
|
export function normalizeProvider(value: unknown): MapProvider {
|
|
return value === 'mapbox-gl' || value === 'maplibre-gl' ? value : 'leaflet';
|
|
}
|
|
|
|
export function styleForProvider(provider: MapProvider, style?: string | null): string {
|
|
if (provider === 'leaflet') return style || MAPBOX_DEFAULT_STYLE;
|
|
if (provider === 'mapbox-gl' && isOpenFreeMapStyle(style)) return MAPBOX_DEFAULT_STYLE;
|
|
return normalizeStyleForProvider(provider, style);
|
|
}
|
|
|
|
// Each GL provider has its own style slot, so toggling providers never clobbers the
|
|
// other one's style. Leaflet/Mapbox use mapbox_style; MapLibre uses maplibre_style.
|
|
export function slotStyle(
|
|
provider: MapProvider,
|
|
s: { mapbox_style?: string; maplibre_style?: string }
|
|
): string | undefined {
|
|
return provider === 'maplibre-gl' ? s.maplibre_style : s.mapbox_style;
|
|
}
|
|
|
|
/**
|
|
* Somewhere recognisable for the style preview to render. A city shows off label density,
|
|
* 3D buildings and satellite texture in a way open ocean cannot. It is not a user setting,
|
|
* and no map opens here: each map frames itself on its own places.
|
|
*/
|
|
export const PREVIEW_CENTER: [number, number] = [48.8566, 2.3522];
|
|
export const PREVIEW_ZOOM = 16;
|
|
|
|
/** The one place the user's map preview shows. */
|
|
export function previewPlace(): Place {
|
|
return {
|
|
id: 1,
|
|
trip_id: 1,
|
|
name: 'Preview',
|
|
description: '',
|
|
lat: PREVIEW_CENTER[0],
|
|
lng: PREVIEW_CENTER[1],
|
|
address: '',
|
|
category_id: 0,
|
|
price: null,
|
|
image_url: null,
|
|
google_place_id: null,
|
|
osm_id: null,
|
|
route_geometry: null,
|
|
place_time: null,
|
|
end_time: null,
|
|
created_at: String(new Date()),
|
|
};
|
|
}
|