mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Move v2 maps to maplibre namespace
This commit is contained in:
parent
39307e1bb3
commit
3662d4f4b3
85 changed files with 376 additions and 360 deletions
|
|
@ -1,11 +1,12 @@
|
|||
class MapsV2Controller < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
layout 'map'
|
||||
module Maps
|
||||
class MaplibreController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
layout 'map'
|
||||
|
||||
def index
|
||||
@start_at = parsed_start_at
|
||||
@end_at = parsed_end_at
|
||||
end
|
||||
def index
|
||||
@start_at = parsed_start_at
|
||||
@end_at = parsed_end_at
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
|
@ -28,4 +29,5 @@ class MapsV2Controller < ApplicationController
|
|||
def parsed_end_at
|
||||
Time.zone.at(end_at)
|
||||
end
|
||||
end
|
||||
end
|
||||
5
app/controllers/maps_controller.rb
Normal file
5
app/controllers/maps_controller.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class MapsController < ApplicationController
|
||||
def index
|
||||
redirect_to maps_maplibre_path
|
||||
end
|
||||
end
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Dawarich JavaScript Architecture
|
||||
|
||||
This document provides a comprehensive guide to the JavaScript architecture used in the Dawarich application, with a focus on the Maps V2 implementation.
|
||||
This document provides a comprehensive guide to the JavaScript architecture used in the Dawarich application, with a focus on the Maps (MapLibre) implementation.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
|
@ -9,13 +9,13 @@ This document provides a comprehensive guide to the JavaScript architecture used
|
|||
- [Architecture Patterns](#architecture-patterns)
|
||||
- [Directory Structure](#directory-structure)
|
||||
- [Core Concepts](#core-concepts)
|
||||
- [Maps V2 Architecture](#maps-v2-architecture)
|
||||
- [Maps (MapLibre) Architecture](#maps-v2-architecture)
|
||||
- [Creating New Features](#creating-new-features)
|
||||
- [Best Practices](#best-practices)
|
||||
|
||||
## Overview
|
||||
|
||||
Dawarich uses a modern JavaScript architecture built on **Hotwire (Turbo + Stimulus)** for page interactions and **MapLibre GL JS** for map rendering. The Maps V2 implementation follows object-oriented principles with clear separation of concerns.
|
||||
Dawarich uses a modern JavaScript architecture built on **Hotwire (Turbo + Stimulus)** for page interactions and **MapLibre GL JS** for map rendering. The Maps (MapLibre) implementation follows object-oriented principles with clear separation of concerns.
|
||||
|
||||
## Technology Stack
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ export default class extends Controller {
|
|||
|
||||
**Purpose:** Encapsulate business logic and API communication
|
||||
|
||||
**Location:** `app/javascript/maps_v2/services/`
|
||||
**Location:** `app/javascript/maps_maplibre/services/`
|
||||
|
||||
**Pattern:**
|
||||
```javascript
|
||||
|
|
@ -89,7 +89,7 @@ export class ApiClient {
|
|||
|
||||
**Purpose:** Manage map visualization layers
|
||||
|
||||
**Location:** `app/javascript/maps_v2/layers/`
|
||||
**Location:** `app/javascript/maps_maplibre/layers/`
|
||||
|
||||
**Pattern:**
|
||||
```javascript
|
||||
|
|
@ -129,7 +129,7 @@ export class CustomLayer extends BaseLayer {
|
|||
|
||||
**Purpose:** Provide reusable helper functions
|
||||
|
||||
**Location:** `app/javascript/maps_v2/utils/`
|
||||
**Location:** `app/javascript/maps_maplibre/utils/`
|
||||
|
||||
**Pattern:**
|
||||
```javascript
|
||||
|
|
@ -147,7 +147,7 @@ export const utilityInstance = new UtilityClass()
|
|||
|
||||
**Purpose:** Reusable UI components
|
||||
|
||||
**Location:** `app/javascript/maps_v2/components/`
|
||||
**Location:** `app/javascript/maps_maplibre/components/`
|
||||
|
||||
**Pattern:**
|
||||
```javascript
|
||||
|
|
@ -164,15 +164,15 @@ export class PopupFactory {
|
|||
app/javascript/
|
||||
├── application.js # Entry point
|
||||
├── controllers/ # Stimulus controllers
|
||||
│ ├── maps_v2_controller.js # Main map controller
|
||||
│ ├── maps_v2/ # Controller modules
|
||||
│ ├── maps/maplibre_controller.js # Main map controller
|
||||
│ ├── maps_maplibre/ # Controller modules
|
||||
│ │ ├── layer_manager.js # Layer lifecycle management
|
||||
│ │ ├── data_loader.js # API data fetching
|
||||
│ │ ├── event_handlers.js # Map event handling
|
||||
│ │ ├── filter_manager.js # Data filtering
|
||||
│ │ └── date_manager.js # Date range management
|
||||
│ └── ... # Other controllers
|
||||
├── maps_v2/ # Maps V2 implementation
|
||||
├── maps_maplibre/ # Maps (MapLibre) implementation
|
||||
│ ├── layers/ # Map layer classes
|
||||
│ │ ├── base_layer.js # Abstract base class
|
||||
│ │ ├── points_layer.js # Point markers
|
||||
|
|
@ -206,7 +206,7 @@ app/javascript/
|
|||
|
||||
### Manager Pattern
|
||||
|
||||
The Maps V2 controller delegates responsibilities to specialized managers:
|
||||
The Maps (MapLibre) controller delegates responsibilities to specialized managers:
|
||||
|
||||
1. **LayerManager** - Layer lifecycle (add/remove/toggle/update)
|
||||
2. **DataLoader** - API data fetching and transformation
|
||||
|
|
@ -277,7 +277,7 @@ map.on('click', 'layer-id', (e) => {
|
|||
})
|
||||
```
|
||||
|
||||
## Maps V2 Architecture
|
||||
## Maps (MapLibre) Architecture
|
||||
|
||||
### Layer Hierarchy
|
||||
|
||||
|
|
@ -393,7 +393,7 @@ All data is transformed to GeoJSON before rendering:
|
|||
|
||||
### Adding a New Layer
|
||||
|
||||
1. **Create layer class** in `app/javascript/maps_v2/layers/`:
|
||||
1. **Create layer class** in `app/javascript/maps_maplibre/layers/`:
|
||||
|
||||
```javascript
|
||||
import { BaseLayer } from './base_layer'
|
||||
|
|
@ -422,10 +422,10 @@ export class NewLayer extends BaseLayer {
|
|||
}
|
||||
```
|
||||
|
||||
2. **Register in LayerManager** (`controllers/maps_v2/layer_manager.js`):
|
||||
2. **Register in LayerManager** (`controllers/maps_maplibre/layer_manager.js`):
|
||||
|
||||
```javascript
|
||||
import { NewLayer } from 'maps_v2/layers/new_layer'
|
||||
import { NewLayer } from 'maps_maplibre/layers/new_layer'
|
||||
|
||||
// In addAllLayers method
|
||||
_addNewLayer(dataGeoJSON) {
|
||||
|
|
@ -528,7 +528,7 @@ export const newManager = new NewManager()
|
|||
2. **Import and use:**
|
||||
|
||||
```javascript
|
||||
import { NewUtility } from 'maps_v2/utils/new_utility'
|
||||
import { NewUtility } from 'maps_maplibre/utils/new_utility'
|
||||
|
||||
const result = NewUtility.calculate(input)
|
||||
```
|
||||
|
|
@ -705,19 +705,19 @@ When updating features, follow this pattern:
|
|||
|
||||
### Complete Layer Implementation
|
||||
|
||||
See `app/javascript/maps_v2/layers/heatmap_layer.js` for a simple example.
|
||||
See `app/javascript/maps_maplibre/layers/heatmap_layer.js` for a simple example.
|
||||
|
||||
### Complete Utility Implementation
|
||||
|
||||
See `app/javascript/maps_v2/utils/settings_manager.js` for state management.
|
||||
See `app/javascript/maps_maplibre/utils/settings_manager.js` for state management.
|
||||
|
||||
### Complete Service Implementation
|
||||
|
||||
See `app/javascript/maps_v2/services/api_client.js` for API communication.
|
||||
See `app/javascript/maps_maplibre/services/api_client.js` for API communication.
|
||||
|
||||
### Complete Controller Implementation
|
||||
|
||||
See `app/javascript/controllers/maps_v2_controller.js` for orchestration.
|
||||
See `app/javascript/controllers/maps/maplibre_controller.js` for orchestration.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Controller } from '@hotwired/stimulus'
|
||||
import { createCircle, calculateDistance } from 'maps_v2/utils/geometry'
|
||||
import { createCircle, calculateDistance } from 'maps_maplibre/utils/geometry'
|
||||
|
||||
/**
|
||||
* Area drawer controller
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Controller } from '@hotwired/stimulus'
|
||||
import { createRectangle } from 'maps_v2/utils/geometry'
|
||||
import { createRectangle } from 'maps_maplibre/utils/geometry'
|
||||
|
||||
/**
|
||||
* Area selector controller
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { SelectionLayer } from 'maps_v2/layers/selection_layer'
|
||||
import { SelectedPointsLayer } from 'maps_v2/layers/selected_points_layer'
|
||||
import { pointsToGeoJSON } from 'maps_v2/utils/geojson_transformers'
|
||||
import { VisitCard } from 'maps_v2/components/visit_card'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { SelectionLayer } from 'maps_maplibre/layers/selection_layer'
|
||||
import { SelectedPointsLayer } from 'maps_maplibre/layers/selected_points_layer'
|
||||
import { pointsToGeoJSON } from 'maps_maplibre/utils/geojson_transformers'
|
||||
import { VisitCard } from 'maps_maplibre/components/visit_card'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
|
||||
/**
|
||||
* Manages area selection and bulk operations for Maps V2
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { pointsToGeoJSON } from 'maps_v2/utils/geojson_transformers'
|
||||
import { RoutesLayer } from 'maps_v2/layers/routes_layer'
|
||||
import { createCircle } from 'maps_v2/utils/geometry'
|
||||
import { performanceMonitor } from 'maps_v2/utils/performance_monitor'
|
||||
import { pointsToGeoJSON } from 'maps_maplibre/utils/geojson_transformers'
|
||||
import { RoutesLayer } from 'maps_maplibre/layers/routes_layer'
|
||||
import { createCircle } from 'maps_maplibre/utils/geometry'
|
||||
import { performanceMonitor } from 'maps_maplibre/utils/performance_monitor'
|
||||
|
||||
/**
|
||||
* Handles loading and transforming data from API
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import maplibregl from 'maplibre-gl'
|
||||
import { PopupFactory } from 'maps_v2/components/popup_factory'
|
||||
import { VisitPopupFactory } from 'maps_v2/components/visit_popup'
|
||||
import { PhotoPopupFactory } from 'maps_v2/components/photo_popup'
|
||||
import { PopupFactory } from 'maps_maplibre/components/popup_factory'
|
||||
import { VisitPopupFactory } from 'maps_maplibre/components/visit_popup'
|
||||
import { PhotoPopupFactory } from 'maps_maplibre/components/photo_popup'
|
||||
|
||||
/**
|
||||
* Handles map interaction events (clicks, popups)
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
import { PointsLayer } from 'maps_v2/layers/points_layer'
|
||||
import { RoutesLayer } from 'maps_v2/layers/routes_layer'
|
||||
import { HeatmapLayer } from 'maps_v2/layers/heatmap_layer'
|
||||
import { VisitsLayer } from 'maps_v2/layers/visits_layer'
|
||||
import { PhotosLayer } from 'maps_v2/layers/photos_layer'
|
||||
import { AreasLayer } from 'maps_v2/layers/areas_layer'
|
||||
import { TracksLayer } from 'maps_v2/layers/tracks_layer'
|
||||
import { PlacesLayer } from 'maps_v2/layers/places_layer'
|
||||
import { FogLayer } from 'maps_v2/layers/fog_layer'
|
||||
import { FamilyLayer } from 'maps_v2/layers/family_layer'
|
||||
import { lazyLoader } from 'maps_v2/utils/lazy_loader'
|
||||
import { performanceMonitor } from 'maps_v2/utils/performance_monitor'
|
||||
import { PointsLayer } from 'maps_maplibre/layers/points_layer'
|
||||
import { RoutesLayer } from 'maps_maplibre/layers/routes_layer'
|
||||
import { HeatmapLayer } from 'maps_maplibre/layers/heatmap_layer'
|
||||
import { VisitsLayer } from 'maps_maplibre/layers/visits_layer'
|
||||
import { PhotosLayer } from 'maps_maplibre/layers/photos_layer'
|
||||
import { AreasLayer } from 'maps_maplibre/layers/areas_layer'
|
||||
import { TracksLayer } from 'maps_maplibre/layers/tracks_layer'
|
||||
import { PlacesLayer } from 'maps_maplibre/layers/places_layer'
|
||||
import { FogLayer } from 'maps_maplibre/layers/fog_layer'
|
||||
import { FamilyLayer } from 'maps_maplibre/layers/family_layer'
|
||||
import { lazyLoader } from 'maps_maplibre/utils/lazy_loader'
|
||||
import { performanceMonitor } from 'maps_maplibre/utils/performance_monitor'
|
||||
|
||||
/**
|
||||
* Manages all map layers lifecycle and visibility
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import maplibregl from 'maplibre-gl'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { performanceMonitor } from 'maps_v2/utils/performance_monitor'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
import { performanceMonitor } from 'maps_maplibre/utils/performance_monitor'
|
||||
|
||||
/**
|
||||
* Manages data loading and layer setup for the map
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import maplibregl from 'maplibre-gl'
|
||||
import { getMapStyle } from 'maps_v2/utils/style_manager'
|
||||
import { getMapStyle } from 'maps_maplibre/utils/style_manager'
|
||||
|
||||
/**
|
||||
* Handles map initialization for Maps V2
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { SettingsManager } from 'maps_v2/utils/settings_manager'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { SettingsManager } from 'maps_maplibre/utils/settings_manager'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
|
||||
/**
|
||||
* Manages places-related operations for Maps V2
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { SettingsManager } from 'maps_v2/utils/settings_manager'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { lazyLoader } from 'maps_v2/utils/lazy_loader'
|
||||
import { SettingsManager } from 'maps_maplibre/utils/settings_manager'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
import { lazyLoader } from 'maps_maplibre/utils/lazy_loader'
|
||||
|
||||
/**
|
||||
* Manages routes-related operations for Maps V2
|
||||
|
|
@ -176,7 +176,7 @@ export class RoutesManager {
|
|||
const distanceThresholdMeters = this.settings.metersBetweenRoutes || 500
|
||||
const timeThresholdMinutes = this.settings.minutesBetweenRoutes || 60
|
||||
|
||||
const { calculateSpeed, getSpeedColor } = await import('maps_v2/utils/speed_colors')
|
||||
const { calculateSpeed, getSpeedColor } = await import('maps_maplibre/utils/speed_colors')
|
||||
|
||||
const routesGeoJSON = await this.generateRoutesWithSpeedColors(
|
||||
points,
|
||||
|
|
@ -199,7 +199,7 @@ export class RoutesManager {
|
|||
* Generate routes with speed coloring
|
||||
*/
|
||||
async generateRoutesWithSpeedColors(points, options, calculateSpeed, getSpeedColor) {
|
||||
const { RoutesLayer } = await import('maps_v2/layers/routes_layer')
|
||||
const { RoutesLayer } = await import('maps_maplibre/layers/routes_layer')
|
||||
const useSpeedColors = this.settings.speedColoredRoutesEnabled || false
|
||||
const speedColorScale = this.settings.speedColorScale || '0:#00ff00|15:#00ffff|30:#ff00ff|50:#ffff00|100:#ff3300'
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { SettingsManager } from 'maps_v2/utils/settings_manager'
|
||||
import { getMapStyle } from 'maps_v2/utils/style_manager'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { SettingsManager } from 'maps_maplibre/utils/settings_manager'
|
||||
import { getMapStyle } from 'maps_maplibre/utils/style_manager'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
|
||||
/**
|
||||
* Handles all settings-related operations for Maps V2
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { SettingsManager } from 'maps_v2/utils/settings_manager'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { SettingsManager } from 'maps_maplibre/utils/settings_manager'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
|
||||
/**
|
||||
* Manages visits-related operations for Maps V2
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
import { Controller } from '@hotwired/stimulus'
|
||||
import { ApiClient } from 'maps_v2/services/api_client'
|
||||
import { SettingsManager } from 'maps_v2/utils/settings_manager'
|
||||
import { SearchManager } from 'maps_v2/utils/search_manager'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { performanceMonitor } from 'maps_v2/utils/performance_monitor'
|
||||
import { CleanupHelper } from 'maps_v2/utils/cleanup_helper'
|
||||
import { MapInitializer } from './maps_v2/map_initializer'
|
||||
import { MapDataManager } from './maps_v2/map_data_manager'
|
||||
import { LayerManager } from './maps_v2/layer_manager'
|
||||
import { DataLoader } from './maps_v2/data_loader'
|
||||
import { EventHandlers } from './maps_v2/event_handlers'
|
||||
import { FilterManager } from './maps_v2/filter_manager'
|
||||
import { DateManager } from './maps_v2/date_manager'
|
||||
import { SettingsController } from './maps_v2/settings_manager'
|
||||
import { AreaSelectionManager } from './maps_v2/area_selection_manager'
|
||||
import { VisitsManager } from './maps_v2/visits_manager'
|
||||
import { PlacesManager } from './maps_v2/places_manager'
|
||||
import { RoutesManager } from './maps_v2/routes_manager'
|
||||
import { ApiClient } from 'maps_maplibre/services/api_client'
|
||||
import { SettingsManager } from 'maps_maplibre/utils/settings_manager'
|
||||
import { SearchManager } from 'maps_maplibre/utils/search_manager'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
import { performanceMonitor } from 'maps_maplibre/utils/performance_monitor'
|
||||
import { CleanupHelper } from 'maps_maplibre/utils/cleanup_helper'
|
||||
import { MapInitializer } from './maplibre/map_initializer'
|
||||
import { MapDataManager } from './maplibre/map_data_manager'
|
||||
import { LayerManager } from './maplibre/layer_manager'
|
||||
import { DataLoader } from './maplibre/data_loader'
|
||||
import { EventHandlers } from './maplibre/event_handlers'
|
||||
import { FilterManager } from './maplibre/filter_manager'
|
||||
import { DateManager } from './maplibre/date_manager'
|
||||
import { SettingsController } from './maplibre/settings_manager'
|
||||
import { AreaSelectionManager } from './maplibre/area_selection_manager'
|
||||
import { VisitsManager } from './maplibre/visits_manager'
|
||||
import { PlacesManager } from './maplibre/places_manager'
|
||||
import { RoutesManager } from './maplibre/routes_manager'
|
||||
|
||||
/**
|
||||
* Main map controller for Maps V2
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Controller } from '@hotwired/stimulus'
|
||||
import { createMapChannel } from 'maps_v2/channels/map_channel'
|
||||
import { WebSocketManager } from 'maps_v2/utils/websocket_manager'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { createMapChannel } from 'maps_maplibre/channels/map_channel'
|
||||
import { WebSocketManager } from 'maps_maplibre/utils/websocket_manager'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
|
||||
/**
|
||||
* Real-time controller
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { Controller } from '@hotwired/stimulus'
|
||||
import { Toast } from 'maps_v2/components/toast'
|
||||
import { Toast } from 'maps_maplibre/components/toast'
|
||||
|
||||
/**
|
||||
* Controller for visit creation modal in Maps V2
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import consumer from '../../channels/consumer'
|
||||
|
||||
/**
|
||||
* Create map channel subscription for maps_v2
|
||||
* Create map channel subscription for maps_maplibre
|
||||
* Wraps the existing FamilyLocationsChannel and other channels for real-time updates
|
||||
* @param {Object} options - { received, connected, disconnected, enableLiveMode }
|
||||
* @returns {Object} Subscriptions object with multiple channels
|
||||
|
|
@ -33,7 +33,7 @@ const LAYER_NAME_MAP = {
|
|||
|
||||
// Mapping between frontend settings and backend API keys
|
||||
const BACKEND_SETTINGS_MAP = {
|
||||
mapStyle: 'maps_v2_style',
|
||||
mapStyle: 'maps_maplibre_style',
|
||||
enabledMapLayers: 'enabled_map_layers'
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ async function loadStyleFile(styleName) {
|
|||
}
|
||||
|
||||
// Fetch the style file from the public assets
|
||||
const response = await fetch(`/maps_v2/styles/${styleName}.json`)
|
||||
const response = await fetch(`/maps_maplibre/styles/${styleName}.json`)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load style: ${styleName} (${response.status})`)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="map-control-panel" data-maps-v2-target="settingsPanel" data-controller="map-panel">
|
||||
<div class="map-control-panel" data-maps--maplibre-target="settingsPanel" data-controller="map-panel">
|
||||
<!-- Vertical Icon Tabs (Left Side) -->
|
||||
<div class="panel-tabs">
|
||||
<button class="tab-btn active"
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
<div class="panel-header">
|
||||
<h3 class="panel-title" data-map-panel-target="title">Layers</h3>
|
||||
<button class="btn btn-ghost btn-sm btn-circle"
|
||||
data-action="click->maps-v2#toggleSettings"
|
||||
data-action="click->maps--maplibre#toggleSettings"
|
||||
title="Close panel">
|
||||
<%= icon 'search' %>
|
||||
</button>
|
||||
|
|
@ -69,11 +69,11 @@
|
|||
<input type="text"
|
||||
placeholder="Enter name of a place"
|
||||
class="input input-bordered w-full"
|
||||
data-maps-v2-target="searchInput"
|
||||
data-maps--maplibre-target="searchInput"
|
||||
autocomplete="off" />
|
||||
<!-- Search Results -->
|
||||
<div class="absolute z-50 w-full mt-1 bg-base-100 rounded-lg shadow-lg border border-base-300 hidden max-h-full overflow-y-auto"
|
||||
data-maps-v2-target="searchResults">
|
||||
data-maps--maplibre-target="searchResults">
|
||||
<!-- Results will be populated by SearchManager -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -91,8 +91,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="pointsToggle"
|
||||
data-action="change->maps-v2#togglePoints" />
|
||||
data-maps--maplibre-target="pointsToggle"
|
||||
data-action="change->maps--maplibre#togglePoints" />
|
||||
<span class="label-text font-medium">Points</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show individual location points</p>
|
||||
|
|
@ -105,36 +105,36 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="routesToggle"
|
||||
data-action="change->maps-v2#toggleRoutes" />
|
||||
data-maps--maplibre-target="routesToggle"
|
||||
data-action="change->maps--maplibre#toggleRoutes" />
|
||||
<span class="label-text font-medium">Routes</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show connected route lines</p>
|
||||
</div>
|
||||
|
||||
<!-- Speed-Colored Routes Options (conditionally shown) -->
|
||||
<div class="ml-14 space-y-3" data-maps-v2-target="routesOptions" style="display: none;">
|
||||
<div class="ml-14 space-y-3" data-maps--maplibre-target="routesOptions" style="display: none;">
|
||||
<div class="form-control">
|
||||
<label class="label cursor-pointer py-2">
|
||||
<span class="label-text text-sm">Color by speed</span>
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
data-maps-v2-target="speedColoredToggle"
|
||||
data-action="change->maps-v2#toggleSpeedColoredRoutes" />
|
||||
data-maps--maplibre-target="speedColoredToggle"
|
||||
data-action="change->maps--maplibre#toggleSpeedColoredRoutes" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Speed Color Scale Editor (shown when speed colors enabled) -->
|
||||
<div class="hidden" data-maps-v2-target="speedColorScaleContainer">
|
||||
<div class="hidden" data-maps--maplibre-target="speedColorScaleContainer">
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline w-full"
|
||||
data-action="click->maps-v2#openSpeedColorEditor">
|
||||
data-action="click->maps--maplibre#openSpeedColorEditor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" />
|
||||
</svg>
|
||||
Edit Color Gradient
|
||||
</button>
|
||||
<input type="hidden" data-maps-v2-target="speedColorScaleInput" value="" />
|
||||
<input type="hidden" data-maps--maplibre-target="speedColorScaleInput" value="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -145,8 +145,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="heatmapToggle"
|
||||
data-action="change->maps-v2#toggleHeatmap" />
|
||||
data-maps--maplibre-target="heatmapToggle"
|
||||
data-action="change->maps--maplibre#toggleHeatmap" />
|
||||
<span class="label-text font-medium">Heatmap</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show density heatmap</p>
|
||||
|
|
@ -159,23 +159,23 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="visitsToggle"
|
||||
data-action="change->maps-v2#toggleVisits" />
|
||||
data-maps--maplibre-target="visitsToggle"
|
||||
data-action="change->maps--maplibre#toggleVisits" />
|
||||
<span class="label-text font-medium">Visits</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show detected area visits</p>
|
||||
</div>
|
||||
|
||||
<!-- Visits Search (conditionally shown) -->
|
||||
<div class="ml-14 space-y-2" data-maps-v2-target="visitsSearch" style="display: none;">
|
||||
<div class="ml-14 space-y-2" data-maps--maplibre-target="visitsSearch" style="display: none;">
|
||||
<input type="text"
|
||||
id="visits-search"
|
||||
placeholder="Filter by name..."
|
||||
class="input input-sm input-bordered w-full"
|
||||
data-action="input->maps-v2#searchVisits" />
|
||||
data-action="input->maps--maplibre#searchVisits" />
|
||||
|
||||
<select class="select select-bordered w-full"
|
||||
data-action="change->maps-v2#filterVisits">
|
||||
data-action="change->maps--maplibre#filterVisits">
|
||||
<option value="all">All Visits</option>
|
||||
<option value="confirmed">Confirmed Only</option>
|
||||
<option value="suggested">Suggested Only</option>
|
||||
|
|
@ -189,21 +189,21 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="placesToggle"
|
||||
data-action="change->maps-v2#togglePlaces" />
|
||||
data-maps--maplibre-target="placesToggle"
|
||||
data-action="change->maps--maplibre#togglePlaces" />
|
||||
<span class="label-text font-medium">Places</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show your saved places</p>
|
||||
</div>
|
||||
|
||||
<!-- Places Tags (conditionally shown) -->
|
||||
<div class="ml-14 space-y-2" data-maps-v2-target="placesFilters" style="display: none;">
|
||||
<div class="ml-14 space-y-2" data-maps--maplibre-target="placesFilters" style="display: none;">
|
||||
<div class="form-control">
|
||||
<label class="label cursor-pointer justify-start gap-2">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-sm"
|
||||
data-maps-v2-target="enableAllPlaceTagsToggle"
|
||||
data-action="change->maps-v2#toggleAllPlaceTags">
|
||||
data-maps--maplibre-target="enableAllPlaceTagsToggle"
|
||||
data-action="change->maps--maplibre#toggleAllPlaceTags">
|
||||
<span class="label-text text-sm">Enable All Tags</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -218,7 +218,7 @@
|
|||
name="place_tag_ids[]"
|
||||
value="untagged"
|
||||
class="checkbox checkbox-xs hidden peer"
|
||||
data-action="change->maps-v2#filterPlacesByTags">
|
||||
data-action="change->maps--maplibre#filterPlacesByTags">
|
||||
<span class="badge badge-sm badge-outline transition-all peer-checked:scale-105"
|
||||
style="border-color: #94a3b8; color: #94a3b8;"
|
||||
data-checked-style="background-color: #94a3b8; color: white;">
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
name="place_tag_ids[]"
|
||||
value="<%= tag.id %>"
|
||||
class="checkbox checkbox-xs hidden peer"
|
||||
data-action="change->maps-v2#filterPlacesByTags">
|
||||
data-action="change->maps--maplibre#filterPlacesByTags">
|
||||
<span class="badge badge-sm badge-outline transition-all peer-checked:scale-105"
|
||||
style="border-color: <%= tag.color %>; color: <%= tag.color %>;"
|
||||
data-checked-style="background-color: <%= tag.color %>; color: white;">
|
||||
|
|
@ -254,8 +254,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="photosToggle"
|
||||
data-action="change->maps-v2#togglePhotos" />
|
||||
data-maps--maplibre-target="photosToggle"
|
||||
data-action="change->maps--maplibre#togglePhotos" />
|
||||
<span class="label-text font-medium">Photos</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show geotagged photos</p>
|
||||
|
|
@ -268,8 +268,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="areasToggle"
|
||||
data-action="change->maps-v2#toggleAreas" />
|
||||
data-maps--maplibre-target="areasToggle"
|
||||
data-action="change->maps--maplibre#toggleAreas" />
|
||||
<span class="label-text font-medium">Areas</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show defined areas</p>
|
||||
|
|
@ -282,8 +282,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="tracksToggle"
|
||||
data-action="change->maps-v2#toggleTracks" />
|
||||
data-maps--maplibre-target="tracksToggle"
|
||||
data-action="change->maps--maplibre#toggleTracks" />
|
||||
<span class="label-text font-medium">Tracks</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show saved tracks</p>
|
||||
|
|
@ -296,8 +296,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="fogToggle"
|
||||
data-action="change->maps-v2#toggleFog" />
|
||||
data-maps--maplibre-target="fogToggle"
|
||||
data-action="change->maps--maplibre#toggleFog" />
|
||||
<span class="label-text font-medium">Fog of War</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show explored areas</p>
|
||||
|
|
@ -310,8 +310,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-maps-v2-target="scratchToggle"
|
||||
data-action="change->maps-v2#toggleScratch" />
|
||||
data-maps--maplibre-target="scratchToggle"
|
||||
data-action="change->maps--maplibre#toggleScratch" />
|
||||
<span class="label-text font-medium">Scratch Map</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 ml-14">Show scratched countries</p>
|
||||
|
|
@ -322,7 +322,7 @@
|
|||
|
||||
<!-- Settings Tab -->
|
||||
<div class="tab-content" data-tab-content="settings" data-map-panel-target="tabContent">
|
||||
<form data-action="submit->maps-v2#updateAdvancedSettings" class="space-y-4">
|
||||
<form data-action="submit->maps--maplibre#updateAdvancedSettings" class="space-y-4">
|
||||
<!-- Map Style -->
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
|
|
@ -330,7 +330,7 @@
|
|||
</label>
|
||||
<select class="select select-bordered w-full"
|
||||
name="mapStyle"
|
||||
data-action="change->maps-v2#updateMapStyle">
|
||||
data-action="change->maps--maplibre#updateMapStyle">
|
||||
<option value="light" selected>Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="white">White</option>
|
||||
|
|
@ -354,8 +354,8 @@
|
|||
step="10"
|
||||
value="100"
|
||||
class="range range-sm"
|
||||
data-maps-v2-target="routeOpacityRange"
|
||||
data-action="input->maps-v2#updateRouteOpacity" />
|
||||
data-maps--maplibre-target="routeOpacityRange"
|
||||
data-action="input->maps--maplibre#updateRouteOpacity" />
|
||||
<div class="w-full flex justify-between text-xs px-2 mt-1">
|
||||
<span>10%</span>
|
||||
<span>50%</span>
|
||||
|
|
@ -369,7 +369,7 @@
|
|||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Fog of War Radius</span>
|
||||
<span class="label-text-alt" data-maps-v2-target="fogRadiusValue">1000m</span>
|
||||
<span class="label-text-alt" data-maps--maplibre-target="fogRadiusValue">1000m</span>
|
||||
</label>
|
||||
<input type="range"
|
||||
name="fogOfWarRadius"
|
||||
|
|
@ -378,7 +378,7 @@
|
|||
step="5"
|
||||
value="1000"
|
||||
class="range range-sm"
|
||||
data-action="input->maps-v2#updateFogRadiusDisplay" />
|
||||
data-action="input->maps--maplibre#updateFogRadiusDisplay" />
|
||||
<div class="w-full flex justify-between text-xs px-2 mt-1">
|
||||
<span>5m</span>
|
||||
<span>1000m</span>
|
||||
|
|
@ -390,7 +390,7 @@
|
|||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Fog of War Threshold</span>
|
||||
<span class="label-text-alt" data-maps-v2-target="fogThresholdValue">1</span>
|
||||
<span class="label-text-alt" data-maps--maplibre-target="fogThresholdValue">1</span>
|
||||
</label>
|
||||
<input type="range"
|
||||
name="fogOfWarThreshold"
|
||||
|
|
@ -399,7 +399,7 @@
|
|||
step="1"
|
||||
value="1"
|
||||
class="range range-sm"
|
||||
data-action="input->maps-v2#updateFogThresholdDisplay" />
|
||||
data-action="input->maps--maplibre#updateFogThresholdDisplay" />
|
||||
<div class="w-full flex justify-between text-xs px-2 mt-1">
|
||||
<span>1</span>
|
||||
<span>5</span>
|
||||
|
|
@ -414,7 +414,7 @@
|
|||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Meters Between Routes</span>
|
||||
<span class="label-text-alt" data-maps-v2-target="metersBetweenValue">500m</span>
|
||||
<span class="label-text-alt" data-maps--maplibre-target="metersBetweenValue">500m</span>
|
||||
</label>
|
||||
<input type="range"
|
||||
name="metersBetweenRoutes"
|
||||
|
|
@ -423,7 +423,7 @@
|
|||
step="100"
|
||||
value="500"
|
||||
class="range range-sm"
|
||||
data-action="input->maps-v2#updateMetersBetweenDisplay" />
|
||||
data-action="input->maps--maplibre#updateMetersBetweenDisplay" />
|
||||
<div class="w-full flex justify-between text-xs px-2 mt-1">
|
||||
<span>100m</span>
|
||||
<span>2500m</span>
|
||||
|
|
@ -435,7 +435,7 @@
|
|||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">Minutes Between Routes</span>
|
||||
<span class="label-text-alt" data-maps-v2-target="minutesBetweenValue">60min</span>
|
||||
<span class="label-text-alt" data-maps--maplibre-target="minutesBetweenValue">60min</span>
|
||||
</label>
|
||||
<input type="range"
|
||||
name="minutesBetweenRoutes"
|
||||
|
|
@ -444,7 +444,7 @@
|
|||
step="1"
|
||||
value="60"
|
||||
class="range range-sm"
|
||||
data-action="input->maps-v2#updateMinutesBetweenDisplay" />
|
||||
data-action="input->maps--maplibre#updateMinutesBetweenDisplay" />
|
||||
<div class="w-full flex justify-between text-xs px-2 mt-1">
|
||||
<span>1min</span>
|
||||
<span>90min</span>
|
||||
|
|
@ -499,8 +499,8 @@
|
|||
<label class="label cursor-pointer justify-start gap-3">
|
||||
<input type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
data-action="change->maps-v2-realtime#toggleLiveMode"
|
||||
data-maps-v2-realtime-target="liveModeToggle" />
|
||||
data-action="change->maps--maplibre-realtime#toggleLiveMode"
|
||||
data-maps--maplibre-realtime-target="liveModeToggle" />
|
||||
<span class="label-text font-medium">Live Mode</span>
|
||||
</label>
|
||||
<p class="text-sm text-base-content/60 mt-1">Show new points in real-time</p>
|
||||
|
|
@ -517,7 +517,7 @@
|
|||
<!-- Reset Settings -->
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline btn-block"
|
||||
data-action="click->maps-v2#resetSettings">
|
||||
data-action="click->maps--maplibre#resetSettings">
|
||||
<%= icon 'rotate-ccw' %>
|
||||
Reset to Defaults
|
||||
</button>
|
||||
|
|
@ -532,7 +532,7 @@
|
|||
<!-- Create a Visit Button -->
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline"
|
||||
data-action="click->maps-v2#startCreateVisit">
|
||||
data-action="click->maps--maplibre#startCreateVisit">
|
||||
<%= icon 'map-pin-check' %>
|
||||
Create a Visit
|
||||
</button>
|
||||
|
|
@ -540,7 +540,7 @@
|
|||
<!-- Create a Place Button -->
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline"
|
||||
data-action="click->maps-v2#startCreatePlace">
|
||||
data-action="click->maps--maplibre#startCreatePlace">
|
||||
<%= icon 'map-pin-plus' %>
|
||||
Create a Place
|
||||
</button>
|
||||
|
|
@ -548,8 +548,8 @@
|
|||
<!-- Select Area Button -->
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline"
|
||||
data-maps-v2-target="selectAreaButton"
|
||||
data-action="click->maps-v2#startSelectArea">
|
||||
data-maps--maplibre-target="selectAreaButton"
|
||||
data-action="click->maps--maplibre#startSelectArea">
|
||||
<%= icon 'square-dashed-mouse-pointer' %>
|
||||
Select Area
|
||||
</button>
|
||||
|
|
@ -557,29 +557,29 @@
|
|||
<!-- Create Area Button -->
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline"
|
||||
data-action="click->maps-v2#startCreateArea">
|
||||
data-action="click->maps--maplibre#startCreateArea">
|
||||
<%= icon 'circle-plus' %>
|
||||
Create an Area
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Selection Actions (shown after area is selected) -->
|
||||
<div class="hidden mt-4 space-y-2" data-maps-v2-target="selectionActions">
|
||||
<div class="hidden mt-4 space-y-2" data-maps--maplibre-target="selectionActions">
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline btn-error btn-block"
|
||||
data-action="click->maps-v2#deleteSelectedPoints"
|
||||
data-maps-v2-target="deletePointsButton">
|
||||
data-action="click->maps--maplibre#deleteSelectedPoints"
|
||||
data-maps--maplibre-target="deletePointsButton">
|
||||
<%= icon 'trash-2' %>
|
||||
<span data-maps-v2-target="deleteButtonText">Delete Selected Points</span>
|
||||
<span data-maps--maplibre-target="deleteButtonText">Delete Selected Points</span>
|
||||
</button>
|
||||
|
||||
<!-- Selected Visits Container -->
|
||||
<div class="hidden mt-4 max-h-full overflow-y-auto" data-maps-v2-target="selectedVisitsContainer">
|
||||
<div class="hidden mt-4 max-h-full overflow-y-auto" data-maps--maplibre-target="selectedVisitsContainer">
|
||||
<!-- Visit cards will be dynamically inserted here -->
|
||||
</div>
|
||||
|
||||
<!-- Bulk Actions for Visits -->
|
||||
<div class="hidden" data-maps-v2-target="selectedVisitsBulkActions">
|
||||
<div class="hidden" data-maps--maplibre-target="selectedVisitsBulkActions">
|
||||
<!-- Bulk action buttons will be dynamically inserted here -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
<%= render 'shared/map/date_navigation_v2', start_at: @start_at, end_at: @end_at %>
|
||||
|
||||
<div id="maps-v2-container"
|
||||
data-controller="maps-v2 area-drawer maps-v2-realtime"
|
||||
data-maps-v2-api-key-value="<%= current_user.api_key %>"
|
||||
data-maps-v2-start-date-value="<%= @start_at.to_s %>"
|
||||
data-maps-v2-end-date-value="<%= @end_at.to_s %>"
|
||||
data-maps-v2-realtime-enabled-value="true"
|
||||
<div id="maps-maplibre-container"
|
||||
data-controller="maps--maplibre area-drawer maps--maplibre-realtime"
|
||||
data-maps--maplibre-api-key-value="<%= current_user.api_key %>"
|
||||
data-maps--maplibre-start-date-value="<%= @start_at.to_s %>"
|
||||
data-maps--maplibre-end-date-value="<%= @end_at.to_s %>"
|
||||
data-maps--maplibre-realtime-enabled-value="true"
|
||||
style="width: 100%; height: 100%; position: relative;">
|
||||
|
||||
<!-- Map container takes full width and height -->
|
||||
<div data-maps-v2-target="container" class="maps-v2-container" style="width: 100%; height: 100%;"></div>
|
||||
<div data-maps--maplibre-target="container" class="maps-maplibre-container" style="width: 100%; height: 100%;"></div>
|
||||
|
||||
<!-- Connection indicator -->
|
||||
<div class="connection-indicator disconnected">
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
<!-- Settings button (top-left corner) -->
|
||||
<div class="absolute top-4 left-4 z-10">
|
||||
<button data-action="click->maps-v2#toggleSettings"
|
||||
<button data-action="click->maps--maplibre#toggleSettings"
|
||||
class="btn btn-sm btn-primary"
|
||||
title="Open map settings">
|
||||
<%= icon 'square-pen' %>
|
||||
|
|
@ -30,19 +30,19 @@
|
|||
</div>
|
||||
|
||||
<!-- Loading overlay -->
|
||||
<div data-maps-v2-target="loading" class="loading-overlay hidden">
|
||||
<div data-maps--maplibre-target="loading" class="loading-overlay hidden">
|
||||
<div class="loading-spinner"></div>
|
||||
<div class="loading-text" data-maps-v2-target="loadingText">Loading points...</div>
|
||||
<div class="loading-text" data-maps--maplibre-target="loadingText">Loading points...</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings panel -->
|
||||
<%= render 'maps_v2/settings_panel' %>
|
||||
<%= render 'maps/maplibre/settings_panel' %>
|
||||
|
||||
<!-- Visit creation modal -->
|
||||
<%= render 'maps_v2/visit_creation_modal' %>
|
||||
<%= render 'maps/maplibre/visit_creation_modal' %>
|
||||
|
||||
<!-- Area creation modal -->
|
||||
<%= render 'maps_v2/area_creation_modal' %>
|
||||
<%= render 'maps/maplibre/area_creation_modal' %>
|
||||
|
||||
<!-- Place creation modal (shared) -->
|
||||
<%= render 'shared/place_creation_modal' %>
|
||||
|
|
@ -17,12 +17,12 @@
|
|||
<div
|
||||
data-map-controls-target="panel"
|
||||
class="hidden lg:!block bg-base-100 rounded-lg shadow-lg p-4 mt-2 lg:mt-0">
|
||||
<%= form_with url: maps_v2_path(import_id: params[:import_id]), method: :get do |f| %>
|
||||
<%= form_with url: maps_maplibre_path(import_id: params[:import_id]), method: :get do |f| %>
|
||||
<div class="flex flex-col space-y-4 lg:flex-row lg:space-y-0 lg:space-x-4 lg:items-end">
|
||||
<div class="w-full lg:w-1/12">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<span class="tooltip" data-tip="<%= human_date(start_at - 1.day) %>">
|
||||
<%= link_to maps_v2_path(start_at: start_at - 1.day, end_at: end_at - 1.day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" do %>
|
||||
<%= link_to maps_maplibre_path(start_at: start_at - 1.day, end_at: end_at - 1.day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" do %>
|
||||
<%= icon 'chevron-left' %>
|
||||
<% end %>
|
||||
</span>
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<div class="w-full lg:w-1/12">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<span class="tooltip" data-tip="<%= human_date(start_at + 1.day) %>">
|
||||
<%= link_to maps_v2_path(start_at: start_at + 1.day, end_at: end_at + 1.day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" do %>
|
||||
<%= link_to maps_maplibre_path(start_at: start_at + 1.day, end_at: end_at + 1.day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" do %>
|
||||
<%= icon 'chevron-right' %>
|
||||
<% end %>
|
||||
</span>
|
||||
|
|
@ -51,18 +51,18 @@
|
|||
<div class="w-full lg:w-1/12">
|
||||
<div class="flex flex-col space-y-2 text-center">
|
||||
<%= link_to "Today",
|
||||
maps_v2_path(start_at: Time.current.beginning_of_day, end_at: Time.current.end_of_day, import_id: params[:import_id]),
|
||||
maps_maplibre_path(start_at: Time.current.beginning_of_day, end_at: Time.current.end_of_day, import_id: params[:import_id]),
|
||||
class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full lg:w-2/12">
|
||||
<div class="flex flex-col space-y-2 text-center">
|
||||
<%= link_to "Last 7 days", maps_v2_path(start_at: 1.week.ago.beginning_of_day, end_at: Time.current.end_of_day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" %>
|
||||
<%= link_to "Last 7 days", maps_maplibre_path(start_at: 1.week.ago.beginning_of_day, end_at: Time.current.end_of_day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full lg:w-2/12">
|
||||
<div class="flex flex-col space-y-2 text-center">
|
||||
<%= link_to "Last month", maps_v2_path(start_at: 1.month.ago.beginning_of_day, end_at: Time.current.end_of_day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" %>
|
||||
<%= link_to "Last month", maps_maplibre_path(start_at: 1.month.ago.beginning_of_day, end_at: Time.current.end_of_day, import_id: params[:import_id]), class: "btn btn-sm border border-base-300 hover:btn-ghost w-full" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
pin_all_from 'app/javascript/channels', under: 'channels'
|
||||
pin_all_from 'app/javascript/maps', under: 'maps'
|
||||
pin_all_from 'app/javascript/maps_v2', under: 'maps_v2'
|
||||
pin_all_from 'app/javascript/maps_maplibre', under: 'maps_maplibre'
|
||||
|
||||
pin 'application', preload: true
|
||||
pin '@rails/actioncable', to: 'actioncable.esm.js'
|
||||
|
|
|
|||
|
|
@ -110,10 +110,19 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :metrics, only: [:index]
|
||||
|
||||
# V1 (Leaflet) - legacy
|
||||
get 'map', to: 'map#index'
|
||||
|
||||
# Maps V2
|
||||
get '/maps_v2', to: 'maps_v2#index', as: :maps_v2
|
||||
# Main maps entry - redirects to MapLibre
|
||||
get '/maps', to: 'maps#index', as: :maps
|
||||
|
||||
# Maps namespace
|
||||
namespace :maps do
|
||||
get '/maplibre', to: 'maplibre#index', as: :maplibre
|
||||
end
|
||||
|
||||
# Backward compatibility redirect
|
||||
get '/maps_v2', to: redirect('/maps/maplibre')
|
||||
|
||||
namespace :api do
|
||||
namespace :v1 do
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* @param {Page} page - Playwright page object
|
||||
*/
|
||||
export async function navigateToMapsV2(page) {
|
||||
await page.goto('/maps_v2');
|
||||
await page.goto('/maps/maplibre');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,18 +44,18 @@ export async function waitForMapLibre(page, timeout = 10000) {
|
|||
|
||||
// Wait for map instance to exist and style to be loaded
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return false;
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return false;
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
// Check if map exists and style is loaded (more reliable than loaded())
|
||||
return controller?.map && controller.map.isStyleLoaded();
|
||||
}, { timeout: 15000 });
|
||||
|
||||
// Wait for loading overlay to be hidden
|
||||
await page.waitForFunction(() => {
|
||||
const loading = document.querySelector('[data-maps-v2-target="loading"]');
|
||||
const loading = document.querySelector('[data-maps--maplibre-target="loading"]');
|
||||
return loading && loading.classList.contains('hidden');
|
||||
}, { timeout: 15000 });
|
||||
}
|
||||
|
|
@ -67,14 +67,14 @@ export async function waitForMapLibre(page, timeout = 10000) {
|
|||
*/
|
||||
export async function hasMapInstance(page) {
|
||||
return await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return false;
|
||||
|
||||
// Get Stimulus controller instance
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return false;
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
return controller && controller.map !== undefined;
|
||||
});
|
||||
}
|
||||
|
|
@ -86,13 +86,13 @@ export async function hasMapInstance(page) {
|
|||
*/
|
||||
export async function getMapZoom(page) {
|
||||
return await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return null;
|
||||
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return null;
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
return controller?.map?.getZoom() || null;
|
||||
});
|
||||
}
|
||||
|
|
@ -104,13 +104,13 @@ export async function getMapZoom(page) {
|
|||
*/
|
||||
export async function getMapCenter(page) {
|
||||
return await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return null;
|
||||
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return null;
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
if (!controller?.map) return null;
|
||||
|
||||
const center = controller.map.getCenter();
|
||||
|
|
@ -125,13 +125,13 @@ export async function getMapCenter(page) {
|
|||
*/
|
||||
export async function getPointsSourceData(page) {
|
||||
return await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return { hasSource: false, featureCount: 0, features: [] };
|
||||
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return { hasSource: false, featureCount: 0, features: [] };
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
if (!controller?.map) return { hasSource: false, featureCount: 0, features: [] };
|
||||
|
||||
const source = controller.map.getSource('points-source');
|
||||
|
|
@ -154,13 +154,13 @@ export async function getPointsSourceData(page) {
|
|||
*/
|
||||
export async function hasLayer(page, layerId) {
|
||||
return await page.evaluate((id) => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return false;
|
||||
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return false;
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
if (!controller?.map) return false;
|
||||
|
||||
return controller.map.getLayer(id) !== undefined;
|
||||
|
|
@ -174,7 +174,7 @@ export async function hasLayer(page, layerId) {
|
|||
* @param {number} y - Y coordinate
|
||||
*/
|
||||
export async function clickMapAt(page, x, y) {
|
||||
const mapContainer = page.locator('[data-maps-v2-target="container"]');
|
||||
const mapContainer = page.locator('[data-maps--maplibre-target="container"]');
|
||||
await mapContainer.click({ position: { x, y } });
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ export async function clickMapAt(page, x, y) {
|
|||
*/
|
||||
export async function waitForLoadingComplete(page) {
|
||||
await page.waitForFunction(() => {
|
||||
const loading = document.querySelector('[data-maps-v2-target="loading"]');
|
||||
const loading = document.querySelector('[data-maps--maplibre-target="loading"]');
|
||||
return loading && loading.classList.contains('hidden');
|
||||
}, { timeout: 15000 });
|
||||
}
|
||||
|
|
@ -207,13 +207,13 @@ export async function hasPopup(page) {
|
|||
*/
|
||||
export async function getLayerVisibility(page, layerId) {
|
||||
return await page.evaluate((id) => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return false;
|
||||
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return false;
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
if (!controller?.map) return false;
|
||||
|
||||
const visibility = controller.map.getLayoutProperty(id, 'visibility');
|
||||
|
|
@ -228,13 +228,13 @@ export async function getLayerVisibility(page, layerId) {
|
|||
*/
|
||||
export async function getRoutesSourceData(page) {
|
||||
return await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]');
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]');
|
||||
if (!element) return { hasSource: false, featureCount: 0, features: [] };
|
||||
|
||||
const app = window.Stimulus || window.Application;
|
||||
if (!app) return { hasSource: false, featureCount: 0, features: [] };
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2');
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre');
|
||||
if (!controller?.map) return { hasSource: false, featureCount: 0, features: [] };
|
||||
|
||||
const source = controller.map.getSource('routes-source');
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { waitForMapLibre, waitForLoadingComplete } from '../helpers/setup.js'
|
|||
test.describe('Area Selection in Maps V2', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Navigate to Maps V2 with specific date range that has data
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForMapLibre(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
|
@ -15,17 +15,17 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
|
||||
test('should enable area selection mode when clicking Select Area button', async ({ page }) => {
|
||||
// Open settings panel and switch to Tools tab
|
||||
await page.click('[data-action="click->maps-v2#toggleSettings"]')
|
||||
await page.click('[data-action="click->maps--maplibre#toggleSettings"]')
|
||||
await page.click('button[data-tab="tools"]')
|
||||
|
||||
// Click Select Area button
|
||||
await page.click('[data-maps-v2-target="selectAreaButton"]')
|
||||
await page.click('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
|
||||
// Wait a moment for UI to update
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
// Verify the button changes to Cancel Selection
|
||||
const selectButton = page.locator('[data-maps-v2-target="selectAreaButton"]')
|
||||
const selectButton = page.locator('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
await expect(selectButton).toContainText('Cancel Selection', { timeout: 2000 })
|
||||
|
||||
// Verify cursor changes to crosshair (via canvas style)
|
||||
|
|
@ -39,20 +39,20 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
|
||||
test('should draw selection rectangle when dragging mouse', async ({ page }) => {
|
||||
// Open settings panel and switch to Tools tab
|
||||
await page.click('[data-action="click->maps-v2#toggleSettings"]')
|
||||
await page.click('[data-action="click->maps--maplibre#toggleSettings"]')
|
||||
await page.click('button[data-tab="tools"]')
|
||||
|
||||
// Click Select Area button
|
||||
await page.click('[data-maps-v2-target="selectAreaButton"]')
|
||||
await page.click('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
|
||||
// Wait for selection mode to be enabled
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
// Check if selection layer has been added to map
|
||||
const hasSelectionLayer = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller.areaSelectionManager?.selectionLayer !== undefined
|
||||
})
|
||||
expect(hasSelectionLayer).toBeTruthy()
|
||||
|
|
@ -77,11 +77,11 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
|
||||
test('should show selection actions when points are selected', async ({ page }) => {
|
||||
// Open settings panel and switch to Tools tab
|
||||
await page.click('[data-action="click->maps-v2#toggleSettings"]')
|
||||
await page.click('[data-action="click->maps--maplibre#toggleSettings"]')
|
||||
await page.click('button[data-tab="tools"]')
|
||||
|
||||
// Click Select Area button
|
||||
await page.click('[data-maps-v2-target="selectAreaButton"]')
|
||||
await page.click('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
|
||||
// Get map canvas
|
||||
const canvas = page.locator('canvas.maplibregl-canvas')
|
||||
|
|
@ -103,30 +103,30 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
await page.waitForTimeout(1000)
|
||||
|
||||
// If points were found, verify UI updates
|
||||
const selectionActions = page.locator('[data-maps-v2-target="selectionActions"]')
|
||||
const selectionActions = page.locator('[data-maps--maplibre-target="selectionActions"]')
|
||||
const isVisible = await selectionActions.isVisible().catch(() => false)
|
||||
|
||||
if (isVisible) {
|
||||
// Verify delete button is visible and shows count
|
||||
const deleteButton = page.locator('[data-maps-v2-target="deleteButtonText"]')
|
||||
const deleteButton = page.locator('[data-maps--maplibre-target="deleteButtonText"]')
|
||||
await expect(deleteButton).toBeVisible()
|
||||
|
||||
// Wait for button text to update with count
|
||||
await expect(deleteButton).toContainText(/Delete \d+ Points?/, { timeout: 2000 })
|
||||
|
||||
// Verify the Select Area button has changed to Cancel Selection (at top of tools)
|
||||
const selectButton = page.locator('[data-maps-v2-target="selectAreaButton"]')
|
||||
const selectButton = page.locator('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
await expect(selectButton).toContainText('Cancel Selection')
|
||||
}
|
||||
})
|
||||
|
||||
test('should cancel area selection', async ({ page }) => {
|
||||
// Open settings panel and switch to Tools tab
|
||||
await page.click('[data-action="click->maps-v2#toggleSettings"]')
|
||||
await page.click('[data-action="click->maps--maplibre#toggleSettings"]')
|
||||
await page.click('button[data-tab="tools"]')
|
||||
|
||||
// Click Select Area button
|
||||
await page.click('[data-maps-v2-target="selectAreaButton"]')
|
||||
await page.click('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
|
||||
// Wait for selection mode
|
||||
await page.waitForTimeout(500)
|
||||
|
|
@ -150,12 +150,12 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
await page.waitForTimeout(500)
|
||||
|
||||
// Check if selection actions are visible
|
||||
const selectionActions = page.locator('[data-maps-v2-target="selectionActions"]')
|
||||
const selectionActions = page.locator('[data-maps--maplibre-target="selectionActions"]')
|
||||
const isVisible = await selectionActions.isVisible().catch(() => false)
|
||||
|
||||
if (isVisible) {
|
||||
// Click Cancel button (the red one at the top that replaced Select Area)
|
||||
const cancelButton = page.locator('[data-maps-v2-target="selectAreaButton"]')
|
||||
const cancelButton = page.locator('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
await expect(cancelButton).toContainText('Cancel Selection')
|
||||
await cancelButton.click()
|
||||
|
||||
|
|
@ -171,11 +171,11 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
|
||||
test('should display delete confirmation dialog', async ({ page }) => {
|
||||
// Open settings panel and switch to Tools tab
|
||||
await page.click('[data-action="click->maps-v2#toggleSettings"]')
|
||||
await page.click('[data-action="click->maps--maplibre#toggleSettings"]')
|
||||
await page.click('button[data-tab="tools"]')
|
||||
|
||||
// Click Select Area button
|
||||
await page.click('[data-maps-v2-target="selectAreaButton"]')
|
||||
await page.click('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
|
||||
// Get map canvas
|
||||
const canvas = page.locator('canvas.maplibregl-canvas')
|
||||
|
|
@ -196,7 +196,7 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
await page.waitForTimeout(500)
|
||||
|
||||
// Check if selection actions are visible
|
||||
const selectionActions = page.locator('[data-maps-v2-target="selectionActions"]')
|
||||
const selectionActions = page.locator('[data-maps--maplibre-target="selectionActions"]')
|
||||
const isVisible = await selectionActions.isVisible().catch(() => false)
|
||||
|
||||
if (isVisible) {
|
||||
|
|
@ -210,7 +210,7 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
})
|
||||
|
||||
// Click Delete button (text now includes count like "Delete 100 Points")
|
||||
await page.locator('[data-maps-v2-target="deletePointsButton"]').click()
|
||||
await page.locator('[data-maps--maplibre-target="deletePointsButton"]').click()
|
||||
|
||||
// Wait for dialog to be handled
|
||||
await page.waitForTimeout(1000)
|
||||
|
|
@ -228,11 +228,11 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
// by verifying the API call is made with the correct parameters when selecting an area
|
||||
|
||||
// Open settings panel and switch to Tools tab
|
||||
await page.click('[data-action="click->maps-v2#toggleSettings"]')
|
||||
await page.click('[data-action="click->maps--maplibre#toggleSettings"]')
|
||||
await page.click('button[data-tab="tools"]')
|
||||
|
||||
// Click Select Area button
|
||||
await page.click('[data-maps-v2-target="selectAreaButton"]')
|
||||
await page.click('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
// Get map canvas
|
||||
|
|
@ -269,11 +269,11 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
|
||||
test('should add selected points layer to map when points are selected', async ({ page }) => {
|
||||
// Open settings panel and switch to Tools tab
|
||||
await page.click('[data-action="click->maps-v2#toggleSettings"]')
|
||||
await page.click('[data-action="click->maps--maplibre#toggleSettings"]')
|
||||
await page.click('button[data-tab="tools"]')
|
||||
|
||||
// Click Select Area button
|
||||
await page.click('[data-maps-v2-target="selectAreaButton"]')
|
||||
await page.click('[data-maps--maplibre-target="selectAreaButton"]')
|
||||
|
||||
// Get map canvas
|
||||
const canvas = page.locator('canvas.maplibregl-canvas')
|
||||
|
|
@ -295,9 +295,9 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
|
||||
// Check if selected points layer exists
|
||||
const hasSelectedPointsLayer = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.areaSelectionManager?.selectedPointsLayer !== undefined
|
||||
})
|
||||
|
||||
|
|
@ -305,9 +305,9 @@ test.describe('Area Selection in Maps V2', () => {
|
|||
if (hasSelectedPointsLayer) {
|
||||
// Verify layer is on the map
|
||||
const layerExistsOnMap = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('selected-points') !== undefined
|
||||
})
|
||||
expect(layerExistsOnMap).toBeTruthy()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ test.describe('Map Core', () => {
|
|||
|
||||
test.describe('Initialization', () => {
|
||||
test('loads map container', async ({ page }) => {
|
||||
const mapContainer = page.locator('[data-maps-v2-target="container"]')
|
||||
const mapContainer = page.locator('[data-maps--maplibre-target="container"]')
|
||||
await expect(mapContainer).toBeVisible()
|
||||
})
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ test.describe('Map Core', () => {
|
|||
})
|
||||
|
||||
test('has valid initial center and zoom', async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForMapLibre(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
|
@ -55,7 +55,7 @@ test.describe('Map Core', () => {
|
|||
|
||||
test.describe('Loading States', () => {
|
||||
test('shows loading indicator during data fetch', async ({ page }) => {
|
||||
const loading = page.locator('[data-maps-v2-target="loading"]')
|
||||
const loading = page.locator('[data-maps--maplibre-target="loading"]')
|
||||
|
||||
const navigationPromise = page.reload({ waitUntil: 'domcontentloaded' })
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ test.describe('Map Core', () => {
|
|||
|
||||
test.describe('Data Bounds', () => {
|
||||
test('fits map bounds to loaded data', async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForMapLibre(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
|
@ -96,7 +96,7 @@ test.describe('Map Core', () => {
|
|||
|
||||
test.describe('Lifecycle', () => {
|
||||
test('cleans up and reinitializes on navigation', async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ test.describe('Map Core', () => {
|
|||
})
|
||||
|
||||
test('reloads data when changing date range', async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
|
||||
test.describe('Map Interactions', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForLoadingComplete(page)
|
||||
await page.waitForTimeout(500)
|
||||
|
|
@ -57,7 +57,7 @@ test.describe('Map Interactions', () => {
|
|||
|
||||
test.describe('Hover Effects', () => {
|
||||
test('map container is interactive', async ({ page }) => {
|
||||
const mapContainer = page.locator('[data-maps-v2-target="container"]')
|
||||
const mapContainer = page.locator('[data-maps--maplibre-target="container"]')
|
||||
await expect(mapContainer).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ import { closeOnboardingModal } from '../../../helpers/navigation.js'
|
|||
|
||||
test.describe('Advanced Layers', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/maps_v2')
|
||||
await page.goto('/maps/maplibre')
|
||||
await page.evaluate(() => {
|
||||
localStorage.removeItem('dawarich-maps-v2-settings')
|
||||
localStorage.removeItem('dawarich-maps--maplibre-settings')
|
||||
})
|
||||
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await page.waitForTimeout(2000)
|
||||
})
|
||||
|
|
@ -16,7 +16,7 @@ test.describe('Advanced Layers', () => {
|
|||
test.describe('Fog of War', () => {
|
||||
test('fog layer is disabled by default', async ({ page }) => {
|
||||
const fogEnabled = await page.evaluate(() => {
|
||||
const settings = JSON.parse(localStorage.getItem('dawarich-maps-v2-settings') || '{}')
|
||||
const settings = JSON.parse(localStorage.getItem('dawarich-maps--maplibre-settings') || '{}')
|
||||
return settings.fogEnabled
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ test.describe('Areas Layer', () => {
|
|||
test.describe('Toggle', () => {
|
||||
test('areas layer toggle exists', async ({ page }) => {
|
||||
// Open settings panel
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -27,7 +27,7 @@ test.describe('Areas Layer', () => {
|
|||
|
||||
test('can toggle areas layer', async ({ page }) => {
|
||||
// Open settings panel
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -46,7 +46,7 @@ test.describe('Areas Layer', () => {
|
|||
test.describe('Area Creation', () => {
|
||||
test('should have Create an Area button in Tools tab', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Tools tab
|
||||
|
|
@ -60,7 +60,7 @@ test.describe('Areas Layer', () => {
|
|||
|
||||
test('should change cursor to crosshair when Create an Area is clicked', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="tools"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
@ -79,7 +79,7 @@ test.describe('Areas Layer', () => {
|
|||
|
||||
test('should show area preview while drawing', async ({ page }) => {
|
||||
// Enable creation mode
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="tools"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
@ -97,9 +97,9 @@ test.describe('Areas Layer', () => {
|
|||
|
||||
// Verify draw layers exist
|
||||
const hasDrawLayers = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
const map = controller?.map
|
||||
return map && map.getSource('draw-source') !== undefined
|
||||
})
|
||||
|
|
@ -108,7 +108,7 @@ test.describe('Areas Layer', () => {
|
|||
|
||||
test('should open modal when area is drawn', async ({ page }) => {
|
||||
// Enable creation mode
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="tools"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
@ -133,7 +133,7 @@ test.describe('Areas Layer', () => {
|
|||
|
||||
test('should display radius and location in modal', async ({ page }) => {
|
||||
// Enable creation mode and draw area
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="tools"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
@ -167,7 +167,7 @@ test.describe('Areas Layer', () => {
|
|||
|
||||
test('should create area and enable layer when submitted', async ({ page }) => {
|
||||
// Draw area
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="tools"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
@ -224,7 +224,7 @@ test.describe('Areas Layer', () => {
|
|||
await page.waitForTimeout(1000)
|
||||
|
||||
// Verify areas layer is now enabled
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="layers"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { closeOnboardingModal } from '../../../helpers/navigation.js'
|
|||
|
||||
test.describe('Heatmap Layer', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await page.waitForTimeout(2000)
|
||||
})
|
||||
|
|
@ -22,18 +22,18 @@ test.describe('Heatmap Layer', () => {
|
|||
|
||||
// Wait for heatmap layer to be created
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return false
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('heatmap') !== undefined
|
||||
}, { timeout: 3000 }).catch(() => false)
|
||||
|
||||
const hasHeatmap = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return false
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('heatmap') !== undefined
|
||||
})
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ test.describe('Heatmap Layer', () => {
|
|||
await page.waitForTimeout(500)
|
||||
|
||||
const settings = await page.evaluate(() => {
|
||||
return localStorage.getItem('dawarich-maps-v2-settings')
|
||||
return localStorage.getItem('dawarich-maps--maplibre-settings')
|
||||
})
|
||||
|
||||
const parsed = JSON.parse(settings)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should have Tools tab with Create a Place button', async ({ page }) => {
|
||||
// Click settings button
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Tools tab
|
||||
|
|
@ -32,7 +32,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should enable place creation mode when Create a Place is clicked', async ({ page }) => {
|
||||
// Open Tools tab
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="tools"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
@ -51,7 +51,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should open modal when map is clicked in creation mode', async ({ page }) => {
|
||||
// Enable creation mode
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
await page.locator('button[data-tab="tools"]').click()
|
||||
await page.waitForTimeout(200)
|
||||
|
|
@ -74,7 +74,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should have Places toggle in settings', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -92,7 +92,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should show tag filters when Places toggle is enabled with all tags enabled by default', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -105,11 +105,11 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
await page.waitForTimeout(1000)
|
||||
|
||||
// Verify filters are visible
|
||||
const placesFilters = page.locator('[data-maps-v2-target="placesFilters"]')
|
||||
const placesFilters = page.locator('[data-maps--maplibre-target="placesFilters"]')
|
||||
await expect(placesFilters).toBeVisible()
|
||||
|
||||
// Verify "Enable All Tags" toggle is enabled by default
|
||||
const enableAllToggle = page.locator('input[data-maps-v2-target="enableAllPlaceTagsToggle"]')
|
||||
const enableAllToggle = page.locator('input[data-maps--maplibre-target="enableAllPlaceTagsToggle"]')
|
||||
await expect(enableAllToggle).toBeChecked()
|
||||
|
||||
// Verify all tag checkboxes are checked by default
|
||||
|
|
@ -127,7 +127,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should toggle tag filter styling when clicked', async ({ page }) => {
|
||||
// Open settings and enable Places
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -139,8 +139,8 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
await page.waitForTimeout(1000)
|
||||
|
||||
// Get first tag badge (in Places filters section) - click badge since checkbox is hidden
|
||||
const firstBadge = page.locator('[data-maps-v2-target="placesFilters"] .badge').first()
|
||||
const firstCheckbox = page.locator('[data-maps-v2-target="placesFilters"] input[name="place_tag_ids[]"]').first()
|
||||
const firstBadge = page.locator('[data-maps--maplibre-target="placesFilters"] .badge').first()
|
||||
const firstCheckbox = page.locator('[data-maps--maplibre-target="placesFilters"] input[name="place_tag_ids[]"]').first()
|
||||
|
||||
// Check initial state (should be checked by default)
|
||||
await expect(firstCheckbox).toBeChecked()
|
||||
|
|
@ -160,7 +160,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should hide tag filters when Places toggle is disabled', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -175,14 +175,14 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
await page.waitForTimeout(300)
|
||||
|
||||
// Verify filters are hidden
|
||||
const placesFilters = page.locator('[data-maps-v2-target="placesFilters"]')
|
||||
const placesFilters = page.locator('[data-maps--maplibre-target="placesFilters"]')
|
||||
const isVisible = await placesFilters.isVisible()
|
||||
expect(isVisible).toBe(false)
|
||||
})
|
||||
|
||||
test('can toggle places layer', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -201,7 +201,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should show popup when clicking on a place marker', async ({ page }) => {
|
||||
// Enable Places layer
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -213,7 +213,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
await page.waitForTimeout(1000)
|
||||
|
||||
// Close settings to make map clickable
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Try to click on a place marker (if any exist)
|
||||
|
|
@ -233,7 +233,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should sync Enable All Tags toggle with individual tag checkboxes', async ({ page }) => {
|
||||
// Open settings and enable Places
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -244,14 +244,14 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
await placesToggle.check()
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
const enableAllToggle = page.locator('input[data-maps-v2-target="enableAllPlaceTagsToggle"]')
|
||||
const enableAllToggle = page.locator('input[data-maps--maplibre-target="enableAllPlaceTagsToggle"]')
|
||||
|
||||
// Initially all tags should be enabled
|
||||
await expect(enableAllToggle).toBeChecked()
|
||||
|
||||
// Click first badge to uncheck it (checkbox is hidden, must click badge)
|
||||
const firstBadge = page.locator('[data-maps-v2-target="placesFilters"] .badge').first()
|
||||
const firstCheckbox = page.locator('[data-maps-v2-target="placesFilters"] input[name="place_tag_ids[]"]').first()
|
||||
const firstBadge = page.locator('[data-maps--maplibre-target="placesFilters"] .badge').first()
|
||||
const firstCheckbox = page.locator('[data-maps--maplibre-target="placesFilters"] input[name="place_tag_ids[]"]').first()
|
||||
|
||||
await firstBadge.click()
|
||||
await page.waitForTimeout(300)
|
||||
|
|
@ -269,7 +269,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should enable/disable all tags when Enable All Tags toggle is clicked', async ({ page }) => {
|
||||
// Open settings and enable Places
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -280,7 +280,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
await placesToggle.check()
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
const enableAllToggle = page.locator('input[data-maps-v2-target="enableAllPlaceTagsToggle"]')
|
||||
const enableAllToggle = page.locator('input[data-maps--maplibre-target="enableAllPlaceTagsToggle"]')
|
||||
|
||||
// Disable all tags
|
||||
await enableAllToggle.uncheck()
|
||||
|
|
@ -305,7 +305,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
|
||||
test('should show no places when all tags are unchecked', async ({ page }) => {
|
||||
// Open settings and enable Places
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(200)
|
||||
|
||||
// Click Layers tab
|
||||
|
|
@ -317,7 +317,7 @@ test.describe('Places Layer in Maps V2', () => {
|
|||
await page.waitForTimeout(1000)
|
||||
|
||||
// Disable all tags
|
||||
const enableAllToggle = page.locator('input[data-maps-v2-target="enableAllPlaceTagsToggle"]')
|
||||
const enableAllToggle = page.locator('input[data-maps--maplibre-target="enableAllPlaceTagsToggle"]')
|
||||
await enableAllToggle.uncheck()
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
|
||||
test.describe('Points Layer', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForLoadingComplete(page)
|
||||
await page.waitForTimeout(1500)
|
||||
|
|
@ -19,9 +19,9 @@ test.describe('Points Layer', () => {
|
|||
test('displays points layer', async ({ page }) => {
|
||||
// Wait for points layer to be added
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('points') !== undefined
|
||||
}, { timeout: 10000 }).catch(() => false)
|
||||
|
||||
|
|
@ -31,9 +31,9 @@ test.describe('Points Layer', () => {
|
|||
|
||||
test('loads and displays point data', async ({ page }) => {
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getSource('points-source') !== undefined
|
||||
}, { timeout: 15000 }).catch(() => false)
|
||||
|
||||
|
|
@ -47,9 +47,9 @@ test.describe('Points Layer', () => {
|
|||
test('points source contains valid GeoJSON features', async ({ page }) => {
|
||||
// Wait for source to be added
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getSource('points-source') !== undefined
|
||||
}, { timeout: 10000 }).catch(() => false)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
|
||||
test.describe('Routes Layer', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForMapLibre(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
|
@ -21,11 +21,11 @@ test.describe('Routes Layer', () => {
|
|||
test.describe('Layer Existence', () => {
|
||||
test('routes layer exists on map', async ({ page }) => {
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return false
|
||||
const app = window.Stimulus || window.Application
|
||||
if (!app) return false
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('routes') !== undefined
|
||||
}, { timeout: 10000 }).catch(() => false)
|
||||
|
||||
|
|
@ -37,11 +37,11 @@ test.describe('Routes Layer', () => {
|
|||
test.describe('Data Source', () => {
|
||||
test('routes source has data', async ({ page }) => {
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return false
|
||||
const app = window.Stimulus || window.Application
|
||||
if (!app) return false
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getSource('routes-source') !== undefined
|
||||
}, { timeout: 20000 })
|
||||
|
||||
|
|
@ -92,22 +92,22 @@ test.describe('Routes Layer', () => {
|
|||
test.describe('Styling', () => {
|
||||
test('routes have solid color', async ({ page }) => {
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return false
|
||||
const app = window.Stimulus || window.Application
|
||||
if (!app) return false
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('routes') !== undefined
|
||||
}, { timeout: 20000 })
|
||||
|
||||
const routeLayerInfo = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return null
|
||||
|
||||
const app = window.Stimulus || window.Application
|
||||
if (!app) return null
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
if (!controller?.map) return null
|
||||
|
||||
const layer = controller.map.getLayer('routes')
|
||||
|
|
@ -132,21 +132,21 @@ test.describe('Routes Layer', () => {
|
|||
test.describe('Layer Order', () => {
|
||||
test('routes layer renders below points layer', async ({ page }) => {
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('routes') !== undefined &&
|
||||
controller?.map?.getLayer('points') !== undefined
|
||||
}, { timeout: 10000 })
|
||||
|
||||
const layerOrder = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return null
|
||||
|
||||
const app = window.Stimulus || window.Application
|
||||
if (!app) return null
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
if (!controller?.map) return null
|
||||
|
||||
const style = controller.map.getStyle()
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ test.describe('Visits Layer', () => {
|
|||
await page.waitForTimeout(500)
|
||||
|
||||
// Verify settings panel closed
|
||||
const settingsPanel = page.locator('[data-maps-v2-target="settingsPanel"]')
|
||||
const settingsPanel = page.locator('[data-maps--maplibre-target="settingsPanel"]')
|
||||
const hasPanelOpenClass = await settingsPanel.evaluate((el) => el.classList.contains('open'))
|
||||
expect(hasPanelOpenClass).toBe(false)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ test.describe('Map Performance', () => {
|
|||
test('map loads within acceptable time', async ({ page }) => {
|
||||
const startTime = Date.now()
|
||||
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForMapLibre(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
|
@ -19,7 +19,7 @@ test.describe('Map Performance', () => {
|
|||
})
|
||||
|
||||
test('handles large datasets efficiently', async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-01T00:00&end_at=2025-10-31T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-01T00:00&end_at=2025-10-31T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
|
||||
const startTime = Date.now()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { waitForMapLibre, waitForLoadingComplete } from '../helpers/setup.js'
|
|||
|
||||
test.describe('Location Search', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await waitForMapLibre(page)
|
||||
await waitForLoadingComplete(page)
|
||||
|
|
@ -18,7 +18,7 @@ test.describe('Location Search', () => {
|
|||
await page.waitForTimeout(400)
|
||||
|
||||
// Search tab should be active by default
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
await expect(searchInput).toBeVisible()
|
||||
await expect(searchInput).toHaveAttribute('placeholder', 'Enter name of a place')
|
||||
})
|
||||
|
|
@ -27,7 +27,7 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
await expect(resultsContainer).toBeAttached()
|
||||
await expect(resultsContainer).toHaveClass(/hidden/)
|
||||
})
|
||||
|
|
@ -38,14 +38,14 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
|
||||
// Type a search query
|
||||
await searchInput.fill('New')
|
||||
await page.waitForTimeout(500) // Wait for debounce
|
||||
|
||||
// Results container should become visible (or show loading)
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Wait for results to appear
|
||||
await page.waitForTimeout(1000)
|
||||
|
|
@ -63,8 +63,8 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Type single character
|
||||
await searchInput.fill('N')
|
||||
|
|
@ -78,8 +78,8 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Type search query
|
||||
await searchInput.fill('New York')
|
||||
|
|
@ -100,18 +100,18 @@ test.describe('Location Search', () => {
|
|||
await page.waitForTimeout(1000)
|
||||
|
||||
const hasSearchManager = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
if (!element) return false
|
||||
|
||||
const app = window.Stimulus || window.Application
|
||||
if (!app) return false
|
||||
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.searchManager !== undefined
|
||||
})
|
||||
|
||||
// Search manager should exist if search targets are present
|
||||
const hasSearchTargets = await page.locator('[data-maps-v2-target="searchInput"]').count()
|
||||
const hasSearchTargets = await page.locator('[data-maps--maplibre-target="searchInput"]').count()
|
||||
if (hasSearchTargets > 0) {
|
||||
expect(hasSearchManager).toBe(true)
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
await expect(searchInput).toHaveAttribute('autocomplete', 'off')
|
||||
})
|
||||
})
|
||||
|
|
@ -131,8 +131,8 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Search for a location
|
||||
await searchInput.fill('Sterndamm')
|
||||
|
|
@ -157,8 +157,8 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Search and select location
|
||||
await searchInput.fill('Sterndamm')
|
||||
|
|
@ -191,8 +191,8 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Search and select location
|
||||
await searchInput.fill('Sterndamm')
|
||||
|
|
@ -236,8 +236,8 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Search and select location
|
||||
await searchInput.fill('Sterndamm')
|
||||
|
|
@ -288,7 +288,7 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const resultsContainer = page.locator('[data-maps-v2-target="searchResults"]')
|
||||
const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
|
||||
|
||||
// Check max-height class is set appropriately (max-h-96)
|
||||
const hasMaxHeight = await resultsContainer.evaluate(el => {
|
||||
|
|
@ -305,7 +305,7 @@ test.describe('Location Search', () => {
|
|||
await page.click('button[title="Open map settings"]')
|
||||
await page.waitForTimeout(400)
|
||||
|
||||
const searchInput = page.locator('[data-maps-v2-target="searchInput"]')
|
||||
const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
|
||||
|
||||
// Focus input with keyboard
|
||||
await searchInput.focus()
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ import { getLayerVisibility } from '../helpers/setup.js'
|
|||
|
||||
test.describe('Map Settings', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/maps_v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await page.goto('/maps/maplibre?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
|
||||
await closeOnboardingModal(page)
|
||||
await page.waitForTimeout(2000)
|
||||
})
|
||||
|
||||
test.describe('Settings Panel', () => {
|
||||
test('opens and closes settings panel', async ({ page }) => {
|
||||
const panel = page.locator('[data-maps-v2-target="settingsPanel"]')
|
||||
const panel = page.locator('[data-maps--maplibre-target="settingsPanel"]')
|
||||
|
||||
// Verify panel exists but is not open initially
|
||||
await expect(panel).toBeVisible()
|
||||
|
|
@ -62,9 +62,9 @@ test.describe('Map Settings', () => {
|
|||
test('points layer visibility matches toggle state', async ({ page }) => {
|
||||
// Wait for points layer to exist
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('points') !== undefined
|
||||
}, { timeout: 5000 }).catch(() => false)
|
||||
|
||||
|
|
@ -84,9 +84,9 @@ test.describe('Map Settings', () => {
|
|||
test('routes layer visibility matches toggle state', async ({ page }) => {
|
||||
// Wait for routes layer to exist
|
||||
await page.waitForFunction(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('routes') !== undefined
|
||||
}, { timeout: 5000 }).catch(() => false)
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ test.describe('Map Settings', () => {
|
|||
const initialState = await pointsToggle.isChecked()
|
||||
|
||||
const settings = await page.evaluate(() => {
|
||||
return localStorage.getItem('dawarich-maps-v2-settings')
|
||||
return localStorage.getItem('dawarich-maps--maplibre-settings')
|
||||
})
|
||||
|
||||
expect(settings).toBeTruthy()
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ test.describe('Realtime Family Tracking', () => {
|
|||
test.skip('family layer exists but is hidden by default', async ({ page }) => {
|
||||
// Family layer is created but hidden until ActionCable data arrives
|
||||
const layerExists = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
return controller?.map?.getLayer('family') !== undefined
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ test.describe('Live Mode', () => {
|
|||
test.describe('Live Mode Toggle', () => {
|
||||
test('should have live mode toggle in settings', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
// Click Settings tab
|
||||
|
|
@ -22,7 +22,7 @@ test.describe('Live Mode', () => {
|
|||
await page.waitForTimeout(300)
|
||||
|
||||
// Verify Live Mode toggle exists
|
||||
const liveModeToggle = page.locator('[data-maps-v2-realtime-target="liveModeToggle"]')
|
||||
const liveModeToggle = page.locator('[data-maps--maplibre-realtime-target="liveModeToggle"]')
|
||||
await expect(liveModeToggle).toBeVisible()
|
||||
|
||||
// Verify label text
|
||||
|
|
@ -36,12 +36,12 @@ test.describe('Live Mode', () => {
|
|||
|
||||
test('should toggle live mode on and off', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(300)
|
||||
await page.locator('button[data-tab="settings"]').click()
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
const liveModeToggle = page.locator('[data-maps-v2-realtime-target="liveModeToggle"]')
|
||||
const liveModeToggle = page.locator('[data-maps--maplibre-realtime-target="liveModeToggle"]')
|
||||
|
||||
// Get initial state
|
||||
const initialState = await liveModeToggle.isChecked()
|
||||
|
|
@ -65,12 +65,12 @@ test.describe('Live Mode', () => {
|
|||
|
||||
test('should show toast notification when toggling live mode', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(300)
|
||||
await page.locator('button[data-tab="settings"]').click()
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
const liveModeToggle = page.locator('[data-maps-v2-realtime-target="liveModeToggle"]')
|
||||
const liveModeToggle = page.locator('[data-maps--maplibre-realtime-target="liveModeToggle"]')
|
||||
const initialState = await liveModeToggle.isChecked()
|
||||
|
||||
// Toggle and watch for toast
|
||||
|
|
@ -86,20 +86,20 @@ test.describe('Live Mode', () => {
|
|||
test.describe('Realtime Controller', () => {
|
||||
test('should initialize realtime controller when enabled', async ({ page }) => {
|
||||
const realtimeControllerExists = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2-realtime"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre-realtime"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2-realtime')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre-realtime')
|
||||
return controller !== undefined
|
||||
})
|
||||
|
||||
expect(realtimeControllerExists).toBe(true)
|
||||
})
|
||||
|
||||
test('should have access to maps-v2 controller', async ({ page }) => {
|
||||
test('should have access to maps--maplibre controller', async ({ page }) => {
|
||||
const hasMapsController = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2-realtime"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre-realtime"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const realtimeController = app?.getControllerForElementAndIdentifier(element, 'maps-v2-realtime')
|
||||
const realtimeController = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre-realtime')
|
||||
const mapsController = realtimeController?.mapsV2Controller
|
||||
return mapsController !== undefined && mapsController.map !== undefined
|
||||
})
|
||||
|
|
@ -112,9 +112,9 @@ test.describe('Live Mode', () => {
|
|||
await page.waitForTimeout(2000)
|
||||
|
||||
const channelsInitialized = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2-realtime"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre-realtime"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2-realtime')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre-realtime')
|
||||
return controller?.channels !== undefined
|
||||
})
|
||||
|
||||
|
|
@ -181,9 +181,9 @@ test.describe('Live Mode', () => {
|
|||
test.describe('Point Handling', () => {
|
||||
test('should have handleNewPoint method', async ({ page }) => {
|
||||
const hasMethod = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2-realtime"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre-realtime"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2-realtime')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre-realtime')
|
||||
return typeof controller?.handleNewPoint === 'function'
|
||||
})
|
||||
|
||||
|
|
@ -192,9 +192,9 @@ test.describe('Live Mode', () => {
|
|||
|
||||
test('should have zoomToPoint method', async ({ page }) => {
|
||||
const hasMethod = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2-realtime"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre-realtime"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2-realtime')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre-realtime')
|
||||
return typeof controller?.zoomToPoint === 'function'
|
||||
})
|
||||
|
||||
|
|
@ -207,9 +207,9 @@ test.describe('Live Mode', () => {
|
|||
|
||||
// Get initial point count
|
||||
const initialCount = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
|
||||
const pointsLayer = controller?.layerManager?.getLayer('points')
|
||||
return pointsLayer?.data?.features?.length || 0
|
||||
})
|
||||
|
|
@ -238,12 +238,12 @@ test.describe('Live Mode', () => {
|
|||
test.describe('Live Mode State Persistence', () => {
|
||||
test('should maintain live mode state after toggling', async ({ page }) => {
|
||||
// Open settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(300)
|
||||
await page.locator('button[data-tab="settings"]').click()
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
const liveModeToggle = page.locator('[data-maps-v2-realtime-target="liveModeToggle"]')
|
||||
const liveModeToggle = page.locator('[data-maps--maplibre-realtime-target="liveModeToggle"]')
|
||||
|
||||
// Enable live mode
|
||||
if (!await liveModeToggle.isChecked()) {
|
||||
|
|
@ -255,9 +255,9 @@ test.describe('Live Mode', () => {
|
|||
expect(await liveModeToggle.isChecked()).toBe(true)
|
||||
|
||||
// Close and reopen settings
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(300)
|
||||
await page.locator('[data-action="click->maps-v2#toggleSettings"]').first().click()
|
||||
await page.locator('[data-action="click->maps--maplibre#toggleSettings"]').first().click()
|
||||
await page.waitForTimeout(300)
|
||||
await page.locator('button[data-tab="settings"]').click()
|
||||
await page.waitForTimeout(300)
|
||||
|
|
@ -271,9 +271,9 @@ test.describe('Live Mode', () => {
|
|||
test('should handle missing maps controller gracefully', async ({ page }) => {
|
||||
// This is tested by the controller's defensive checks
|
||||
const hasDefensiveChecks = await page.evaluate(() => {
|
||||
const element = document.querySelector('[data-controller*="maps-v2-realtime"]')
|
||||
const element = document.querySelector('[data-controller*="maps--maplibre-realtime"]')
|
||||
const app = window.Stimulus || window.Application
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps-v2-realtime')
|
||||
const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre-realtime')
|
||||
|
||||
// The controller should have the mapsV2Controller getter
|
||||
return typeof controller?.mapsV2Controller !== 'undefined'
|
||||
|
|
|
|||
Loading…
Reference in a new issue