pretix-map 0.1.4__py3-none-any.whl → 0.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pretix_map-0.1.5.dist-info/METADATA +88 -0
- {pretix_map-0.1.4.dist-info → pretix_map-0.1.5.dist-info}/RECORD +32 -30
- {pretix_map-0.1.4.dist-info → pretix_map-0.1.5.dist-info}/WHEEL +1 -1
- {pretix_map-0.1.4.dist-info → pretix_map-0.1.5.dist-info}/licenses/LICENSE +15 -15
- pretix_mapplugin/__init__.py +1 -1
- pretix_mapplugin/apps.py +28 -28
- pretix_mapplugin/geocoding.py +162 -102
- pretix_mapplugin/locale/de/LC_MESSAGES/django.po +12 -12
- pretix_mapplugin/locale/de_Informal/LC_MESSAGES/django.po +12 -12
- pretix_mapplugin/management/commands/geocode_existing_orders.py +271 -271
- pretix_mapplugin/migrations/0001_initial.py +27 -27
- pretix_mapplugin/migrations/0002_remove_ordergeocodedata_geocoded_timestamp_and_more.py +32 -32
- pretix_mapplugin/migrations/0003_mapmilestone.py +27 -0
- pretix_mapplugin/models.py +71 -47
- pretix_mapplugin/signals.py +77 -92
- pretix_mapplugin/static/pretix_mapplugin/css/salesmap.css +51 -51
- pretix_mapplugin/static/pretix_mapplugin/js/salesmap.js +342 -452
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.Default.css +59 -59
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.css +14 -14
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-heat.js +10 -10
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.esm.js +14419 -14419
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.js +14512 -14512
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.css +661 -661
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.js +5 -5
- pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.markercluster.js +2 -2
- pretix_mapplugin/tasks.py +144 -113
- pretix_mapplugin/templates/pretix_mapplugin/map_page.html +154 -88
- pretix_mapplugin/templates/pretix_mapplugin/milestones.html +53 -0
- pretix_mapplugin/urls.py +38 -21
- pretix_mapplugin/views.py +272 -163
- pretix_map-0.1.4.dist-info/METADATA +0 -195
- {pretix_map-0.1.4.dist-info → pretix_map-0.1.5.dist-info}/entry_points.txt +0 -0
- {pretix_map-0.1.4.dist-info → pretix_map-0.1.5.dist-info}/top_level.txt +0 -0
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
# Generated by Django 4.2.20 on 2025-04-16 01:22
|
|
2
|
-
|
|
3
|
-
from django.db import migrations, models
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Migration(migrations.Migration):
|
|
7
|
-
|
|
8
|
-
dependencies = [
|
|
9
|
-
('pretix_mapplugin', '0001_initial'),
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
operations = [
|
|
13
|
-
migrations.RemoveField(
|
|
14
|
-
model_name='ordergeocodedata',
|
|
15
|
-
name='geocoded_timestamp',
|
|
16
|
-
),
|
|
17
|
-
migrations.AddField(
|
|
18
|
-
model_name='ordergeocodedata',
|
|
19
|
-
name='last_geocoded_at',
|
|
20
|
-
field=models.DateTimeField(auto_now=True),
|
|
21
|
-
),
|
|
22
|
-
migrations.AlterField(
|
|
23
|
-
model_name='ordergeocodedata',
|
|
24
|
-
name='latitude',
|
|
25
|
-
field=models.FloatField(null=True),
|
|
26
|
-
),
|
|
27
|
-
migrations.AlterField(
|
|
28
|
-
model_name='ordergeocodedata',
|
|
29
|
-
name='longitude',
|
|
30
|
-
field=models.FloatField(null=True),
|
|
31
|
-
),
|
|
32
|
-
]
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-04-16 01:22
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('pretix_mapplugin', '0001_initial'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.RemoveField(
|
|
14
|
+
model_name='ordergeocodedata',
|
|
15
|
+
name='geocoded_timestamp',
|
|
16
|
+
),
|
|
17
|
+
migrations.AddField(
|
|
18
|
+
model_name='ordergeocodedata',
|
|
19
|
+
name='last_geocoded_at',
|
|
20
|
+
field=models.DateTimeField(auto_now=True),
|
|
21
|
+
),
|
|
22
|
+
migrations.AlterField(
|
|
23
|
+
model_name='ordergeocodedata',
|
|
24
|
+
name='latitude',
|
|
25
|
+
field=models.FloatField(null=True),
|
|
26
|
+
),
|
|
27
|
+
migrations.AlterField(
|
|
28
|
+
model_name='ordergeocodedata',
|
|
29
|
+
name='longitude',
|
|
30
|
+
field=models.FloatField(null=True),
|
|
31
|
+
),
|
|
32
|
+
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from django.db import migrations, models
|
|
2
|
+
import django.db.models.deletion
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Migration(migrations.Migration):
|
|
6
|
+
|
|
7
|
+
dependencies = [
|
|
8
|
+
('pretixbase', '0001_initial'),
|
|
9
|
+
('pretix_mapplugin', '0002_remove_ordergeocodedata_geocoded_timestamp_and_more'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.CreateModel(
|
|
14
|
+
name='MapMilestone',
|
|
15
|
+
fields=[
|
|
16
|
+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
|
|
17
|
+
('date', models.DateField(verbose_name='Date')),
|
|
18
|
+
('label', models.CharField(max_length=200, verbose_name='Milestone Label')),
|
|
19
|
+
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='map_milestones', to='pretixbase.Event')),
|
|
20
|
+
],
|
|
21
|
+
options={
|
|
22
|
+
'verbose_name': 'Map Milestone',
|
|
23
|
+
'verbose_name_plural': 'Map Milestones',
|
|
24
|
+
'ordering': ['date'],
|
|
25
|
+
},
|
|
26
|
+
),
|
|
27
|
+
]
|
pretix_mapplugin/models.py
CHANGED
|
@@ -1,47 +1,71 @@
|
|
|
1
|
-
from django.db import models
|
|
2
|
-
from pretix.base.models import LoggedModel, Order
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class OrderGeocodeData(LoggedModel): # Keep LoggedModel if you want audit logs
|
|
6
|
-
"""
|
|
7
|
-
Stores the geocoded coordinates for a Pretix Order's invoice address.
|
|
8
|
-
Allows null coordinates for failed geocoding attempts.
|
|
9
|
-
"""
|
|
10
|
-
order = models.OneToOneField(
|
|
11
|
-
Order,
|
|
12
|
-
on_delete=models.CASCADE,
|
|
13
|
-
related_name='geocode_data',
|
|
14
|
-
primary_key=True # Keep this if you want order PK as primary key
|
|
15
|
-
)
|
|
16
|
-
latitude = models.FloatField(
|
|
17
|
-
null=True, # Allow NULL in the database if geocoding fails
|
|
18
|
-
blank=True # Allow blank in forms/admin (good practice with null=True)
|
|
19
|
-
)
|
|
20
|
-
longitude = models.FloatField(
|
|
21
|
-
null=True, # Allow NULL in the database if geocoding fails
|
|
22
|
-
blank=True # Allow blank in forms/admin
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
# Change to auto_now to update timestamp on every save (successful or null)
|
|
26
|
-
last_geocoded_at = models.DateTimeField(
|
|
27
|
-
auto_now=True, # Set/Update timestamp every time the record is saved
|
|
28
|
-
help_text="Timestamp when geocoding was last attempted/updated."
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
class Meta:
|
|
32
|
-
verbose_name = "Order Geocode Data"
|
|
33
|
-
verbose_name_plural = "Order Geocode Data"
|
|
34
|
-
# Optional: Indexing coordinates can speed up map data queries if you have many entries
|
|
35
|
-
# indexes = [
|
|
36
|
-
# models.Index(fields=['latitude', 'longitude']),
|
|
37
|
-
# ]
|
|
38
|
-
|
|
39
|
-
def __str__(self):
|
|
40
|
-
# Provide more informative string representation
|
|
41
|
-
if self.latitude is not None and self.longitude is not None:
|
|
42
|
-
return f"Geocode for Order {self.order.code}: ({self.latitude:.4f}, {self.longitude:.4f})"
|
|
43
|
-
else:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
from django.db import models
|
|
2
|
+
from pretix.base.models import LoggedModel, Order
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class OrderGeocodeData(LoggedModel): # Keep LoggedModel if you want audit logs
|
|
6
|
+
"""
|
|
7
|
+
Stores the geocoded coordinates for a Pretix Order's invoice address.
|
|
8
|
+
Allows null coordinates for failed geocoding attempts.
|
|
9
|
+
"""
|
|
10
|
+
order = models.OneToOneField(
|
|
11
|
+
Order,
|
|
12
|
+
on_delete=models.CASCADE,
|
|
13
|
+
related_name='geocode_data',
|
|
14
|
+
primary_key=True # Keep this if you want order PK as primary key
|
|
15
|
+
)
|
|
16
|
+
latitude = models.FloatField(
|
|
17
|
+
null=True, # Allow NULL in the database if geocoding fails
|
|
18
|
+
blank=True # Allow blank in forms/admin (good practice with null=True)
|
|
19
|
+
)
|
|
20
|
+
longitude = models.FloatField(
|
|
21
|
+
null=True, # Allow NULL in the database if geocoding fails
|
|
22
|
+
blank=True # Allow blank in forms/admin
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Change to auto_now to update timestamp on every save (successful or null)
|
|
26
|
+
last_geocoded_at = models.DateTimeField(
|
|
27
|
+
auto_now=True, # Set/Update timestamp every time the record is saved
|
|
28
|
+
help_text="Timestamp when geocoding was last attempted/updated."
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
class Meta:
|
|
32
|
+
verbose_name = "Order Geocode Data"
|
|
33
|
+
verbose_name_plural = "Order Geocode Data"
|
|
34
|
+
# Optional: Indexing coordinates can speed up map data queries if you have many entries
|
|
35
|
+
# indexes = [
|
|
36
|
+
# models.Index(fields=['latitude', 'longitude']),
|
|
37
|
+
# ]
|
|
38
|
+
|
|
39
|
+
def __str__(self):
|
|
40
|
+
# Provide more informative string representation
|
|
41
|
+
if self.latitude is not None and self.longitude is not None:
|
|
42
|
+
return f"Geocode for Order {self.order.code}: ({self.latitude:.4f}, {self.longitude:.4f})"
|
|
43
|
+
else:
|
|
44
|
+
return f"Geocode data for Order {self.order.code} (Coordinates: None)"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class MapMilestone(models.Model):
|
|
48
|
+
"""
|
|
49
|
+
Stores marketing milestones (e.g., newsletters, ad starts) for an event.
|
|
50
|
+
Used for visualization in the Sales Map timeline.
|
|
51
|
+
"""
|
|
52
|
+
event = models.ForeignKey(
|
|
53
|
+
'pretixbase.Event',
|
|
54
|
+
on_delete=models.CASCADE,
|
|
55
|
+
related_name='map_milestones'
|
|
56
|
+
)
|
|
57
|
+
date = models.DateField(
|
|
58
|
+
verbose_name="Date"
|
|
59
|
+
)
|
|
60
|
+
label = models.CharField(
|
|
61
|
+
max_length=200,
|
|
62
|
+
verbose_name="Milestone Label"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
class Meta:
|
|
66
|
+
ordering = ['date']
|
|
67
|
+
verbose_name = "Map Milestone"
|
|
68
|
+
verbose_name_plural = "Map Milestones"
|
|
69
|
+
|
|
70
|
+
def __str__(self):
|
|
71
|
+
return f"{self.date}: {self.label} ({self.event.slug})"
|
pretix_mapplugin/signals.py
CHANGED
|
@@ -1,92 +1,77 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from django.dispatch import receiver
|
|
3
|
-
from django.urls import reverse, NoReverseMatch
|
|
4
|
-
from django.utils.translation import gettext_lazy as _
|
|
5
|
-
from django.http import HttpRequest
|
|
6
|
-
from django.conf import settings
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# ---
|
|
15
|
-
from .
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
'organizer': request.organizer.slug,
|
|
79
|
-
'event': request.event.slug,
|
|
80
|
-
})
|
|
81
|
-
except NoReverseMatch:
|
|
82
|
-
logger.error(f"Could not reverse URL for map view '{MAP_VIEW_URL_NAME}'. Check urls.py.")
|
|
83
|
-
return []
|
|
84
|
-
is_active = False
|
|
85
|
-
if hasattr(request, 'resolver_match') and request.resolver_match:
|
|
86
|
-
is_active = request.resolver_match.view_name == MAP_VIEW_URL_NAME
|
|
87
|
-
return [{
|
|
88
|
-
'label': _('Sales Map'),
|
|
89
|
-
'url': map_url,
|
|
90
|
-
'active': is_active,
|
|
91
|
-
'icon': 'map-o',
|
|
92
|
-
}]
|
|
1
|
+
import logging
|
|
2
|
+
from django.dispatch import receiver
|
|
3
|
+
from django.urls import reverse, NoReverseMatch
|
|
4
|
+
from django.utils.translation import gettext_lazy as _
|
|
5
|
+
from django.http import HttpRequest
|
|
6
|
+
from django.conf import settings
|
|
7
|
+
from django.utils.timezone import now
|
|
8
|
+
from django.db import transaction
|
|
9
|
+
|
|
10
|
+
# --- Pretix Signals ---
|
|
11
|
+
from pretix.base.signals import order_placed, periodic_task
|
|
12
|
+
from pretix.control.signals import nav_event
|
|
13
|
+
|
|
14
|
+
# --- Tasks ---
|
|
15
|
+
from .tasks import geocode_order_task, nightly_reprocess_geocoding
|
|
16
|
+
# --- Geocoding Default ---
|
|
17
|
+
from .geocoding import DEFAULT_NOMINATIM_USER_AGENT
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
# --- Constants ---
|
|
22
|
+
MAP_VIEW_URL_NAME = 'plugins:pretix_mapplugin:event.settings.salesmap.show'
|
|
23
|
+
REQUIRED_MAP_PERMISSION = 'can_view_orders'
|
|
24
|
+
PLUGIN_NAME = 'pretix_mapplugin'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@receiver(periodic_task, dispatch_uid="sales_mapper_periodic_reprocess")
|
|
28
|
+
def trigger_nightly_geocoding(sender, **kwargs):
|
|
29
|
+
if now().hour == 3 and now().minute < 10:
|
|
30
|
+
nightly_reprocess_geocoding.apply_async()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@receiver(order_placed, dispatch_uid="sales_mapper_order_placed_geocode")
|
|
34
|
+
def trigger_geocoding_on_placement(sender, order, **kwargs):
|
|
35
|
+
"""
|
|
36
|
+
Queues geocoding after the current transaction is committed to avoid SQLite locks.
|
|
37
|
+
"""
|
|
38
|
+
user_agent = DEFAULT_NOMINATIM_USER_AGENT
|
|
39
|
+
if hasattr(settings, 'CONFIG_FILE') and settings.CONFIG_FILE.has_section('pretix_mapplugin'):
|
|
40
|
+
user_agent = settings.CONFIG_FILE.get('pretix_mapplugin', 'nominatim_user_agent', fallback=DEFAULT_NOMINATIM_USER_AGENT)
|
|
41
|
+
|
|
42
|
+
def run_task():
|
|
43
|
+
geocode_order_task.apply_async(
|
|
44
|
+
args=[order.pk],
|
|
45
|
+
kwargs={
|
|
46
|
+
'nominatim_user_agent': user_agent,
|
|
47
|
+
'organizer_pk': order.event.organizer.pk
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Crucial: Only run AFTER the order has been saved to DB
|
|
52
|
+
transaction.on_commit(run_task)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@receiver(nav_event, dispatch_uid="sales_mapper_nav_event_add_map")
|
|
56
|
+
def add_map_nav_item(sender, request: HttpRequest, **kwargs):
|
|
57
|
+
has_permission = request.user.has_event_permission(request.organizer, request.event, REQUIRED_MAP_PERMISSION, request=request)
|
|
58
|
+
if not has_permission: return []
|
|
59
|
+
try:
|
|
60
|
+
map_url = reverse(MAP_VIEW_URL_NAME, kwargs={'organizer': request.organizer.slug, 'event': request.event.slug})
|
|
61
|
+
milestone_url = reverse('plugins:pretix_mapplugin:event.settings.salesmap.milestones', kwargs={'organizer': request.organizer.slug, 'event': request.event.slug})
|
|
62
|
+
except NoReverseMatch:
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
is_active = request.resolver_match.view_name == MAP_VIEW_URL_NAME if request.resolver_match else False
|
|
66
|
+
is_milestone_active = request.resolver_match.view_name == 'plugins:pretix_mapplugin:event.settings.salesmap.milestones' if request.resolver_match else False
|
|
67
|
+
|
|
68
|
+
return [{
|
|
69
|
+
'label': _('Sales Map'),
|
|
70
|
+
'url': map_url,
|
|
71
|
+
'active': is_active or is_milestone_active,
|
|
72
|
+
'icon': 'map-o',
|
|
73
|
+
'children': [
|
|
74
|
+
{'label': _('Map View'), 'url': map_url, 'active': is_active},
|
|
75
|
+
{'label': _('Milestones'), 'url': milestone_url, 'active': is_milestone_active},
|
|
76
|
+
]
|
|
77
|
+
}]
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
.plugin-map-content-wrapper {
|
|
2
|
-
display: flex;
|
|
3
|
-
flex-direction: column;
|
|
4
|
-
height: calc(100vh - 100px);
|
|
5
|
-
min-height: 450px;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.plugin-map-content-wrapper h1,
|
|
9
|
-
.plugin-map-content-wrapper .form-group {
|
|
10
|
-
flex-shrink: 0;
|
|
11
|
-
margin-bottom: 1em;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.map-wrapper {
|
|
15
|
-
flex-grow: 1;
|
|
16
|
-
position: relative;
|
|
17
|
-
min-height: 0;
|
|
18
|
-
border: 1px solid #ccc;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
#sales-map-container {
|
|
22
|
-
height: 100%;
|
|
23
|
-
width: 100%;
|
|
24
|
-
display: block;
|
|
25
|
-
position: relative;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
#map-status-overlay {
|
|
29
|
-
position: absolute;
|
|
30
|
-
top: 0;
|
|
31
|
-
left: 0;
|
|
32
|
-
width: 100%;
|
|
33
|
-
height: 100%;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
#map-status-overlay p {
|
|
37
|
-
padding: 1em;
|
|
38
|
-
background: #fff;
|
|
39
|
-
border-radius: 5px;
|
|
40
|
-
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
#heatmap-options-panel input[type=range] {
|
|
44
|
-
width: 100%;
|
|
45
|
-
display: block;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
#map-status-overlay p.text-danger {
|
|
49
|
-
color: #a94442;
|
|
50
|
-
background-color: #f2dede;
|
|
51
|
-
border-color: #ebccd1;
|
|
1
|
+
.plugin-map-content-wrapper {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
height: calc(100vh - 100px);
|
|
5
|
+
min-height: 450px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.plugin-map-content-wrapper h1,
|
|
9
|
+
.plugin-map-content-wrapper .form-group {
|
|
10
|
+
flex-shrink: 0;
|
|
11
|
+
margin-bottom: 1em;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.map-wrapper {
|
|
15
|
+
flex-grow: 1;
|
|
16
|
+
position: relative;
|
|
17
|
+
min-height: 0;
|
|
18
|
+
border: 1px solid #ccc;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#sales-map-container {
|
|
22
|
+
height: 100%;
|
|
23
|
+
width: 100%;
|
|
24
|
+
display: block;
|
|
25
|
+
position: relative;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#map-status-overlay {
|
|
29
|
+
position: absolute;
|
|
30
|
+
top: 0;
|
|
31
|
+
left: 0;
|
|
32
|
+
width: 100%;
|
|
33
|
+
height: 100%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#map-status-overlay p {
|
|
37
|
+
padding: 1em;
|
|
38
|
+
background: #fff;
|
|
39
|
+
border-radius: 5px;
|
|
40
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#heatmap-options-panel input[type=range] {
|
|
44
|
+
width: 100%;
|
|
45
|
+
display: block;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#map-status-overlay p.text-danger {
|
|
49
|
+
color: #a94442;
|
|
50
|
+
background-color: #f2dede;
|
|
51
|
+
border-color: #ebccd1;
|
|
52
52
|
}
|