Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,21 @@ def _upload_files_to_gcs(self, file_to_upload):
self.bucket_name,
blob_path,
)

try:
blob.make_public()
self.logger.debug(
"Made object public: https://storage.googleapis.com/%s/%s",
self.bucket_name,
blob_path,
)
except Exception as e:
# Likely due to Uniform bucket-level access; log and continue
self.logger.warning(
"Could not make %s public (uniform bucket-level access enabled?): %s",
blob_path,
e,
)
except Exception as e:
raise Exception(f"Failed to upload files to GCS: {e}") from e

Expand Down
4 changes: 4 additions & 0 deletions web-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@turf/center": "^6.5.0",
"@types/i18next": "^13.0.0",
"@types/leaflet": "^1.9.12",
"@types/react-map-gl": "^6.1.7",
"axios": "^1.7.2",
"countries-list": "^3.1.1",
"date-fns": "^2.30.0",
Expand All @@ -24,10 +25,12 @@
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.5.2",
"leaflet": "^1.9.4",
"maplibre-gl": "^4.7.1",
"material-react-table": "^2.13.0",
"mui-datatables": "^4.3.0",
"mui-nested-menu": "^3.4.0",
"openapi-fetch": "^0.9.3",
"pmtiles": "^4.2.1",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"react-ga4": "^2.1.0",
Expand All @@ -36,6 +39,7 @@
"react-hook-form": "^7.52.1",
"react-i18next": "^14.1.2",
"react-leaflet": "^4.2.1",
"react-map-gl": "^7.1.7",
"react-redux": "^8.1.3",
"react-router-dom": "^6.16.0",
"react-scripts": "5.0.1",
Expand Down
16 changes: 16 additions & 0 deletions web-app/src/app/Theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ declare module '@mui/material/styles' {
interface PaletteOptions {
boxShadow?: string;
}
interface Theme {
map: {
basemapTileUrl: string;
};
}

interface ThemeOptions {
map?: {
basemapTileUrl?: string;
};
}
}

declare module '@mui/material/Typography' {
Expand Down Expand Up @@ -96,6 +107,11 @@ export const getTheme = (mode: ThemeModeEnum): Theme => {
const chosenPalette = !isLightMode ? darkPalette : palette;
return createTheme({
palette: { ...chosenPalette, mode },
map: {
basemapTileUrl: isLightMode
? 'https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png'
: 'https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',
},
mixins: {
code: {
contrastText: '#f1fa8c',
Expand Down
2 changes: 1 addition & 1 deletion web-app/src/app/components/ContentBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const ContentBox = (
mb: 1,
}}
>
<span>{props.title}</span>
{props.title.trim() !== '' && <span>{props.title}</span>}
{props.action != null && props.action}
</Typography>
)}
Expand Down
199 changes: 123 additions & 76 deletions web-app/src/app/components/CoveredAreaMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
Skeleton,
Button,
Typography,
Fab,
} from '@mui/material';
import { Link } from 'react-router-dom';
import MapIcon from '@mui/icons-material/Map';
import TravelExploreIcon from '@mui/icons-material/TravelExplore';
import { ContentBox } from './ContentBox';
Expand All @@ -28,6 +30,9 @@
import { displayFormattedDate } from '../utils/date';
import { useSelector } from 'react-redux';
import { selectAutodiscoveryGbfsVersion } from '../store/feed-selectors';
import ModeOfTravelIcon from '@mui/icons-material/ModeOfTravel';
import { GtfsVisualizationMap } from './GtfsVisualizationMap';
import ZoomOutMapIcon from '@mui/icons-material/ZoomOutMap';

interface CoveredAreaMapProps {
boundingBox?: LatLngExpression[];
Expand All @@ -50,6 +55,11 @@
return await response.json();
};

type MapViews =
| 'boundingBoxView'
| 'detailedCoveredAreaView'
| 'gtfsVisualizationView';

const CoveredAreaMap: React.FC<CoveredAreaMapProps> = ({
boundingBox,
latestDataset,
Expand All @@ -63,9 +73,7 @@
>(null);
const [geoJsonError, setGeoJsonError] = useState(false);
const [geoJsonLoading, setGeoJsonLoading] = useState(false);
const [view, setView] = useState<
'boundingBoxView' | 'detailedCoveredAreaView'
>('detailedCoveredAreaView');
const [view, setView] = useState<MapViews>('detailedCoveredAreaView');
const latestGbfsVersion = useSelector(selectAutodiscoveryGbfsVersion);

const getAndSetGeoJsonData = (urlToExtract: string): void => {
Expand All @@ -74,7 +82,7 @@
.then((data) => {
setGeoJsonData(data);
setGeoJsonError(false);
setView('detailedCoveredAreaView');
setView('gtfsVisualizationView');
})
.catch(() => {
setGeoJsonError(true);
Expand Down Expand Up @@ -112,7 +120,7 @@

const handleViewChange = (
_: React.MouseEvent<HTMLElement>,
newView: 'boundingBoxView' | 'detailedCoveredAreaView' | null,
newView: MapViews | null,
): void => {
if (newView !== null) setView(newView);
};
Expand All @@ -132,29 +140,50 @@
const renderMap = (): JSX.Element => {
const displayBoundingBoxMap =
view === 'boundingBoxView' && feed?.data_type === 'gtfs';

const displayGtfsVisualizationView =
view === 'gtfsVisualizationView' && feed?.data_type === 'gtfs';
let gbfsBoundingBox: LatLngExpression[] = [];
if (feed?.data_type === 'gbfs') {
gbfsBoundingBox = computeBoundingBox(geoJsonData) ?? [];
if (gbfsBoundingBox.length === 0) {
setGeoJsonError(true);
}
}
return (
<>
{displayBoundingBoxMap ? (
<Map polygon={boundingBox ?? []} />
) : (
<MapGeoJSON
geoJSONData={geoJsonData}
polygon={boundingBox ?? gbfsBoundingBox}
displayMapDetails={feed?.data_type === 'gtfs'}

if (displayBoundingBoxMap) {
return <Map polygon={boundingBox ?? []} />;
}

if (displayGtfsVisualizationView) {
return (
<>
<Fab
size='small'
sx={{ position: 'absolute', top: 16, right: 16 }}
component={Link}
to='./map'
>
<ZoomOutMapIcon></ZoomOutMapIcon>
</Fab>
<GtfsVisualizationMap
polygon={boundingBox ?? []}
latestDataset={latestDataset}
/>
)}
</>
</>
);
}

return (
<MapGeoJSON
geoJSONData={geoJsonData}
polygon={boundingBox ?? gbfsBoundingBox}
displayMapDetails={feed?.data_type === 'gtfs'}
/>
);
};

const mapDisplayError = boundingBox == undefined && geoJsonError;

Check failure on line 186 in web-app/src/app/components/CoveredAreaMap.tsx

View workflow job for this annotation

GitHub Actions / deploy-web-app / Test

'mapDisplayError' is assigned a value but never used
const latestAutodiscoveryUrl = getGbfsLatestVersionVisualizationUrl(
feed as GBFSFeedType,
);
Expand All @@ -166,73 +195,91 @@
flexDirection: 'column',
maxHeight: {
xs: '100%',
md: '70vh',
md: '70vh', // TODO: optimize this
},
minHeight: '50vh',
}}
title={mapDisplayError ? '' : t('coveredAreaTitle') + ' - ' + t(view)}
title={''}
width={{ xs: '100%' }}
outlineColor={theme.palette.primary.dark}
padding={2}
action={
<>
{feed?.data_type === 'gbfs' ? (
<Box sx={{ textAlign: 'right' }}>
{latestAutodiscoveryUrl != undefined && (
<Button
href={latestAutodiscoveryUrl}
target='_blank'
rel='noreferrer'
endIcon={<OpenInNew />}
>
{t('viewRealtimeVisualization')}
</Button>
)}
{(geoJsonData as GeoJSONDataGBFS)?.extracted_at != undefined && (
<Typography
variant='caption'
color='text.secondary'
sx={{ display: 'block', px: 1 }}
>
{t('common:updated')}:{' '}
{displayFormattedDate(
(geoJsonData as GeoJSONDataGBFS).extracted_at,
)}
</Typography>
)}
</Box>
) : (
<ToggleButtonGroup
value={view}
color='primary'
exclusive
aria-label='map view selection'
onChange={handleViewChange}
>
<Tooltip title={t('detailedCoveredAreaViewTooltip')}>
<ToggleButton
value='detailedCoveredAreaView'
disabled={
geoJsonLoading || geoJsonError || boundingBox === undefined
}
aria-label='Detailed Covered Area View'
>
<TravelExploreIcon />
</ToggleButton>
</Tooltip>
<Tooltip title={t('boundingBoxViewTooltip')}>
<ToggleButton
value='boundingBoxView'
aria-label='Bounding Box View'
>
<MapIcon />
</ToggleButton>
</Tooltip>
</ToggleButtonGroup>
)}
</>
}
>
<Box
display={'flex'}
justifyContent={
view === 'gtfsVisualizationView' ? 'space-between' : 'flex-end'
}
mb={1}
alignItems={'center'}
>
{view === 'gtfsVisualizationView' && (
<Button component={Link} to='./map'>
Open Full Map with Filters
</Button>
)}
{feed?.data_type === 'gbfs' ? (
<Box sx={{ textAlign: 'right' }}>
{latestAutodiscoveryUrl != undefined && (
<Button
href={latestAutodiscoveryUrl}
target='_blank'
rel='noreferrer'
endIcon={<OpenInNew />}
>
{t('viewRealtimeVisualization')}
</Button>
)}
{(geoJsonData as GeoJSONDataGBFS)?.extracted_at != undefined && (
<Typography
variant='caption'
color='text.secondary'
sx={{ display: 'block', px: 1 }}
>
{t('common:updated')}:{' '}
{displayFormattedDate(
(geoJsonData as GeoJSONDataGBFS).extracted_at,
)}
</Typography>
)}
</Box>
) : (
<ToggleButtonGroup
value={view}
color='primary'
exclusive
aria-label='map view selection'
onChange={handleViewChange}
>
<Tooltip title={'gtfs visualization'}>
<ToggleButton
value='gtfsVisualizationView'
aria-label='Bounding Box View'
>
<ModeOfTravelIcon />
</ToggleButton>
</Tooltip>
<Tooltip title={t('detailedCoveredAreaViewTooltip')}>
<ToggleButton
value='detailedCoveredAreaView'
disabled={
geoJsonLoading || geoJsonError || boundingBox === undefined
}
aria-label='Detailed Covered Area View'
>
<TravelExploreIcon />
</ToggleButton>
</Tooltip>
<Tooltip title={t('boundingBoxViewTooltip')}>
<ToggleButton
value='boundingBoxView'
aria-label='Bounding Box View'
>
<MapIcon />
</ToggleButton>
</Tooltip>
</ToggleButtonGroup>
)}
</Box>
{feed?.data_type === 'gtfs' &&
boundingBox === undefined &&
view === 'boundingBoxView' && (
Expand Down
Loading
Loading