New SatNOGS DB user interface
Initial commit of new UI. There is still some work to be done before this goes into dev, but here is the work so far: * Updated dependencies to latest 2.x django * Updated to Bootstrap 4 * New home screen to display most recent satellite entries, most recent data, and contributors * Adopted django-bootstrap-modal-forms for handling satellite and transmitter creation and update, with more of an emphasis on django's model/view/form model - and a dynamic flow where the modals and details are only loaded when the proper icon is clicked, reducing the overall page size * Adopted AdminLTE 3.x framework atop Bootstrap 4 * Created reusable cards for satellite and transmitters * Cards and Modals are organized into subdirectories for template includes and base templates, respectively * New stats display widgets using BS4 and AdminLTE 3 * Satellite search is redesigned and now accessible from any page of the site * Introduced datatables for an "All Satellites" view and a modification of the new "All Transmitters" view * Focus on all UI scaling down to mobile devices * New model created for Operator (/ Owner): name, names, description, website * Added django-countries for support of CountryField * Satellite model expanded to include: Operator, (satellite) website, countries, launched datetime, deployed datetime * Transmitter suggestions can now be approved in the UI by superusers * Satellite entries can now be edited in the UI by users with the change satellite permission * Satellite page is now broken into 'tabbed' panels (Profile, Map, Transmitters, etc) - with the tab menu options appearing in the sidebar or at the top depending on screen size * Other cleanup and changes that I'm missing for sure. Signed-off-by: Corey Shields <cshields@gmail.com>spacecruft
|
@ -6,6 +6,7 @@ env
|
|||
.env
|
||||
.cache
|
||||
*.egg-info
|
||||
*.DS_Store
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.shortcuts import redirect
|
|||
from django.urls import reverse
|
||||
|
||||
from db.base.models import Artifact, DemodData, ExportedFrameset, Mode, \
|
||||
Satellite, Telemetry, Transmitter, TransmitterEntry, \
|
||||
Operator, Satellite, Telemetry, Transmitter, TransmitterEntry, \
|
||||
TransmitterSuggestion
|
||||
from db.base.tasks import check_celery, decode_all_data
|
||||
|
||||
|
@ -20,6 +20,13 @@ class ModeAdmin(admin.ModelAdmin):
|
|||
list_display = ('name', )
|
||||
|
||||
|
||||
@admin.register(Operator)
|
||||
class OperatorAdmin(admin.ModelAdmin):
|
||||
"""Defines Operator view in django admin UI"""
|
||||
list_display = ('name', 'names', 'website')
|
||||
search_fields = ('name', 'names')
|
||||
|
||||
|
||||
@admin.register(Satellite)
|
||||
class SatelliteAdmin(admin.ModelAdmin):
|
||||
"""Defines Satellite view in django admin UI"""
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"model": "base.operator",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Libre Space Foundation",
|
||||
"names": "LSF",
|
||||
"description": "The Libre Space Foundation promotes open source space technologies.",
|
||||
"website": "https://libre.space"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "base.operator",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "Radio Amateur Satellite Corporation",
|
||||
"names": "AMSAT",
|
||||
"description": "The goal of AMSAT is to foster Amateur Radio’s participation in space research and communication.",
|
||||
"website": "https://www.amsat.org"
|
||||
}
|
||||
}
|
||||
]
|
|
@ -1,9 +1,10 @@
|
|||
"""SatNOGS DB django base Forms class"""
|
||||
from django import forms
|
||||
from bootstrap_modal_forms.forms import BSModalModelForm
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.forms import NumberInput, TextInput
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from db.base.models import Transmitter, TransmitterEntry
|
||||
from db.base.models import Satellite, Transmitter, TransmitterEntry
|
||||
|
||||
|
||||
def existing_uuid(value):
|
||||
|
@ -18,15 +19,52 @@ def existing_uuid(value):
|
|||
)
|
||||
|
||||
|
||||
class TransmitterEntryForm(forms.ModelForm):
|
||||
class TransmitterModelForm(BSModalModelForm): # pylint: disable=too-many-ancestors
|
||||
"""Model Form class for TransmitterEntry objects"""
|
||||
|
||||
uuid = forms.CharField(required=False, validators=[existing_uuid])
|
||||
|
||||
class Meta:
|
||||
model = TransmitterEntry
|
||||
fields = [
|
||||
'description', 'status', 'type', 'uplink_low', 'uplink_high', 'downlink_low',
|
||||
'downlink_high', 'uplink_drift', 'downlink_drift', 'downlink_mode', 'uplink_mode',
|
||||
'invert', 'baud', 'satellite', 'citation', 'service'
|
||||
'invert', 'baud', 'citation', 'service'
|
||||
]
|
||||
widgets = {
|
||||
'description': TextInput(),
|
||||
}
|
||||
|
||||
|
||||
class TransmitterUpdateForm(BSModalModelForm): # pylint: disable=too-many-ancestors
|
||||
"""Model Form class for TransmitterEntry objects"""
|
||||
class Meta:
|
||||
model = TransmitterEntry
|
||||
fields = [
|
||||
'description', 'status', 'type', 'service', 'uplink_low', 'uplink_drift',
|
||||
'uplink_high', 'downlink_low', 'uplink_mode', 'downlink_drift', 'downlink_high',
|
||||
'downlink_mode', 'invert', 'baud', 'created', 'citation'
|
||||
]
|
||||
widgets = {
|
||||
'description': TextInput(),
|
||||
'created': TextInput(attrs={'readonly': True}),
|
||||
}
|
||||
|
||||
|
||||
class SatelliteModelForm(BSModalModelForm):
|
||||
"""Form that uses django-bootstrap-modal-forms for satellite editing"""
|
||||
class Meta:
|
||||
model = Satellite
|
||||
fields = [
|
||||
'norad_cat_id', 'name', 'names', 'operator', 'status', 'description', 'countries',
|
||||
'website', 'dashboard_url', 'launched', 'deployed', 'decayed', 'image'
|
||||
]
|
||||
labels = {
|
||||
'norad_cat_id': _('Norad ID'),
|
||||
'names': _('Other names'),
|
||||
'countries': _('Countries of Origin'),
|
||||
'launched': _('Launch Date'),
|
||||
'deployed': _('Deploy Date'),
|
||||
'decayed': _('Re-entry Date'),
|
||||
'description': _('Description'),
|
||||
'dashboard_url': _('Dashboard URL'),
|
||||
'operator': _('Owner/Operator'),
|
||||
}
|
||||
widgets = {'norad_cat_id': NumberInput(attrs={'readonly': True}), 'names': TextInput()}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# Generated by Django 2.2.14 on 2020-07-15 12:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_countries.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0018_artifact'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Operator',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True)),
|
||||
('names', models.TextField(blank=True)),
|
||||
('description', models.TextField(blank=True)),
|
||||
('website', models.URLField(blank=True)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='countries',
|
||||
field=django_countries.fields.CountryField(blank=True, max_length=746, multiple=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='deployed',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='launched',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='website',
|
||||
field=models.URLField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='satellite',
|
||||
name='operator',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='satellite_operator', to='base.Operator'),
|
||||
),
|
||||
]
|
|
@ -12,6 +12,7 @@ from django.db.models import OuterRef, Subquery
|
|||
from django.db.models.signals import post_save, pre_save
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.timezone import now
|
||||
from django_countries.fields import CountryField
|
||||
from markdown import markdown
|
||||
from shortuuidfield import ShortUUIDField
|
||||
|
||||
|
@ -86,6 +87,18 @@ class Mode(models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Operator(models.Model):
|
||||
"""Satellite Owner/Operator"""
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
names = models.TextField(blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
website = models.URLField(blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Satellite(models.Model):
|
||||
"""Model for all the satellites."""
|
||||
|
@ -103,6 +116,20 @@ class Satellite(models.Model):
|
|||
)
|
||||
decayed = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
# new fields below, metasat etc
|
||||
# countries is multiple for edge cases like ISS/Zarya
|
||||
countries = CountryField(blank=True, multiple=True, blank_label='(select countries)')
|
||||
website = models.URLField(blank=True)
|
||||
launched = models.DateTimeField(null=True, blank=True)
|
||||
deployed = models.DateTimeField(null=True, blank=True)
|
||||
operator = models.ForeignKey(
|
||||
Operator,
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='satellite_operator'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['norad_cat_id']
|
||||
|
||||
|
@ -182,6 +209,47 @@ class Satellite(models.Model):
|
|||
'redistributable': self.tle_redistributable
|
||||
}
|
||||
|
||||
@property
|
||||
def latest_data(self):
|
||||
"""Returns the latest DemodData for this Satellite
|
||||
|
||||
:returns: dict with most recent DemodData for this Satellite
|
||||
"""
|
||||
data = DemodData.objects.filter(satellite=self.id).order_by('-id')[:1]
|
||||
return {
|
||||
'data_id': data[0].data_id,
|
||||
'payload_frame': data[0].payload_frame,
|
||||
'timestamp': data[0].timestamp,
|
||||
'is_decoded': data[0].is_decoded,
|
||||
'station': data[0].station,
|
||||
'observer': data[0].observer,
|
||||
}
|
||||
|
||||
@property
|
||||
def needs_help(self):
|
||||
"""Returns a boolean based on whether or not this Satellite could
|
||||
use some editorial help based on a configurable threshold
|
||||
|
||||
:returns: bool
|
||||
"""
|
||||
score = 0
|
||||
if self.description and self.description != '':
|
||||
score += 1
|
||||
if self.countries and self.countries != '':
|
||||
score += 1
|
||||
if self.website and self.website != '':
|
||||
score += 1
|
||||
if self.names and self.names != '':
|
||||
score += 1
|
||||
if self.launched and self.launched != '':
|
||||
score += 1
|
||||
if self.operator and self.operator != '':
|
||||
score += 1
|
||||
if self.image and self.image != '':
|
||||
score += 1
|
||||
|
||||
return score <= 2
|
||||
|
||||
def __str__(self):
|
||||
return '{0} - {1}'.format(self.norad_cat_id, self.name)
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Django base URL routings for SatNOGS DB"""
|
||||
from django.conf.urls import url
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.urls import path
|
||||
|
||||
from db.base import views
|
||||
|
||||
|
@ -7,8 +9,8 @@ BASE_URLPATTERNS = (
|
|||
[
|
||||
url(r'^$', views.home, name='home'),
|
||||
url(r'^about/$', views.about, name='about'),
|
||||
url(r'^transmitters/$', views.transmitters_list, name='transmitters_list'),
|
||||
url(r'^faq/$', views.faq, name='faq'),
|
||||
url(r'^satellites/$', views.satellites, name='satellites'),
|
||||
url(r'^satellite/(?P<norad>[0-9]+)/$', views.satellite, name='satellite'),
|
||||
url(r'^frames/(?P<norad>[0-9]+)/$', views.request_export, name='request_export_all'),
|
||||
url(
|
||||
|
@ -16,14 +18,32 @@ BASE_URLPATTERNS = (
|
|||
views.request_export,
|
||||
name='request_export'
|
||||
),
|
||||
url(r'^help/$', views.satnogs_help, name='help'),
|
||||
url(
|
||||
r'^transmitter_suggestion/$',
|
||||
views.transmitter_suggestion,
|
||||
name='transmitter_suggestion'
|
||||
r'^transmitter_suggestion_handler/$',
|
||||
views.transmitter_suggestion_handler,
|
||||
name='transmitter_suggestion_handler'
|
||||
),
|
||||
url(r'^transmitters/$', views.transmitters_list, name='transmitters_list'),
|
||||
url(r'^statistics/$', views.statistics, name='statistics'),
|
||||
url(r'^stats/$', views.stats, name='stats'),
|
||||
url(r'^users/edit/$', views.users_edit, name='users_edit'),
|
||||
url(r'^robots\.txt$', views.robots, name='robots'),
|
||||
url(r'^search/$', views.search, name='search_results'),
|
||||
url(
|
||||
r'^update_satellite/(?P<pk>[0-9]+)/$',
|
||||
permission_required('base.change_satellite')(views.SatelliteUpdateView.as_view()),
|
||||
name='update_satellite'
|
||||
),
|
||||
path(
|
||||
'create_transmitter/<int:satellite_pk>',
|
||||
views.TransmitterCreateView.as_view(),
|
||||
name='create_transmitter'
|
||||
),
|
||||
path(
|
||||
'update_transmitter/<int:pk>',
|
||||
views.TransmitterUpdateView.as_view(),
|
||||
name='update_transmitter'
|
||||
),
|
||||
]
|
||||
)
|
||||
|
|
338
db/base/views.py
|
@ -1,40 +1,62 @@
|
|||
"""Base django views for SatNOGS DB"""
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from bootstrap_modal_forms.generic import BSModalCreateView, BSModalUpdateView
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, \
|
||||
PermissionRequiredMixin
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import OperationalError
|
||||
from django.db.models import Count
|
||||
from django.db.models import Count, Max, Q
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from db.base.forms import TransmitterEntryForm
|
||||
from db.base.forms import SatelliteModelForm, TransmitterModelForm, \
|
||||
TransmitterUpdateForm
|
||||
from db.base.helpers import get_apikey
|
||||
from db.base.models import SERVICE_TYPE, TRANSMITTER_STATUS, \
|
||||
TRANSMITTER_TYPE, DemodData, Mode, Satellite, Transmitter, \
|
||||
TransmitterSuggestion
|
||||
TransmitterEntry, TransmitterSuggestion
|
||||
from db.base.tasks import export_frames
|
||||
from db.base.utils import cache_statistics
|
||||
|
||||
LOGGER = logging.getLogger('db')
|
||||
|
||||
|
||||
def superuser_check(user):
|
||||
"""Returns True if user is a superuser, for use with @user_passes_test
|
||||
"""
|
||||
return user.is_superuser
|
||||
|
||||
|
||||
def home(request):
|
||||
"""View to render home page.
|
||||
|
||||
:returns: base/home.html
|
||||
"""
|
||||
satellites = Satellite.objects.annotate(transmitters_count=Count('transmitter_entries'))
|
||||
transmitter_suggestions = TransmitterSuggestion.objects.count()
|
||||
contributors = User.objects.filter(is_active=1).count()
|
||||
newest_sats = Satellite.objects.all().order_by('-id')[:5].annotate(
|
||||
transmitters_count=Count('transmitter_entries')
|
||||
)
|
||||
latest_data = Satellite.objects.annotate(
|
||||
latest=Max('telemetry_data__timestamp'), transmitters_count=Count('transmitter_entries')
|
||||
).order_by('-latest')[:5]
|
||||
|
||||
# Calculate latest contributors
|
||||
date_from = timezone.now() - timedelta(days=1)
|
||||
latest_submitters = DemodData.objects.filter(timestamp__gte=date_from
|
||||
).values('station').annotate(c=Count('station')
|
||||
).order_by('-c')
|
||||
|
||||
suggestion_count = TransmitterSuggestion.objects.count()
|
||||
contributor_count = User.objects.filter(is_active=1).count()
|
||||
cached_stats = cache.get('stats_transmitters')
|
||||
if not cached_stats:
|
||||
try:
|
||||
|
@ -44,10 +66,12 @@ def home(request):
|
|||
pass
|
||||
return render(
|
||||
request, 'base/home.html', {
|
||||
'satellites': satellites,
|
||||
'newest_sats': newest_sats,
|
||||
'latest_data': latest_data,
|
||||
'latest_submitters': latest_submitters,
|
||||
'statistics': cached_stats,
|
||||
'contributors': contributors,
|
||||
'transmitter_suggestions': transmitter_suggestions
|
||||
'contributor_count': contributor_count,
|
||||
'suggestion_count': suggestion_count
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -72,6 +96,33 @@ def robots(request):
|
|||
return response
|
||||
|
||||
|
||||
def satellites(request):
|
||||
"""View to render satellites page.
|
||||
|
||||
:returns: base/satellites.html
|
||||
"""
|
||||
satellite_objects = Satellite.objects.annotate(
|
||||
transmitters_count=Count('transmitter_entries')
|
||||
).prefetch_related('operator')
|
||||
suggestion_count = TransmitterSuggestion.objects.count()
|
||||
contributor_count = User.objects.filter(is_active=1).count()
|
||||
cached_stats = cache.get('stats_transmitters')
|
||||
if not cached_stats:
|
||||
try:
|
||||
cache_statistics()
|
||||
cached_stats = cache.get('stats_transmitters')
|
||||
except OperationalError:
|
||||
pass
|
||||
return render(
|
||||
request, 'base/satellites.html', {
|
||||
'satellites': satellite_objects,
|
||||
'statistics': cached_stats,
|
||||
'contributor_count': contributor_count,
|
||||
'suggestion_count': suggestion_count
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def satellite(request, norad):
|
||||
"""View to render satellite page.
|
||||
|
||||
|
@ -132,68 +183,106 @@ def request_export(request, norad, period=None):
|
|||
return redirect(reverse('satellite', kwargs={'norad': norad}))
|
||||
|
||||
|
||||
# <cshields> leaving this in place for reference while the New UI is fixed up
|
||||
# and the functionality below is moved into new modals accordingly.
|
||||
# @login_required
|
||||
# @require_POST
|
||||
# def transmitter_suggestion(request):
|
||||
# """View to process transmitter suggestion form
|
||||
|
||||
# :returns: the originating satellite page unless an error occurs
|
||||
# """
|
||||
# transmitter_form = TransmitterEntryForm(request.POST)
|
||||
# if transmitter_form.is_valid():
|
||||
# transmitter = transmitter_form.save(commit=False)
|
||||
# transmitter.user = request.user
|
||||
# transmitter.reviewed = False
|
||||
# transmitter.approved = False
|
||||
# uuid = transmitter_form.cleaned_data['uuid']
|
||||
# if uuid:
|
||||
# transmitter.uuid = uuid
|
||||
# transmitter.save()
|
||||
|
||||
# # Notify admins
|
||||
# admins = User.objects.filter(is_superuser=True)
|
||||
# site = get_current_site(request)
|
||||
# subject = '[{0}] A new suggestion for {1} was submitted'.format(
|
||||
# site.name, transmitter.satellite.name
|
||||
# )
|
||||
# template = 'emails/new_transmitter_suggestion.txt'
|
||||
# saturl = '{0}{1}'.format(
|
||||
# site.domain,
|
||||
# reverse('satellite', kwargs={'norad': transmitter.satellite.norad_cat_id})
|
||||
# )
|
||||
# data = {
|
||||
# 'satname': transmitter.satellite.name,
|
||||
# 'saturl': saturl,
|
||||
# 'sitedomain': site.domain,
|
||||
# 'contributor': transmitter.user
|
||||
# }
|
||||
# message = render_to_string(template, {'data': data})
|
||||
# for user in admins:
|
||||
# try:
|
||||
# user.email_user(subject, message, from_email=settings.DEFAULT_FROM_EMAIL)
|
||||
# except Exception: # pylint: disable=W0703
|
||||
# LOGGER.error('Could not send email to user', exc_info=True)
|
||||
|
||||
# messages.success(
|
||||
# request,
|
||||
# ('Your transmitter suggestion was stored successfully. '
|
||||
# 'Thanks for contibuting!')
|
||||
# )
|
||||
# redirect_page = redirect(
|
||||
# reverse('satellite', kwargs={'norad': transmitter.satellite.norad_cat_id})
|
||||
# )
|
||||
# else:
|
||||
# LOGGER.error(
|
||||
# 'Suggestion form was not valid %s',
|
||||
# format(transmitter_form.errors),
|
||||
# exc_info=True,
|
||||
# extra={
|
||||
# 'form': transmitter_form.errors,
|
||||
# }
|
||||
# )
|
||||
# messages.error(request, 'We are sorry, but some error occured :(')
|
||||
# redirect_page = redirect(reverse('home'))
|
||||
|
||||
# return redirect_page
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def transmitter_suggestion(request):
|
||||
"""View to process transmitter suggestion form
|
||||
@user_passes_test(superuser_check)
|
||||
def transmitter_suggestion_handler(request):
|
||||
"""Returns the Satellite page after approving or rejecting a suggestion
|
||||
|
||||
:returns: the originating satellite page unless an error occurs
|
||||
:returns: Satellite page
|
||||
"""
|
||||
transmitter_form = TransmitterEntryForm(request.POST)
|
||||
if transmitter_form.is_valid():
|
||||
transmitter = transmitter_form.save(commit=False)
|
||||
transmitter.user = request.user
|
||||
transmitter.reviewed = False
|
||||
transmitter = TransmitterSuggestion.objects.get(uuid=request.POST['uuid'])
|
||||
if 'approve' in request.POST:
|
||||
transmitter.approved = True
|
||||
messages.success(request, ('Transmitter approved.'))
|
||||
elif 'reject' in request.POST:
|
||||
transmitter.approved = False
|
||||
uuid = transmitter_form.cleaned_data['uuid']
|
||||
if uuid:
|
||||
transmitter.uuid = uuid
|
||||
messages.success(request, ('Transmitter rejected.'))
|
||||
transmitter.reviewed = True
|
||||
transmitter.created = timezone.now()
|
||||
transmitter.user = request.user
|
||||
|
||||
# Need to determine if we will attribute the suggestion or the approval
|
||||
# transmitter.user = request.user
|
||||
|
||||
transmitter.save()
|
||||
|
||||
# Notify admins
|
||||
admins = User.objects.filter(is_superuser=True)
|
||||
site = get_current_site(request)
|
||||
subject = '[{0}] A new suggestion for {1} was submitted'.format(
|
||||
site.name, transmitter.satellite.name
|
||||
)
|
||||
template = 'emails/new_transmitter_suggestion.txt'
|
||||
saturl = '{0}{1}'.format(
|
||||
site.domain,
|
||||
reverse('satellite', kwargs={'norad': transmitter.satellite.norad_cat_id})
|
||||
)
|
||||
data = {
|
||||
'satname': transmitter.satellite.name,
|
||||
'saturl': saturl,
|
||||
'sitedomain': site.domain,
|
||||
'contributor': transmitter.user
|
||||
}
|
||||
message = render_to_string(template, {'data': data})
|
||||
for user in admins:
|
||||
try:
|
||||
user.email_user(subject, message, from_email=settings.DEFAULT_FROM_EMAIL)
|
||||
except Exception: # pylint: disable=W0703
|
||||
LOGGER.error('Could not send email to user', exc_info=True)
|
||||
|
||||
messages.success(
|
||||
request,
|
||||
('Your transmitter suggestion was stored successfully. '
|
||||
'Thanks for contibuting!')
|
||||
# the way we handle suggestions in admin is to update the suggestion as
|
||||
# reviewed and save a new object. This feels hacky but preserves the
|
||||
# admin workflow
|
||||
TransmitterSuggestion.objects.filter(uuid=request.POST['uuid']).update(
|
||||
reviewed=True, approved=transmitter.approved
|
||||
)
|
||||
redirect_page = redirect(
|
||||
reverse('satellite', kwargs={'norad': transmitter.satellite.norad_cat_id})
|
||||
)
|
||||
else:
|
||||
LOGGER.error(
|
||||
'Suggestion form was not valid %s',
|
||||
format(transmitter_form.errors),
|
||||
exc_info=True,
|
||||
extra={
|
||||
'form': transmitter_form.errors,
|
||||
}
|
||||
)
|
||||
messages.error(request, 'We are sorry, but some error occured :(')
|
||||
redirect_page = redirect(reverse('home'))
|
||||
|
||||
return redirect_page
|
||||
|
||||
|
||||
|
@ -213,25 +302,68 @@ def faq(request):
|
|||
return render(request, 'base/faq.html')
|
||||
|
||||
|
||||
def satnogs_help(request):
|
||||
"""View to render help modal. Have to avoid builtin 'help' name
|
||||
|
||||
:returns: base/modals/help.html
|
||||
"""
|
||||
return render(request, 'base/modals/satnogs_help.html')
|
||||
|
||||
|
||||
def search(request):
|
||||
"""View to render search page.
|
||||
|
||||
:returns: base/search.html
|
||||
"""
|
||||
if ('q' in request.GET) and request.GET['q'].strip():
|
||||
query_string = request.GET['q']
|
||||
|
||||
results = Satellite.objects.filter(
|
||||
Q(name__icontains=query_string) | Q(names__icontains=query_string)
|
||||
| Q(norad_cat_id__icontains=query_string) # noqa: W503 google W503 it is evil
|
||||
).order_by('name').annotate(transmitters_count=Count('transmitter_entries'))
|
||||
|
||||
if results.count() == 1:
|
||||
return redirect(reverse('satellite', kwargs={'norad': results[0].norad_cat_id}))
|
||||
|
||||
# else (no-else-return)
|
||||
return render(request, 'base/search.html', {
|
||||
'results': results,
|
||||
})
|
||||
|
||||
|
||||
def stats(request):
|
||||
"""View to render stats page.
|
||||
|
||||
:returns: base/stats.html
|
||||
"""
|
||||
satellites = []
|
||||
cached_satellites = []
|
||||
ids = cache.get('satellites_ids')
|
||||
observers = cache.get('stats_observers')
|
||||
suggestion_count = TransmitterSuggestion.objects.count()
|
||||
contributor_count = User.objects.filter(is_active=1).count()
|
||||
cached_stats = cache.get('stats_transmitters')
|
||||
if not ids or not observers:
|
||||
try:
|
||||
cache_statistics()
|
||||
cached_stats = cache.get('stats_transmitters')
|
||||
ids = cache.get('satellites_ids')
|
||||
observers = cache.get('stats_observers')
|
||||
except OperationalError:
|
||||
pass
|
||||
else:
|
||||
for sid in ids:
|
||||
stat = cache.get(sid['id'])
|
||||
satellites.append(stat)
|
||||
cached_satellites.append(stat)
|
||||
|
||||
return render(request, 'base/stats.html', {'satellites': satellites, 'observers': observers})
|
||||
return render(
|
||||
request, 'base/stats.html', {
|
||||
'satellites': cached_satellites,
|
||||
'observers': observers,
|
||||
'statistics': cached_stats,
|
||||
'contributor_count': contributor_count,
|
||||
'suggestion_count': suggestion_count,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def statistics(request):
|
||||
|
@ -253,4 +385,74 @@ def users_edit(request):
|
|||
:returns: base/users_edit.html
|
||||
"""
|
||||
token = get_apikey(request.user)
|
||||
return render(request, 'base/users_edit.html', {'token': token})
|
||||
return render(request, 'base/modals/users_edit.html', {'token': token})
|
||||
|
||||
|
||||
class TransmitterCreateView(LoginRequiredMixin, BSModalCreateView):
|
||||
"""A django-bootstrap-modal-forms view for creating transmitter suggestions"""
|
||||
template_name = 'base/modals/transmitter_create.html'
|
||||
model = TransmitterEntry
|
||||
form_class = TransmitterModelForm
|
||||
success_message = 'Your transmitter suggestion was stored successfully and will be \
|
||||
reviewed by a moderator. Thanks for contibuting!'
|
||||
|
||||
satellite = Satellite()
|
||||
user = User()
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
"""
|
||||
Overridden so we can make sure the `Satellite` instance exists first
|
||||
"""
|
||||
self.satellite = get_object_or_404(Satellite, pk=kwargs['satellite_pk'])
|
||||
self.user = request.user
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
"""
|
||||
Overridden to add the `Satellite` relation to the `Transmitter` instance.
|
||||
"""
|
||||
form.instance.satellite = self.satellite
|
||||
form.instance.user = self.user
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return self.request.META.get('HTTP_REFERER')
|
||||
|
||||
|
||||
class TransmitterUpdateView(LoginRequiredMixin, BSModalUpdateView):
|
||||
"""A django-bootstrap-modal-forms view for updating transmitter entries"""
|
||||
template_name = 'base/modals/transmitter_update.html'
|
||||
model = TransmitterEntry
|
||||
form_class = TransmitterUpdateForm
|
||||
success_message = 'Your transmitter suggestion was stored successfully and will be \
|
||||
reviewed by a moderator. Thanks for contibuting!'
|
||||
|
||||
user = User()
|
||||
|
||||
def get_initial(self):
|
||||
initial = {}
|
||||
initial['created'] = timezone.now()
|
||||
return initial
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.user = request.user
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.user = self.user
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return self.request.META.get('HTTP_REFERER')
|
||||
|
||||
|
||||
class SatelliteUpdateView(PermissionRequiredMixin, BSModalUpdateView):
|
||||
"""A django-bootstrap-modal-forms view for updating satellite fields"""
|
||||
permission_required = 'base.change_satellite'
|
||||
model = Satellite
|
||||
template_name = 'base/modals/satellite_update.html'
|
||||
form_class = SatelliteModelForm
|
||||
success_message = 'Satellite was updated.'
|
||||
|
||||
def get_success_url(self):
|
||||
return self.request.META.get('HTTP_REFERER')
|
||||
|
|
|
@ -30,9 +30,13 @@ DJANGO_APPS = (
|
|||
)
|
||||
THIRD_PARTY_APPS = (
|
||||
'avatar',
|
||||
'bootstrap_modal_forms',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'django_countries',
|
||||
'django_filters',
|
||||
'fontawesome_5',
|
||||
'widget_tweaks',
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
|
@ -159,8 +163,8 @@ STATICFILES_FINDERS = (
|
|||
MEDIA_ROOT = config('MEDIA_ROOT', default=Path('media').resolve())
|
||||
FILE_UPLOAD_TEMP_DIR = config('FILE_UPLOAD_TEMP_DIR', default=Path('/tmp').resolve())
|
||||
MEDIA_URL = config('MEDIA_URL', default='/media/')
|
||||
CRISPY_TEMPLATE_PACK = 'bootstrap3'
|
||||
SATELLITE_DEFAULT_IMAGE = '/static/img/sat.png'
|
||||
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
||||
SATELLITE_DEFAULT_IMAGE = '/static/img/sat_purple.png'
|
||||
COMPRESS_ENABLED = config('COMPRESS_ENABLED', default=False, cast=bool)
|
||||
COMPRESS_OFFLINE = config('COMPRESS_OFFLINE', default=False, cast=bool)
|
||||
COMPRESS_CACHE_BACKEND = config('COMPRESS_CACHE_BACKEND', default='default')
|
||||
|
@ -279,6 +283,9 @@ CSP_DEFAULT_SRC = config(
|
|||
cast=lambda v: tuple(s.strip() for s in v.split(',')),
|
||||
default="'self',"
|
||||
'https://*.mapbox.com,'
|
||||
'https://kit-free.fontawesome.com,'
|
||||
'https://ka-f.fontawesome.com,'
|
||||
'https://fonts.gstatic.com,'
|
||||
"'unsafe-inline'"
|
||||
)
|
||||
CSP_SCRIPT_SRC = config(
|
||||
|
@ -286,8 +293,8 @@ CSP_SCRIPT_SRC = config(
|
|||
cast=lambda v: tuple(s.strip() for s in v.split(',')),
|
||||
default="'self',"
|
||||
'https://*.google-analytics.com,'
|
||||
"'unsafe-eval',"
|
||||
"'unsafe-inline'"
|
||||
'https://kit-free.fontawesome.com,'
|
||||
'https://kit.fontawesome.com,'
|
||||
)
|
||||
CSP_IMG_SRC = config(
|
||||
'CSP_IMG_SRC',
|
||||
|
@ -302,6 +309,12 @@ CSP_IMG_SRC = config(
|
|||
CSP_FRAME_SRC = config(
|
||||
'CSP_FRAME_SRC', cast=lambda v: tuple(s.strip() for s in v.split(',')), default='blob:'
|
||||
)
|
||||
CSP_WORKER_SRC = config(
|
||||
'CSP_WORKER_SRC',
|
||||
cast=lambda v: tuple(s.strip() for s in v.split(',')),
|
||||
default="'self',"
|
||||
'blob:'
|
||||
)
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
SECURE_BROWSER_XSS_FILTER = True
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
@font-face {
|
||||
font-family: ClearSans;
|
||||
src: url('../fonts/ClearSans-Regular.eot');
|
||||
src: url('../fonts/ClearSans-Regular.eot?#iefix') format('embedded-opentype'),
|
||||
src: url('../fonts/ClearSans-Regular.eot?#iefix')
|
||||
format('embedded-opentype'),
|
||||
url('../fonts/ClearSans-Regular.woff') format('woff'),
|
||||
url('../fonts/ClearSans-Regular.ttf') format('truetype'),
|
||||
url('../fonts/ClearSans-Regular.svg#open_sans') format('svg');
|
||||
|
@ -26,10 +27,12 @@
|
|||
@font-face {
|
||||
font-family: ClearSans;
|
||||
src: url('../fonts/ClearSans-BoldItalic.eot');
|
||||
src: url('../fonts/ClearSans-BoldItalic.eot?#iefix') format('embedded-opentype'),
|
||||
src: url('../fonts/ClearSans-BoldItalic.eot?#iefix')
|
||||
format('embedded-opentype'),
|
||||
url('../fonts/ClearSans-BoldItalic.woff') format('woff'),
|
||||
url('../fonts/ClearSans-BoldItalic.ttf') format('truetype'),
|
||||
url('../fonts/ClearSans-BoldItalic.svg#open_sansbold_italic') format('svg');
|
||||
url('../fonts/ClearSans-BoldItalic.svg#open_sansbold_italic')
|
||||
format('svg');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
@ -48,12 +51,6 @@
|
|||
/* Generic
|
||||
==================== */
|
||||
|
||||
body {
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
font-family: ClearSans;
|
||||
}
|
||||
|
||||
.alert-debug {
|
||||
color: black;
|
||||
background-color: white;
|
||||
|
@ -112,13 +109,13 @@ body {
|
|||
}
|
||||
|
||||
#search {
|
||||
margin: auto;
|
||||
margin: 15px auto;
|
||||
}
|
||||
|
||||
.statistics {
|
||||
text-align: center;
|
||||
text-shadow: 1px 1px 2px rgba(150, 150, 150, 0.77);
|
||||
margin-top: 12px;
|
||||
margin: 12px auto auto auto;
|
||||
display: inline-block;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
@ -166,6 +163,7 @@ a.satellite-item:hover {
|
|||
min-height: 30px;
|
||||
padding-top: 5px;
|
||||
display: inline-block;
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.satellite-title .badge {
|
||||
|
@ -192,7 +190,7 @@ a.satellite-item:hover {
|
|||
}
|
||||
|
||||
.satellite-status {
|
||||
font-size: .9em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.satellite-status[data-status='alive'] {
|
||||
|
@ -218,7 +216,9 @@ a.satellite-item:hover {
|
|||
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
/* height: 250px; */
|
||||
height: 100%;
|
||||
min-height: 250px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
|
@ -232,13 +232,13 @@ a.satellite-item:hover {
|
|||
}
|
||||
|
||||
.satellite-img-full {
|
||||
width: 100%;
|
||||
/* width: 100%; */
|
||||
max-height: 250px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.panel-transmitter {
|
||||
margin: 20px 0;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.panel-tle {
|
||||
|
@ -250,18 +250,14 @@ a.satellite-item:hover {
|
|||
}
|
||||
|
||||
.suggest-transmitter {
|
||||
margin-top: -6px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.transmitter-uuid {
|
||||
margin-top: -6px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.transmitter-citation {
|
||||
/* .transmitter-citation {
|
||||
margin-top: -8px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
margin: 6px 10px 6px 10px;
|
||||
} */
|
||||
|
||||
.transmitter-suggestions-counter {
|
||||
display: inline-block;
|
||||
|
@ -277,12 +273,19 @@ a.satellite-item:hover {
|
|||
margin: 10px;
|
||||
}
|
||||
|
||||
.transmitter-badge {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.transmitter-element-suggest {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.transmitter-citation-footer {
|
||||
font-size: .8em;
|
||||
.transmitter-card-footer {
|
||||
font-size: 0.8em;
|
||||
height: 100%;
|
||||
padding: 6px 10px 6px 10px;
|
||||
background-color: var(--satnogs-color-white);
|
||||
}
|
||||
|
||||
.tle-element {
|
||||
|
@ -364,7 +367,7 @@ footer {
|
|||
============================= */
|
||||
|
||||
.chart text {
|
||||
color: #333;
|
||||
color: var(--satnogs-color-dark);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
@ -401,7 +404,8 @@ svg.chart {
|
|||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.tick line, .domain {
|
||||
.tick line,
|
||||
.domain {
|
||||
fill: none;
|
||||
stroke: #ddd;
|
||||
}
|
||||
|
@ -411,3 +415,583 @@ svg.chart {
|
|||
stroke: #286090;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
/* New UI CSS
|
||||
============= */
|
||||
|
||||
/* Theme */
|
||||
|
||||
.bg-gradient-primary {
|
||||
background-color: #4e73df;
|
||||
background-image: linear-gradient(180deg, #4e73df 10%, #224abe 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gradient-secondary {
|
||||
background-color: #858796;
|
||||
background-image: linear-gradient(180deg, #858796 10%, #60616f 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gradient-success {
|
||||
background-color: #1cc88a;
|
||||
background-image: linear-gradient(180deg, #1cc88a 10%, #13855c 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gradient-info {
|
||||
background-color: #36b9cc;
|
||||
background-image: linear-gradient(180deg, #36b9cc 10%, #258391 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gradient-warning {
|
||||
background-color: #f6c23e;
|
||||
background-image: linear-gradient(180deg, #f6c23e 10%, #dda20a 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gradient-danger {
|
||||
background-color: #e74a3b;
|
||||
background-image: linear-gradient(180deg, #e74a3b 10%, #be2617 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gradient-light {
|
||||
background-color: #f8f9fc;
|
||||
background-image: linear-gradient(180deg, #f8f9fc 10%, #c2cbe5 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gradient-dark {
|
||||
background-color: #5a5c69;
|
||||
background-image: linear-gradient(180deg, #5a5c69 10%, #373840 100%);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bg-gray-100 {
|
||||
background-color: #f8f9fc;
|
||||
}
|
||||
|
||||
.bg-gray-200 {
|
||||
background-color: #eaecf4;
|
||||
}
|
||||
|
||||
.bg-gray-300 {
|
||||
background-color: #dddfeb;
|
||||
}
|
||||
|
||||
.bg-gray-400 {
|
||||
background-color: #d1d3e2;
|
||||
}
|
||||
|
||||
.bg-gray-500 {
|
||||
background-color: #b7b9cc;
|
||||
}
|
||||
|
||||
.bg-gray-600 {
|
||||
background-color: #858796;
|
||||
}
|
||||
|
||||
.bg-gray-700 {
|
||||
background-color: #6e707e;
|
||||
}
|
||||
|
||||
.bg-gray-800 {
|
||||
background-color: #5a5c69;
|
||||
}
|
||||
|
||||
.bg-gray-900 {
|
||||
background-color: #3a3b45;
|
||||
}
|
||||
|
||||
.o-hidden {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.text-gray-100 {
|
||||
color: #f8f9fc;
|
||||
}
|
||||
|
||||
.text-gray-200 {
|
||||
color: #eaecf4;
|
||||
}
|
||||
|
||||
.text-gray-300 {
|
||||
color: #dddfeb;
|
||||
}
|
||||
|
||||
.text-gray-400 {
|
||||
color: #d1d3e2;
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
color: #b7b9cc;
|
||||
}
|
||||
|
||||
.text-gray-600 {
|
||||
color: #858796;
|
||||
}
|
||||
|
||||
.text-gray-700 {
|
||||
color: #6e707e;
|
||||
}
|
||||
|
||||
.text-gray-800 {
|
||||
color: #5a5c69;
|
||||
}
|
||||
|
||||
.text-gray-900 {
|
||||
color: #3a3b45;
|
||||
}
|
||||
|
||||
.icon-circle {
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
border-radius: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.border-left-primary {
|
||||
border-left: 0.25rem solid var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.border-bottom-primary {
|
||||
border-bottom: 0.25rem solid var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.border-left-active {
|
||||
border-left: 0.25rem solid #dff0d8;
|
||||
/* color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
border-color: #d6e9c6; */
|
||||
}
|
||||
|
||||
.border-left-secondary {
|
||||
border-left: 0.25rem solid #858796;
|
||||
}
|
||||
|
||||
.border-bottom-secondary {
|
||||
border-bottom: 0.25rem solid #858796;
|
||||
}
|
||||
|
||||
.border-left-success {
|
||||
border-left: 0.25rem solid #1cc88a;
|
||||
}
|
||||
|
||||
.border-bottom-success {
|
||||
border-bottom: 0.25rem solid #1cc88a;
|
||||
}
|
||||
|
||||
.border-left-info {
|
||||
border-left: 0.25rem solid #36b9cc;
|
||||
}
|
||||
|
||||
.border-bottom-info {
|
||||
border-bottom: 0.25rem solid #36b9cc;
|
||||
}
|
||||
|
||||
.border-left-warning {
|
||||
border-left: 0.25rem solid #f6c23e;
|
||||
}
|
||||
|
||||
.border-bottom-warning {
|
||||
border-bottom: 0.25rem solid #f6c23e;
|
||||
}
|
||||
|
||||
.border-left-danger {
|
||||
border-left: 0.25rem solid #e74a3b;
|
||||
}
|
||||
|
||||
.border-bottom-danger {
|
||||
border-bottom: 0.25rem solid #e74a3b;
|
||||
}
|
||||
|
||||
.border-left-light {
|
||||
border-left: 0.25rem solid #f8f9fc;
|
||||
}
|
||||
|
||||
.border-bottom-light {
|
||||
border-bottom: 0.25rem solid #f8f9fc;
|
||||
}
|
||||
|
||||
.border-left-dark {
|
||||
border-left: 0.25rem solid #5a5c69;
|
||||
}
|
||||
|
||||
.border-bottom-dark {
|
||||
border-bottom: 0.25rem solid #5a5c69;
|
||||
}
|
||||
|
||||
@-webkit-keyframes grow_in {
|
||||
|
||||
0% {
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes grow_in {
|
||||
|
||||
0% {
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.animated--grow-in,
|
||||
.sidebar .nav-item .collapse {
|
||||
-webkit-animation-name: grow_in;
|
||||
animation-name: grow_in;
|
||||
-webkit-animation-duration: 200ms;
|
||||
animation-duration: 200ms;
|
||||
-webkit-animation-timing-function: transform
|
||||
cubic-bezier(0.18, 1.25, 0.4, 1),
|
||||
opacity cubic-bezier(0, 1, 0.4, 1);
|
||||
animation-timing-function: transform cubic-bezier(0.18, 1.25, 0.4, 1),
|
||||
opacity cubic-bezier(0, 1, 0.4, 1);
|
||||
}
|
||||
|
||||
@-webkit-keyframes fade_in {
|
||||
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade_in {
|
||||
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.animated--fade-in {
|
||||
-webkit-animation-name: fade_in;
|
||||
animation-name: fade_in;
|
||||
-webkit-animation-duration: 200ms;
|
||||
animation-duration: 200ms;
|
||||
-webkit-animation-timing-function: opacity cubic-bezier(0, 1, 0.4, 1);
|
||||
animation-timing-function: opacity cubic-bezier(0, 1, 0.4, 1);
|
||||
}
|
||||
|
||||
#satnogs-menu {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
height: 30px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#satnogs-navbar {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.satnogs-navbar-link {
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
font-family: Roboto, Helvetica, Arial, sans-serif;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1.6px;
|
||||
font-size: 13px;
|
||||
color: var(--satnogs-color-white);
|
||||
}
|
||||
|
||||
.satnogs-navbar-link:hover {
|
||||
text-decoration: none;
|
||||
color: var(--satnogs-color-white);
|
||||
}
|
||||
|
||||
#db-menu {
|
||||
background-color: var(--satnogs-color-menu-background);
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#db-menu-col {
|
||||
height: 30px;
|
||||
/* border-color: var(--satnogs-color-primary); */
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#db-menu-navbar {
|
||||
/* border-color: var(--satnogs-color-primary); */
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.db-menu-link {
|
||||
font-family: Roboto, Helvetica, Arial, sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
letter-spacing: 1.6px;
|
||||
height: 30px;
|
||||
padding-left: 0;
|
||||
/* color: rgba(0,0,0,0.5); */
|
||||
color: var(--satnogs-color-menu-text);
|
||||
}
|
||||
|
||||
.db-menu-link:hover {
|
||||
text-decoration: none;
|
||||
color: var(--satnogs-color-menu-hover);
|
||||
}
|
||||
|
||||
.satnogs-card-header {
|
||||
padding: 5px 15px 5px 15px;
|
||||
height: 100%;
|
||||
background-color: var(--satnogs-color-header);
|
||||
border-color: var(--satnogs-color-border);
|
||||
}
|
||||
|
||||
.satnogs-card-body {
|
||||
padding: 5px 15px 5px 15px;
|
||||
background-color: var(--satnogs-color-background);
|
||||
border-color: var(--satnogs-color-border);
|
||||
}
|
||||
|
||||
.satnogs-card {
|
||||
background-color: var(--satnogs-color-card-background);
|
||||
border-color: var(--satnogs-color-border);
|
||||
}
|
||||
|
||||
.transmitter-card-header {
|
||||
padding: 6px 10px 6px 10px;
|
||||
margin-bottom: 0;
|
||||
background-color: var(--satnogs-color-white);
|
||||
/* height: 34px; */
|
||||
}
|
||||
|
||||
.transmitter-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
/* width: 100%; */
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.satellite-panels,
|
||||
.stats-panel {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.transmitter-inactive {
|
||||
color: #a94442;
|
||||
background-color: #f2dede;
|
||||
border-color: #ebccd1;
|
||||
}
|
||||
|
||||
.transmitter-active {
|
||||
color: #3c763d;
|
||||
background-color: #dff0d8;
|
||||
border-color: #d6e9c6;
|
||||
}
|
||||
|
||||
.transmitter-card-body {
|
||||
padding: 10px 10px;
|
||||
}
|
||||
|
||||
/* Color pallete */
|
||||
|
||||
.text-satnogs-white {
|
||||
color: var(--satnogs-color-white);
|
||||
}
|
||||
|
||||
.text-satnogs-dark {
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.text-satnogs-text {
|
||||
color: var(--satnogs-color-text);
|
||||
}
|
||||
|
||||
.text-satnogs-background {
|
||||
color: var(--satnogs-color-background);
|
||||
}
|
||||
|
||||
.text-satnogs-primary {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.text-satnogs-active {
|
||||
color: #3c763d;
|
||||
}
|
||||
|
||||
.text-satnogs-inactive {
|
||||
color: #a94442;
|
||||
}
|
||||
|
||||
.background-satnogs {
|
||||
background-color: var(--satnogs-color-background);
|
||||
}
|
||||
|
||||
.background-satnogs-light {
|
||||
background-color: var(--satnogs-color-white);
|
||||
}
|
||||
|
||||
.background-satnogs-primary {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.background-satnogs-header {
|
||||
background-color: var(--satnogs-color-header);
|
||||
}
|
||||
|
||||
.text-satnogs-header {
|
||||
color: var(--satnogs-color-text);
|
||||
}
|
||||
|
||||
.text-satnogs {
|
||||
color: var(--satnogs-color-text);
|
||||
}
|
||||
|
||||
.text-satnogs-headline {
|
||||
color: var(--satnogs-color-headline);
|
||||
}
|
||||
|
||||
.satnogs-icon {
|
||||
color: var(--satnogs-color-icon);
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--color-scheme-background);
|
||||
color: var(--color-scheme-text-color);
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
font-family: ClearSans;
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
color: var(--satnogs-color-menu-hover);
|
||||
}
|
||||
|
||||
:root {
|
||||
--satnogs-color-primary: #656fdb;
|
||||
--satnogs-color-dark: #4d4e59;
|
||||
--satnogs-color-text: #7c81b2;
|
||||
--satnogs-color-background: #f2f2f7;
|
||||
--satnogs-color-header: #f2f2f7;
|
||||
--satnogs-color-border: #f2f2f7;
|
||||
--satnogs-color-white: #f2f2f7;
|
||||
--satnogs-color-card-background: #f2f2f7;
|
||||
--satnogs-color-icon: #656fdb;
|
||||
--satnogs-color-headline: #656fdb;
|
||||
--satnogs-color-menu-background: #f2f2f7;
|
||||
--satnogs-color-menu-text: #4d4e59;
|
||||
--satnogs-color-menu-hover: #656fdb;
|
||||
--color-scheme-background: white;
|
||||
--color-scheme-text-color: #4d4e59;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.satellite-card-body a:link,
|
||||
.satellite-card-body a:visited,
|
||||
.satellite-card-body a:hover {
|
||||
color: var(--color-scheme-text-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.satellite-card-body-row {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
td.details-control {
|
||||
text-align: center;
|
||||
color: forestgreen;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
tr.shown td.details-control {
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.table {
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.page-item.active .page-link {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
border-color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.page-link {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
/* Dark mode */
|
||||
/* @media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--satnogs-color-primary:#656FDB;
|
||||
--satnogs-color-dark: #4d4e59;
|
||||
--satnogs-color-text: #F2F2F7;
|
||||
--satnogs-color-background: #4D4E59;
|
||||
--satnogs-color-header: #656fdb;
|
||||
--satnogs-color-border: #656fdb;
|
||||
--satnogs-color-white: #F2F2F7;
|
||||
--satnogs-color-card-background: #7c81b2;
|
||||
--satnogs-color-icon:#4d4e59;
|
||||
--satnogs-color-headline:#f2f2f7;
|
||||
--satnogs-color-menu-background: #7c81b2;
|
||||
--satnogs-color-menu-text: #4d4e59;
|
||||
--satnogs-color-menu-hover: #F2F2F7;
|
||||
--color-scheme-background: #4d4e59;
|
||||
--color-scheme-text-color: #F2F2F7;
|
||||
}
|
||||
} */
|
||||
|
||||
/* Light mode */
|
||||
/* @media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--satnogs-color-primary:#656FDB;
|
||||
--satnogs-color-dark: #4d4e59;
|
||||
--satnogs-color-text: #7c81b2;
|
||||
--satnogs-color-background: #F2F2F7;
|
||||
--satnogs-color-header: #F2F2F7;
|
||||
--satnogs-color-border: #F2F2F7;
|
||||
--satnogs-color-white: #F2F2F7;
|
||||
--satnogs-color-card-background: #f2f2f7;
|
||||
--satnogs-color-icon: #656FDB;
|
||||
--satnogs-color-headline:#656FDB;
|
||||
--satnogs-color-menu-background: #F2F2F7;
|
||||
--satnogs-color-menu-text: #4d4e59;
|
||||
--satnogs-color-menu-hover: #656FDB;
|
||||
--color-scheme-background: white;
|
||||
--color-scheme-text-color: #4d4e59;
|
||||
}
|
||||
} */
|
||||
|
|
|
@ -0,0 +1,376 @@
|
|||
/* transitional / new CSS file for the new SatNOGS-DB UI */
|
||||
|
||||
:root {
|
||||
--satnogs-color-primary: #656fdb;
|
||||
--satnogs-color-dark: #4d4e59;
|
||||
--satnogs-color-text: #7c81b2;
|
||||
--satnogs-color-background: #f2f2f7;
|
||||
--satnogs-color-header: #f2f2f7;
|
||||
--satnogs-color-border: #f2f2f7;
|
||||
--satnogs-color-white: #f2f2f7;
|
||||
--satnogs-color-card-background: #f2f2f7;
|
||||
--satnogs-color-icon: #656fdb;
|
||||
--satnogs-color-headline: #656fdb;
|
||||
--satnogs-color-menu-background: #f2f2f7;
|
||||
--satnogs-color-menu-text: #4d4e59;
|
||||
--satnogs-color-menu-hover: #656fdb;
|
||||
--color-scheme-background: white;
|
||||
--color-scheme-text-color: #4d4e59;
|
||||
}
|
||||
|
||||
.satellite-title {
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.text-satnogs-white {
|
||||
color: var(--satnogs-color-white);
|
||||
}
|
||||
|
||||
.text-satnogs-dark {
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.text-satnogs-text {
|
||||
color: var(--satnogs-color-text);
|
||||
}
|
||||
|
||||
.text-satnogs-background {
|
||||
color: var(--satnogs-color-background);
|
||||
}
|
||||
|
||||
.text-satnogs-primary {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.text-satnogs-active {
|
||||
color: #3c763d;
|
||||
}
|
||||
|
||||
.text-satnogs-inactive {
|
||||
color: #a94442;
|
||||
}
|
||||
|
||||
.background-satnogs {
|
||||
background-color: var(--satnogs-color-background);
|
||||
}
|
||||
|
||||
.background-satnogs-light {
|
||||
background-color: var(--satnogs-color-white);
|
||||
}
|
||||
|
||||
.background-satnogs-primary {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.background-satnogs-header {
|
||||
background-color: var(--satnogs-color-header);
|
||||
}
|
||||
|
||||
.text-satnogs-header {
|
||||
color: var(--satnogs-color-text);
|
||||
}
|
||||
|
||||
.text-satnogs {
|
||||
color: var(--satnogs-color-text);
|
||||
}
|
||||
|
||||
.text-satnogs-headline {
|
||||
color: var(--satnogs-color-headline);
|
||||
}
|
||||
|
||||
.satnogs-icon {
|
||||
color: var(--satnogs-color-icon);
|
||||
}
|
||||
|
||||
.c-app:not(.c-legacy-theme):not(.c-dark-theme) .c-header.c-header-fixed {
|
||||
border: 0;
|
||||
box-shadow: 0 2px 2px 0 rgba(60, 75, 100, 0.14),
|
||||
0 3px 1px -2px rgba(60, 75, 100, 0.12),
|
||||
0 1px 5px 0 rgba(60, 75, 100, 0.2);
|
||||
}
|
||||
|
||||
#map {
|
||||
min-height: 250px;
|
||||
position: relative;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.mapbox-improve-map,
|
||||
.mapboxgl-ctrl-bottom-left {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mapboxgl-canvas-container {
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.satellite-card-body a:link,
|
||||
.satellite-card-body a:visited,
|
||||
.satellite-card-body a:hover {
|
||||
color: var(--color-scheme-text-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.satellite-card-body-row {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.satellite-img-full {
|
||||
max-width: 100%;
|
||||
max-height: 250px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.c-avatar {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
border-radius: 50em;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 14.4px;
|
||||
}
|
||||
|
||||
.c-avatar .c-avatar-status {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.c-avatar-img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 50em;
|
||||
}
|
||||
|
||||
.c-avatar-status {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 50em;
|
||||
}
|
||||
|
||||
.card-satnogs,
|
||||
.card-satnogs > a,
|
||||
.jumbotron-satnogs {
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.card-satnogs.card-outline {
|
||||
border-top: 3px solid var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.card-satnogs.card-outline-tabs > .card-header a:hover {
|
||||
border-top: 3px solid #dee2e6;
|
||||
}
|
||||
|
||||
.card-satnogs.card-outline-tabs > .card-header a.active {
|
||||
border-top: 3px solid var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.sat-menu-panel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[class*='sidebar-dark'] .sat-menu-panel {
|
||||
border-top: 1px solid #4f5962;
|
||||
}
|
||||
|
||||
[class*='sidebar-light'] .sat-menu-panel {
|
||||
border-top: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.sat-menu-panel,
|
||||
.sat-menu-panel .info {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sat-menu-panel .image {
|
||||
display: inline-block;
|
||||
padding-left: 0.8rem;
|
||||
}
|
||||
|
||||
.sat-menu-panel img {
|
||||
height: auto;
|
||||
width: 2.1rem;
|
||||
}
|
||||
|
||||
.sat-menu-panel .info {
|
||||
display: inline-block;
|
||||
padding: 5px 5px 5px 10px;
|
||||
}
|
||||
|
||||
.sat-menu-panel .status,
|
||||
.sat-menu-panel .dropdown-menu {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.sat-menu-panel .sat-name {
|
||||
color: #c2c7d0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.navbar-nav > .nav-item > .nav-link.active,
|
||||
.nav > .nav-item > .nav-link.active,
|
||||
.sidebar-dark-primary .nav-sidebar > .nav-item > .nav-link.active,
|
||||
.sidebar-light-primary .nav-sidebar > .nav-item > .nav-link.active {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link:not(.active):hover {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.dropdown-item.active, .dropdown-item:active {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.brand-text {
|
||||
/* color: var(--satnogs-color-primary); */
|
||||
color: #b9b9b9;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.page-item.active .page-link {
|
||||
z-index: 3;
|
||||
color: #fff;
|
||||
background-color: var(--satnogs-color-primary);
|
||||
border-color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.page-link {
|
||||
color: var(--satnogs-color-primary);
|
||||
background-color: #fff;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.satnogs-nav-sat {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.satnogs-nav-sat > .nav-link {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.satnogs-nav-sat .nav-link {
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.satnogs-nav-sat > .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
|
||||
color: #fff;
|
||||
background-color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.satnogs-nav-sat > .nav-pills .nav-link:not(.active):hover {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.satnogs-nav-sat > .nav-tabs .nav-link.active, .nav-tabs .show > .nav-link {
|
||||
color: #fff;
|
||||
background-color: var(--satnogs-color-primary);
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.satnogs-nav-sat > .nav-tabs .nav-link:not(.active):hover {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.navbar-nav > .nav-item > .brand-link {
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.nav-sidebar > .nav-item .nav-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.small-box-satnogs {
|
||||
background-color: var(--satnogs-color-text);
|
||||
color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.sat-menu-panel > .image > .fas {
|
||||
color: var(--satnogs-color-primary);
|
||||
}
|
||||
|
||||
.timeline > .time-label > .background-satnogs-primary,
|
||||
.timeline > div > .background-satnogs-primary {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.nav-sidebar .nav-item > .nav-link.disabled {
|
||||
color: #6c757d;
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.freqlabel {
|
||||
display: inline-block;
|
||||
width: 75px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.btn-satnogs-primary,
|
||||
.badge-satnogs-primary {
|
||||
background-color: var(--satnogs-color-primary);
|
||||
color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.nav-link.active > .badge-satnogs-primary {
|
||||
color: rgba(255, 255, 255, .8);
|
||||
background-color: var(--satnogs-color-text);
|
||||
}
|
||||
|
||||
.btn-satnogs {
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.btn-navbar-satnogs {
|
||||
color: #939ba2;
|
||||
opacity: 1;
|
||||
border: 1px solid #56606a;
|
||||
}
|
||||
|
||||
a.dropdown-item {
|
||||
color: var(--satnogs-color-dark);
|
||||
}
|
||||
|
||||
.transmitter-element-suggest {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
[class*='sidebar-dark'] .user-panel {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
[class*='sidebar-dark'] .satnogs-sidebar-footer,
|
||||
[class*='sidebar-dark'] .satnogs-sidebar-footer a {
|
||||
color: rgba(255, 255, 255, .5);
|
||||
font-size: .7rem;
|
||||
}
|
||||
|
||||
.toasts-top-right {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 4.25rem;
|
||||
}
|
||||
|
||||
.toast.alert-warning > .toast-header {
|
||||
background-color: rgba(255, 255, 255, .2);
|
||||
color: #000;
|
||||
}
|
After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.8 KiB |
|
@ -1,3 +1,4 @@
|
|||
/* eslint new-cap: "off" */
|
||||
$(document).ready(function() {
|
||||
'use strict';
|
||||
|
||||
|
@ -6,5 +7,39 @@ $(document).ready(function() {
|
|||
$('#copy').text(current_year);
|
||||
|
||||
// Enable tooltips
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
// $('[data-toggle="tooltip"]').tooltip();
|
||||
// $('[data-toggle="popover"]').popover();
|
||||
|
||||
// User Settings / API Modal Form Link
|
||||
$('.basemodal-link').each(function () {
|
||||
$(this).modalForm({
|
||||
formURL: $(this).data('form-url'),
|
||||
modalID: '#basemodal'
|
||||
});
|
||||
$(this).click(function() {
|
||||
$('#control-sidebar-toggle').ControlSidebar('toggle');
|
||||
});
|
||||
});
|
||||
|
||||
// Transitional from inline alerts to Toasts
|
||||
$('.alert').each(function() {
|
||||
var alerticon = 'fas fa-question';
|
||||
var alerttitle = 'Unknown';
|
||||
if ($(this).data('alertclass') == 'alert-success') {
|
||||
alerticon = 'far fa-thumbs-up';
|
||||
alerttitle = 'Success';
|
||||
}
|
||||
if ($(this).data('alertclass') == 'alert-warning') {
|
||||
alerticon = 'fas fa-exclamation';
|
||||
alerttitle = 'Alert';
|
||||
}
|
||||
$(document).Toasts('create', {
|
||||
class: $(this).data('alertclass'),
|
||||
title: alerttitle,
|
||||
autohide: true,
|
||||
delay: 6000,
|
||||
icon: alerticon,
|
||||
body: $(this).data('alertmessage')
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -119,7 +119,8 @@ $(document).ready(function() {
|
|||
|
||||
var map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://styles/pierros/cj8kftshl4zll2slbelhkndwo',
|
||||
// style: 'mapbox://styles/pierros/cj8kftshl4zll2slbelhkndwo',
|
||||
style: 'mapbox://styles/cshields/ckc1a24y45smb1ht9bbhrcrk6',
|
||||
zoom: 2,
|
||||
center: sat_location
|
||||
});
|
||||
|
@ -223,4 +224,10 @@ $(document).ready(function() {
|
|||
}
|
||||
setInterval(update_map, 5000);
|
||||
});
|
||||
|
||||
// couldn't get this to work with shown.bs.tab, have to go with click
|
||||
// timeout is necessary for the first click for some reason
|
||||
document.getElementById('mapcontent-tab').addEventListener('click', function() {
|
||||
setTimeout( function() { map.resize();}, 200);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint new-cap: "off" */
|
||||
function copyToClipboard(text, el) {
|
||||
var copyTest = document.queryCommandSupported('copy');
|
||||
var elOriginalText = el.attr('data-original-title');
|
||||
|
@ -41,7 +42,7 @@ function transmitter_suggestion_type(selection) {
|
|||
$('.input-group').has('input[name=\'invert\']').hide();
|
||||
$('.input-group').has('select[name=\'uplink_mode\']').hide();
|
||||
|
||||
$('.input-group-addon:contains(\'Downlink Low\')').html('Downlink');
|
||||
$('.input-group-prepend:contains(\'Downlink Low\')').html('<span class="input-group-text">Downlink</span>');
|
||||
break;
|
||||
case 'Transceiver':
|
||||
$('.input-group').show();
|
||||
|
@ -54,15 +55,15 @@ function transmitter_suggestion_type(selection) {
|
|||
$('.input-group').has('input[name=\'downlink_high\']').hide();
|
||||
$('.input-group').has('input[name=\'invert\']').hide();
|
||||
|
||||
$('input[name=\'downlink_low\']').prev().html('Downlink');
|
||||
$('input[name=\'uplink_low\']').prev().html('Uplink');
|
||||
$('input[name=\'downlink_low\']').prev().html('<span class="input-group-text">Downlink</span>');
|
||||
$('input[name=\'uplink_low\']').prev().html('<span class="input-group-text">Uplink</span>');
|
||||
break;
|
||||
case 'Transponder':
|
||||
$('.input-group').show();
|
||||
$('input').prop( 'disabled', false );
|
||||
$('select').prop( 'disabled', false );
|
||||
$('input[name=\'downlink_low\']').prev().html('Downlink Low');
|
||||
$('input[name=\'uplink_low\']').prev().html('Uplink Low');
|
||||
$('input[name=\'downlink_low\']').prev().html('<span class="input-group-text">Downlink Low</span>');
|
||||
$('input[name=\'uplink_low\']').prev().html('<span class="input-group-text">Uplink Low</span>');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ $(document).ready(function() {
|
|||
transmitter_suggestion_type(selection);
|
||||
});
|
||||
|
||||
$('.transmitter_suggestion-edit-modal').on('show.bs.modal', function(){
|
||||
$('.transmitter_suggestion-modal').on('show.bs.modal', function(){
|
||||
var selection = $(this).find('.transmitter_suggestion-type').val();
|
||||
transmitter_suggestion_type(selection);
|
||||
|
||||
|
@ -114,10 +115,6 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
$('#NewSuggestionModal').on('show.bs.modal', function(){
|
||||
transmitter_suggestion_type('Transmitter');
|
||||
});
|
||||
|
||||
// Calculate the drifted frequencies
|
||||
$('.drifted').each(function() {
|
||||
var drifted = ppb_to_freq($(this).data('freq_or'),$(this).data('drift'));
|
||||
|
@ -126,13 +123,13 @@ $(document).ready(function() {
|
|||
|
||||
$('.uplink-drifted-sugedit').on('change click', function(){
|
||||
var freq_obs = parseInt($(this).val());
|
||||
var freq = parseInt($('.in input[name=\'uplink_low\']').val());
|
||||
var freq = parseInt($('input[name=\'uplink_low\']:visible').val());
|
||||
$('.uplink-ppb-sugedit').val(freq_to_ppb(freq_obs,freq));
|
||||
});
|
||||
|
||||
$('.downlink-drifted-sugedit').on('change click', function(){
|
||||
var freq_obs = parseInt($(this).val());
|
||||
var freq = parseInt($('.in input[name=\'downlink_low\']').val());
|
||||
var freq = parseInt($('input[name=\'downlink_low\']:visible').val());
|
||||
$('.downlink-ppb-sugedit').val(freq_to_ppb(freq_obs,freq));
|
||||
});
|
||||
|
||||
|
@ -148,4 +145,39 @@ $(document).ready(function() {
|
|||
var el = $(this);
|
||||
copyToClipboard(text, el);
|
||||
});
|
||||
|
||||
// Update Satellite
|
||||
$('.bs-modal').each(function () {
|
||||
$(this).modalForm({
|
||||
formURL: $(this).data('form-url')
|
||||
});
|
||||
});
|
||||
|
||||
// Update Transmitter
|
||||
$('.update-transmitter-link').each(function () {
|
||||
$(this).modalForm({
|
||||
formURL: $(this).data('form-url'),
|
||||
modalID: '#update-transmitter-modal'
|
||||
});
|
||||
});
|
||||
|
||||
// New transmitter links
|
||||
$('.create-transmitter-link').each(function () {
|
||||
$(this).modalForm({
|
||||
formURL: $(this).data('form-url'),
|
||||
modalID: '#create-transmitter-modal'
|
||||
});
|
||||
});
|
||||
|
||||
// Ask for help in a toast if this Satellite object is flagged as in need
|
||||
if ($('#satellite_name').data('needshelp') == 'True') {
|
||||
$(document).Toasts('create', {
|
||||
title: 'Please Help!',
|
||||
class: 'alert-warning',
|
||||
autohide: true,
|
||||
delay: 6000,
|
||||
icon: 'fas fa-hand-holding-medical',
|
||||
body: 'This Satellite needs editing. <a href="https://wiki.satnogs.org/Get_In_Touch" target="_blank">Contact us</a> to become an editor.'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* eslint new-cap: "off" */
|
||||
$(document).ready(function() {
|
||||
$('#sats').DataTable( {
|
||||
// the dom field controls the layout and visibility of datatable items
|
||||
// and is not intuitive at all. Without layout we have dom: 'Bftrilp'
|
||||
// https://datatables.net/reference/option/dom
|
||||
dom: '<"row"<"d-none d-md-block col-md-6"B><"col-sm-12 col-md-6"f>>' +
|
||||
'<"row"<"col-sm-12"tr>>' +
|
||||
'<"row"<"col-sm-12 col-xl-3"i><"col-sm-12 col-md-6 col-xl-3"l><"col-sm-12 col-md-6 col-xl-6"p>>',
|
||||
buttons: [
|
||||
'colvis'
|
||||
],
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.childRow,
|
||||
type: 'column'
|
||||
}
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
className: 'control',
|
||||
orderable: false,
|
||||
targets: 0
|
||||
},
|
||||
],
|
||||
language: {
|
||||
search: 'Filter:',
|
||||
buttons: {
|
||||
colvis: 'Columns',
|
||||
}
|
||||
},
|
||||
order: [ 1, 'asc' ],
|
||||
pageLength: 25
|
||||
} );
|
||||
|
||||
// Update Satellite
|
||||
$('.bs-modal').each(function () {
|
||||
$(this).modalForm({
|
||||
formURL: $(this).data('form-url')
|
||||
});
|
||||
});
|
||||
} );
|
|
@ -75,30 +75,40 @@ $(document).ready(function() {
|
|||
$('#transmitters-numbers').hide();
|
||||
} else {
|
||||
var i;
|
||||
var r;
|
||||
var g;
|
||||
var b;
|
||||
var a;
|
||||
var h;
|
||||
var s;
|
||||
var l;
|
||||
var color;
|
||||
var mode_total = 0;
|
||||
var band_total = 0;
|
||||
// Create colors for Mode Chart
|
||||
var mode_colors = [];
|
||||
for (i = 0; i < data.mode_label.length; i++) {
|
||||
r = Math.floor(data.mode_data[i]* 10);
|
||||
b = Math.floor(0.3 * 255);
|
||||
g = Math.floor(data.mode_data[i]* 10);
|
||||
a = 0.5;
|
||||
color = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
|
||||
mode_total += data.mode_data[i];
|
||||
}
|
||||
for (i = 0; i < data.band_label.length; i++) {
|
||||
band_total += data.band_data[i];
|
||||
}
|
||||
for (i = 0; i < data.mode_label.length; i++) {
|
||||
// Switching to HSL to stick with hue of LSF logo
|
||||
h = 235;
|
||||
l = data.mode_data[i]/mode_total*100;
|
||||
l *= 3; // adjust for better visibility
|
||||
s = data.mode_data[i]/mode_total*100;
|
||||
s *= 3; // adjust for better visibility
|
||||
color = 'hsl(' + h + ',' + Math.floor(s) + '%,' + Math.floor(l) + '%)';
|
||||
mode_colors.push(color);
|
||||
}
|
||||
|
||||
// Create colors for Band Chart
|
||||
var band_colors = [];
|
||||
for (i = 0; i < data.band_label.length; i++) {
|
||||
b = Math.floor(0.1 * 255);
|
||||
g = Math.floor(data.band_data[i]);
|
||||
r = Math.floor(data.band_data[i]);
|
||||
a = 0.5;
|
||||
color = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
|
||||
h = 235;
|
||||
l = data.band_data[i]/band_total*100;
|
||||
l *= 1.25; // adjust for better visibility
|
||||
s = data.band_data[i]/band_total*100;
|
||||
s *= 1.25; // adjust for better visibility
|
||||
color = 'hsl(' + h + ',' + s + '%,' + l + '%)';
|
||||
band_colors.push(color);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,23 +3,65 @@ function ppb_to_freq(freq, drift) {
|
|||
return Math.round(freq_obs);
|
||||
}
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* Disabling eslint for the following function since it is called by the Bootstrap Table library */
|
||||
function freqSorter(a, b) {
|
||||
var aa = a.split(' ', 1);
|
||||
var bb = b.split(' ', 1);
|
||||
return aa - bb;
|
||||
function format_freq(frequency) {
|
||||
if (isNaN(frequency) || frequency == ''){
|
||||
return 'None';
|
||||
} else if (frequency < 1000) {
|
||||
// Frequency is in Hz range
|
||||
return frequency.toFixed(3) + ' Hz';
|
||||
} else if (frequency < 1000000) {
|
||||
return (frequency/1000).toFixed(3) + ' kHz';
|
||||
} else {
|
||||
return (frequency/1000000).toFixed(3) + ' MHz';
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
/* eslint new-cap: "off" */
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#transmitters-table').bootstrapTable();
|
||||
$('#transmitters-table').css('opacity','1');
|
||||
|
||||
// Calculate the drifted frequencies
|
||||
$('.drifted').each(function() {
|
||||
var drifted = ppb_to_freq($(this).data('freq_or'),$(this).data('drift'));
|
||||
$(this).html(drifted);
|
||||
});
|
||||
});
|
||||
|
||||
// Format all frequencies
|
||||
$('.frequency').each(function() {
|
||||
var to_format = $(this).html();
|
||||
$(this).html(format_freq(to_format));
|
||||
});
|
||||
|
||||
$('#transmitters').DataTable( {
|
||||
// the dom field controls the layout and visibility of datatable items
|
||||
// and is not intuitive at all. Without layout we have dom: 'Bftrilp'
|
||||
// https://datatables.net/reference/option/dom
|
||||
dom: '<"row"<"d-none d-md-block col-md-6"B><"col-sm-12 col-md-6"f>>' +
|
||||
'<"row"<"col-sm-12"tr>>' +
|
||||
'<"row"<"col-sm-12 col-xl-3"i><"col-sm-12 col-md-6 col-xl-3"l><"col-sm-12 col-md-6 col-xl-6"p>>',
|
||||
buttons: [
|
||||
'colvis'
|
||||
],
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.childRow,
|
||||
type: 'column'
|
||||
}
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
className: 'control',
|
||||
orderable: false,
|
||||
targets: 0
|
||||
},
|
||||
],
|
||||
language: {
|
||||
search: 'Filter:',
|
||||
buttons: {
|
||||
colvis: 'Columns',
|
||||
}
|
||||
},
|
||||
order: [ 1, 'asc' ],
|
||||
pageLength: 25
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %} - Page Not found{% endblock %}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %} - Server Error{% endblock %}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
|
||||
{% endif %}
|
||||
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">Forgot Password?</a>
|
||||
<button class="btn btn-primary" type="submit">Sign In</button>
|
||||
<button class="btn btn-satnogs-primary" type="submit">Sign In</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
<img src="{{ url }}" width="{{ size }}" height="{{ size }}" class="img-avatar">
|
||||
<!-- <img src="{{ url }}" width="{{ size }}" height="{{ size }}" class="img-avatar"> -->
|
||||
<img src="{{ url }}" class="user-image" alt="User Image">
|
||||
|
|
|
@ -1,129 +1,248 @@
|
|||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
{% load avatar_tags %}
|
||||
{% load tags %}
|
||||
{% load compress %}
|
||||
{% load fontawesome_5 %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" ng-app>
|
||||
<head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SatNOGS DB{% block title %}{% endblock title %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{% compress css %}
|
||||
<link rel="stylesheet" href="{% static 'lib/bootstrap/dist/css/bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/app.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'lib/admin-lte/dist/css/adminlte.min.css' %}">
|
||||
|
||||
<link rel="stylesheet" href="{% static 'css/newapp.css' %}">
|
||||
{% block css %}{% endblock %}
|
||||
{% endcompress %}
|
||||
{% fontawesome_5_static %}
|
||||
|
||||
<link rel="shortcut icon" href="{% static 'favicon.ico' %}">
|
||||
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{ stage_notice }}
|
||||
<body class="layout-fixed">
|
||||
<div class="wrapper bg-light">
|
||||
|
||||
<div class="container">
|
||||
<nav class="navbar navbar-default" role="navigation" id="main-navbar">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="{% url 'home' %}">
|
||||
<img id="navbar-logo" src="{% static 'img/satnogs_db.png' %}" alt="SatNOGS net">
|
||||
</a>
|
||||
<!-- Top Navbar menu -->
|
||||
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
|
||||
<ul class="navbar-nav d-lg-none">
|
||||
<a class="nav-link keychainify-checked" data-widget="pushmenu" href="#" role="button"><i
|
||||
class="fas fa-bars"></i></a>
|
||||
</ul>
|
||||
<span class="d-lg-none font-weight-light pr-2">SatNOGS DB</span>
|
||||
|
||||
<!-- hacky, push dyamic content and/or user menu to the right -->
|
||||
<div class="pl-3 mr-auto">
|
||||
{% block top-menu-left %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% block top-menu-right %}
|
||||
{% endblock %}
|
||||
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="{% active request 'about' %}"><a href="{% url 'about' %}">About</a></li>
|
||||
<li class="{% active request 'home' %}"><a href="{% url 'home' %}">Satellites</a></li>
|
||||
<li class="{% active request 'transmitters_list' %}"><a href="{% url 'transmitters_list' %}">Transmitters</a></li>
|
||||
<li class="{% active request 'stats' %}"><a href="{% url 'stats' %}">Statistics</a></li>
|
||||
<li class="{% active request 'faq' %}"><a href="{% url 'faq' %}">FAQ</a></li>
|
||||
<li><a href="https://community.libre.space/c/satnogs/" target="_blank">Community</a></li>
|
||||
<li><a href="https://wiki.satnogs.org/" target="_blank">Wiki</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="https://www.timeanddate.com/worldclock" target="_blank" class="hidden-sm"><span id="current_utc">--:-- UTC</span></a></li>
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="dropdown">
|
||||
<a href="#"
|
||||
class="dropdown-toggle"
|
||||
data-toggle="dropdown">{% avatar request.user 35 %} {{ request.user.username }}
|
||||
<span class="caret"></span>
|
||||
<ul class="nav navbar-nav py-2">
|
||||
<li class="user user-menu">
|
||||
<a href="#" id="control-sidebar-toggle" data-widget="control-sidebar">
|
||||
{% avatar request.user %}
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="{% url 'users_edit' %}">Settings/API Key</a></li>
|
||||
{{ logout_block }}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% else %}
|
||||
{{ auth_block }}
|
||||
{% endif %}
|
||||
</nav>
|
||||
|
||||
<!-- Sidebar menu -->
|
||||
<aside class="main-sidebar sidebar-dark-primary elevation-4 h-100" id="sidebar">
|
||||
<div class="brand-link border-bottom-0">
|
||||
<img src="{% static 'img/satnogs-logo-only-light.png' %}" alt="SatNOGS Logo" class="brand-image"
|
||||
style="opacity: .8;">
|
||||
<span class="brand-text font-weight-light">SatNOGS DB</span>
|
||||
</div>
|
||||
<div class="sidebar d-flex flex-column">
|
||||
|
||||
<form class="form-inline mt-1" action="{% url 'search_results' %}" method="GET">
|
||||
<div class="input-group input-group-sm">
|
||||
<input class="form-control form-control-sidebar" type="search" name="q"
|
||||
placeholder="Satellite name or ID" aria-label="Search">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-navbar-satnogs" type="submit">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<nav class="mt-2">
|
||||
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{% if request.resolver_match.url_name == 'home' %} active{% endif %}"
|
||||
href="{% url 'home' %}">
|
||||
<i class="nav-icon fas fa-home"></i>
|
||||
<p>Home</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{% if request.resolver_match.url_name == 'about' %} active{% endif %}"
|
||||
href="{% url 'about' %}">
|
||||
<i class="nav-icon fas fa-info-circle"></i>
|
||||
<p>About</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{% if request.resolver_match.url_name == 'satellites' %} active{% endif %}"
|
||||
href="{% url 'satellites' %}">
|
||||
<i class="nav-icon fas fa-satellite"></i>
|
||||
<p>All Satellites</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{% if request.resolver_match.url_name == 'transmitters_list' %} active{% endif %}"
|
||||
href="{% url 'transmitters_list' %}">
|
||||
<i class="nav-icon fas fa-satellite-dish"></i>
|
||||
<p>All Transmitters</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{% if request.resolver_match.url_name == 'stats' %} active{% endif %}"
|
||||
href="{% url 'stats' %}">
|
||||
<i class="nav-icon fas fa-chart-bar"></i>
|
||||
<p>Statistics</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="disabled nav-link{% if request.resolver_match.url_name == 'news' %} active{% endif %}"
|
||||
href="">
|
||||
<i class="nav-icon fas fa-newspaper"></i>
|
||||
<p>News</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item has-treeview">
|
||||
<a href="#" class="nav-link">
|
||||
<i class="nav-icon fas fa-link"></i>
|
||||
<p>
|
||||
SatNOGS Links
|
||||
<i class="right align-middle fas fa-angle-left"></i>
|
||||
</p>
|
||||
</a>
|
||||
<ul class="nav nav-treeview">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://network.satnogs.org">
|
||||
<i class="nav-icon fas fa-external-link-alt"></i>
|
||||
<p>Ground Station Control</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://wiki.satnogs.org">
|
||||
<i class="nav-icon fas fa-external-link-alt"></i>
|
||||
<p>Wiki</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://community.libre.space">
|
||||
<i class="nav-icon fas fa-external-link-alt"></i>
|
||||
<p>Forums</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- /.nav-sidebar -->
|
||||
</nav>
|
||||
|
||||
<div class="mt-auto satnogs-sidebar-footer">
|
||||
<div>
|
||||
<span class="align-self-center"><i class="far fa-copyright"></i> 2014<span id="copy"></span>
|
||||
<a href="https://libre.space" target="_blank">Libre Space Foundation</a></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
{{ version }}
|
||||
<br>
|
||||
{{ decoders_version }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.panel-collapse -->
|
||||
</div>
|
||||
<!-- /.satnogs-sidebar-footer -->
|
||||
</div>
|
||||
<!-- /.sidebar -->
|
||||
</aside>
|
||||
<!-- /.main-sidebar -->
|
||||
|
||||
<!-- Control Sidebar (Right Menu) -->
|
||||
<aside class="control-sidebar control-sidebar-dark">
|
||||
<!-- Control sidebar content goes here -->
|
||||
<div class="p-3">
|
||||
<div class="row justify-content-center border-bottom">
|
||||
<h5 class="mb-1 text-sm">{{ user.username }}</h5>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="nav nav-pills nav-sidebar flex-column">
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link basemodal-link control-sidebar-link" data-form-url="/users/edit/">
|
||||
<i class="nav-icon fas fa-cog"></i>
|
||||
<p>Settings / API Key</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link basemodal-link control-sidebar-link" data-form-url="/help/">
|
||||
<i class="nav-icon fas fa-question-circle"></i>
|
||||
<p>Help</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
{{ logout_block }}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- /.control-sidebar -->
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- Content window -->
|
||||
<div class="content-wrapper bg-light">
|
||||
{% if messages %}
|
||||
<div class="row messages">
|
||||
<div class="col-md-12">
|
||||
<!-- This is hidden, transitional to Toasts - see app.js -->
|
||||
{% for notification in messages %}
|
||||
<div class="alert alert-{{ notification.tags }}" role="alert">
|
||||
<div hidden class="alert alert-{{ notification.tags }}" data-alertclass="alert-{{ notification.tags }}" data-alertmessage="{{ notification.message }}" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
{{ notification.message }}
|
||||
</div>
|
||||
<!-- /.alert -->
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block top %}{% endblock %}
|
||||
|
||||
{% block content %}{% endblock content %}
|
||||
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<span class="glyphicon glyphicon-copyright-mark" aria-hidden="true"></span> 2014<span id="copy"></span>
|
||||
<a href="http://librespacefoundation.org/" target="_blank">Libre Space Foundation</a>.<br>
|
||||
<span class="glyphicon glyphicon-cloud" aria-hidden="true"></span>
|
||||
Transmitter data are freely distributed under the
|
||||
<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">CC BY-SA</a> license.
|
||||
</div>
|
||||
<div class="col-md-6 text-right footer-options">
|
||||
<a href="https://satnogs.org/" target="_blank">SatNOGS</a> |
|
||||
<a href="#top">Back to top</a>
|
||||
<p>
|
||||
{{ version }}
|
||||
<br>
|
||||
{{ decoders_version }}
|
||||
</p>
|
||||
<!-- /.content-wrapper -->
|
||||
<div class="modal fade" tabindex="-1" role="dialog" id="basemodal">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- /.wrapper -->
|
||||
|
||||
{% compress js %}
|
||||
<script src="{% static 'lib/jquery/dist/jquery.min.js' %}"></script>
|
||||
<script src="{% static 'lib/popper.js/dist/umd/popper.min.js' %}"></script>
|
||||
<script src="{% static 'lib/bootstrap/dist/js/bootstrap.min.js' %}"></script>
|
||||
<script src="{% static 'lib/admin-lte/dist/js/adminlte.min.js' %}"></script>
|
||||
<script src="{% static 'js/jquery.bootstrap.modal.forms.min.js' %}"></script>
|
||||
<script src="{% static 'js/app.js' %}"></script>
|
||||
<script src="{% static 'js/current_utc.js'%}"></script>
|
||||
<!-- <script src="{% static 'js/current_utc.js'%}"></script> -->
|
||||
{% block javascript %}{% endblock javascript %}
|
||||
{{ analytics_code }}
|
||||
{% endcompress %}
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -2,10 +2,44 @@
|
|||
|
||||
{% block title %} - About{% endblock %}
|
||||
|
||||
{% block top-menu-left %}
|
||||
<h5 class="mb-0 mr-3">About</h5>
|
||||
{% endblock %}
|
||||
|
||||
{% block top-menu-right %}
|
||||
|
||||
<ul class="navbar-nav nav nav-pills" data-widget="treeview" role="menu" data-accordion="false" id="tabs"
|
||||
role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="satnogsdb-tab" data-toggle="tab" href="#satnogsdb" role="tab" aria-controls="satnogsdb"
|
||||
aria-selected="true"><i class="nav-icon fas fa-info-circle"></i>
|
||||
<p class="d-none d-lg-inline-block">SatNOGS DB</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="api-tab" data-toggle="tab" href="#api" role="tab"
|
||||
aria-controls="api" aria-selected="false">
|
||||
<i class="nav-icon fas fa-info-circle"></i>
|
||||
<p class="d-none d-lg-inline-block">API</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="lsf-tab" data-toggle="tab" href="#lsf" role="tab"
|
||||
aria-controls="lsf" aria-selected="false">
|
||||
<i class="nav-icon fas fa-info-circle"></i>
|
||||
<p class="d-none d-lg-inline-block">Libre Space Foundation</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row text">
|
||||
<!-- The following div is managed by the tab menus -->
|
||||
<div class="col-12 tab-content pt-3 mx-2" id="myTabContent">
|
||||
|
||||
<!-- SatNOGS DB panel -->
|
||||
<div class="tab-pane fade show active mx-1" id="satnogsdb" role="tabpanel" aria-labelledby="satnogsdb-tab">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>About</h1>
|
||||
SatNOGS DB is an effort to create an hollistic, unified, global transmitter database for all satellite
|
||||
transmitters. You can export the data or even connect your application using our API.
|
||||
It's part of the <a href="https://satnogs.org/" target="_blank">SatNOGS project</a>.
|
||||
|
@ -22,4 +56,21 @@
|
|||
<a href="https://docs.satnogs.org/projects/satnogs-db/en/stable/" target="_blank">docs.satnogs.org</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API panel -->
|
||||
<div class="tab-pane fademx-1" id="api" role="tabpanel" aria-labelledby="api-tab">
|
||||
<div class="row">
|
||||
API info coming soon..
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LSF panel -->
|
||||
<div class="tab-pane fade mx-1" id="lsf" role="tabpanel" aria-labelledby="lsf-tab">
|
||||
<div class="row">
|
||||
Libre Space Foundation info coming soon. Visit <a href="https://libre.space" target="_blank">https://libre.space</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %} - FAQ{% endblock %}
|
||||
|
||||
|
|
|
@ -1,67 +1,84 @@
|
|||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{% endblock %}
|
||||
{% block title %} - Home{% endblock %}
|
||||
|
||||
{% block top %}
|
||||
<div class="row" id="search">
|
||||
<div class="col-md-7">
|
||||
<input type="text" list="satellites-list"
|
||||
class="form-control input-lg satellite-search"
|
||||
placeholder="Filter by Name or NORAD Cat ID"
|
||||
autocomplete="off">
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="row hidden-xs hidden-sm">
|
||||
<p class="statistics" title="satellites" data-toggle="tooltip">
|
||||
<img src="{% static 'img/satellites.png' %}">
|
||||
{{ statistics.total_satellites }}
|
||||
</p>
|
||||
<p class="statistics" title="transmitters" data-toggle="tooltip">
|
||||
<img src="{% static 'img/transmitters.png' %}">
|
||||
{{ statistics.transmitters }}
|
||||
</p>
|
||||
{% if transmitter_suggestions %}
|
||||
<p class="statistics" title="transmitter suggestions" data-toggle="tooltip">
|
||||
<img src="{% static 'img/transmitter_suggestions.png' %}">
|
||||
{{ transmitter_suggestions }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="statistics" title="telemetry" data-toggle="tooltip">
|
||||
<img src="{% static 'img/payloads.png' %}">
|
||||
{{ statistics.total_data }}
|
||||
</p>
|
||||
<p class="statistics" title="contributors" data-toggle="tooltip">
|
||||
<img src="{% static 'img/contributors.png' %}">
|
||||
{{ contributors }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'lib/flag-icon-css/css/flag-icon.min.css' %}" />
|
||||
{% endblock css %}
|
||||
|
||||
{% block top-menu-left %}
|
||||
<h5 class="mb-0 mr-3">Welcome to SatNOGS DB</h5>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row sats">
|
||||
{% for sat in satellites %}
|
||||
<div class="satellite-group-item"
|
||||
data-selector="{{ sat.name|lower }}{{ sat.norad_cat_id }}{{ sat.names|lower }}"
|
||||
data-image="{{ sat.get_image }}">
|
||||
<a href="{% url 'satellite' norad=sat.norad_cat_id %}" class="panel panel-default satellite-item">
|
||||
<div class="panel-heading"></div>
|
||||
<div class="panel-body">
|
||||
<div class="satellite-title">{{ sat.norad_cat_id }} - {{ sat.name }}</div>
|
||||
<div class="satellite-names">{{ sat.names }} </div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
{{ sat.transmitters_count }} Transmitters
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="row px-2 pt-2 card-deck">
|
||||
<div class="col-md-6 col-xl-4 satellite-panels">
|
||||
<h4 class="text-satnogs text-center mb-0">New Satellites</h4>
|
||||
|
||||
{% for satellite in newest_sats %}
|
||||
{% include 'includes/cards/satellite_card.html' with satellite=satellite %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="info row">
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-6 col-xl-4 satellite-panels">
|
||||
<h4 class="text-satnogs text-center mb-0">Latest Data</h4>
|
||||
|
||||
{% for satellite in latest_data %}
|
||||
{% include 'includes/cards/satellite_card.html' with satellite=satellite %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-xl-4 satellite-panels">
|
||||
<h4 class="text-satnogs text-center mb-0">Recent Contributors</h4>
|
||||
<div class="card shadow card-outline card-satnogs my-3">
|
||||
{% if latest_submitters.count %}
|
||||
<div class="card-header py-1">
|
||||
<div class="row">
|
||||
<div class="pl-1">
|
||||
<span class="card-title">Data - Last 24h</span><br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body satellite-card-body py-2 px-2">
|
||||
<div class="d-flex flex-row no-gutters text-nowrap align-items-center justify-content-between">
|
||||
<div class="d-flex flex-column float-left align-self-center">
|
||||
{% for contributor in latest_submitters %}
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex satellite-card-body-row align-self-center justify-content-center">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex">
|
||||
{{ contributor.station }} - {{ contributor.c }} frames
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="card-body d-flex flex-row">
|
||||
<div class="d-inline-flex">
|
||||
<p class="text-wrap">
|
||||
It appears there have been no contributions in the past 24 hours.
|
||||
Please visit
|
||||
<a href="https://wiki.satnogs.org" target="_blank">wiki.satnogs.org</a>
|
||||
to learn how to contribute data!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-footer">
|
||||
<span class="text-value-sm">Thank you to our contributors! Please visit
|
||||
<a href="https://wiki.satnogs.org" target="_blank">wiki.satnogs.org</a>
|
||||
to learn how to contribute data.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="info row p-3">
|
||||
<div class="col-lg-4">
|
||||
<h3>Open</h3>
|
||||
<p>
|
||||
SatNOGS DB is, and will always be, an open database. We aspire to create an hollistic,
|
||||
|
@ -69,14 +86,14 @@
|
|||
data or even connect your application using our API.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="col-lg-4">
|
||||
<h3>Crowd-sourced</h3>
|
||||
<p>
|
||||
We rely on user submitted crowd-sourced information. Create an account and start
|
||||
suggesting additions and/or modifications on our Database. We need your help!
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="col-lg-4">
|
||||
<h3>Extensible</h3>
|
||||
<p>
|
||||
We designed SatNOGS-DB to be easily extensible to accommodate additions and modification
|
||||
|
@ -84,9 +101,7 @@
|
|||
<a href="https://gitlab.com/librespacefoundation/satnogs/satnogs-db">our repo</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script src="{% static 'js/home.js' %}"></script>
|
||||
</div> -->
|
||||
{% endblock %} {% block javascript %}
|
||||
<script src="{% static 'js/home.js' %}"></script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,37 @@
|
|||
{% load widget_tweaks %}
|
||||
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Update Satellite</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
|
||||
{% for error in form.non_field_errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% for field in form %}
|
||||
<div class="input-group my-1">
|
||||
<label class="input-group-prepend input-group-text" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{% render_field field class="form-control" placeholder=field.label %}
|
||||
<div class="{% if field.errors %} invalid{% endif %}">
|
||||
{% for error in field.errors %}
|
||||
<p class="help-block">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="submit-btn btn btn-satnogs-primary">Update</button>
|
||||
</div>
|
||||
|
||||
</form>
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Help</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="row m-2">
|
||||
<div class="col-md-12">
|
||||
Coming soon..
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,45 @@
|
|||
{% load widget_tweaks %}
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
<form action="" method="post" id="transmitter_create-form">
|
||||
{% csrf_token %}
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Create Transmitter</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
|
||||
{% for error in form.non_field_errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% for field in form %}
|
||||
<div class="input-group my-1">
|
||||
<label class="input-group-prepend input-group-text" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{% render_field field class="form-control" placeholder=field.label %}
|
||||
<div class="{% if field.errors %} invalid{% endif %}">
|
||||
{% for error in field.errors %}
|
||||
<p class="help-block">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="submit-btn btn btn-satnogs-primary">Create</button>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="modal-body">
|
||||
<div class="text-danger">You need to login first to add a new transmitter suggestion.</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-outline-secondary" data-dismiss="modal">Close</button>
|
||||
<a href="{% url 'account_login' %}" class="btn btn-satnogs-primary">Log In</a>
|
||||
</div>
|
||||
{% endif %}
|
|
@ -0,0 +1,45 @@
|
|||
{% load widget_tweaks %}
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
<form action="" method="post" id="transmitter_create-form">
|
||||
{% csrf_token %}
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Update Transmitter</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
|
||||
{% for error in form.non_field_errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% for field in form %}
|
||||
<div class="input-group my-1">
|
||||
<label class="input-group-prepend input-group-text" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{% render_field field class="form-control" placeholder=field.label %}
|
||||
<div class="{% if field.errors %} invalid{% endif %}">
|
||||
{% for error in field.errors %}
|
||||
<p class="help-block">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="submit-btn btn btn-satnogs-primary">Update</button>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="modal-body">
|
||||
<div class="text-danger">You need to login first to add a new transmitter suggestion.</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-outline-secondary" data-dismiss="modal">Close</button>
|
||||
<a href="{% url 'account_login' %}" class="btn btn-satnogs-primary">Log In</a>
|
||||
</div>
|
||||
{% endif %}
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">User Settings</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="row m-2">
|
||||
<div class="col-md-12">
|
||||
<div>You can use this token to interact with the API.</div>
|
||||
<div>
|
||||
<code>{{ token }}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,90 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %} - Satellite List{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'lib/datatables.net-bs4/css/dataTables.bootstrap4.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'lib/datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'lib/flag-icon-css/css/flag-icon.min.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="p-3">
|
||||
|
||||
<table id="sats" class="table table-sm display responsive table-striped" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-priority="1"></th>
|
||||
<th data-priority="2">Name</th>
|
||||
<th data-priority="3">NORAD</th>
|
||||
<th data-priority="4">Status</th>
|
||||
<th data-priority="6">Alt. Names</th>
|
||||
<th data-priority="5">XMit</th>
|
||||
<th data-priority="10" data-sortable="true" data-visible="false">Operator</th>
|
||||
<th data-priority="10" data-sortable="true" data-visible="false">Launched</th>
|
||||
<th data-priority="10" data-sortable="true" data-visible="false">Website</th>
|
||||
<th data-priority="10" data-sortable="true" data-visible="false">Dashboard</th>
|
||||
|
||||
<th data-priority="6" data-sortable="false"><i class="fa fa-flag-o px-0"></i></th>
|
||||
{% if perms.base.change_satellite %}
|
||||
<th data-priority="2" data-sortable="false"></th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for sat in satellites %}
|
||||
<tr>
|
||||
<td class='details-control'>
|
||||
<i class="fa fa-plus-square" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td><a href="{% url 'satellite' norad=sat.norad_cat_id %}">{{ sat.name|lower }}</a></td>
|
||||
<td><a href="{% url 'satellite' norad=sat.norad_cat_id %}">{{ sat.norad_cat_id }}</a></td>
|
||||
<td class="d-flex justify-content-center">
|
||||
{% if sat.status == 'alive' %}
|
||||
<img height="32" src="{% static 'img/status_alive.png' %}" alt="alive">
|
||||
{% elif sat.status == 're-entered' %}
|
||||
<img height="32" src="{% static 'img/status_decayed.png' %}" alt="re-entered">
|
||||
{% elif sat.status == 'dead' %}
|
||||
<img height="32" src="{% static 'img/status_dead.png' %}" alt="dead">
|
||||
{% else %}
|
||||
<img height="32" src="{% static 'img/status_unknown.png' %}" alt="unknown">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ sat.names|lower }}</td>
|
||||
<td>{{ sat.transmitters_count }}</td>
|
||||
<td>{{ sat.operator }}</td>
|
||||
<td>{{ sat.launched }}</td>
|
||||
<td>{{ sat.website }}</td>
|
||||
<td>{{ sat.dashboard_url }}</td>
|
||||
<td><span class="align-middle flag-icon flag-icon-{{ sat.country.code|lower }}"></span></td>
|
||||
{% if perms.base.change_satellite %}
|
||||
<td><button type="button" class="bs-modal btn btn-sm btn-satnogs-primary"
|
||||
data-form-url="{% url 'update_satellite' sat.id %}">
|
||||
<span class="fa fa-pencil"></span>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Satellite update modal -->
|
||||
<div class="modal fade" tabindex="-1" role="dialog" id="modal">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script src="{% static 'lib/datatables.net/js/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-buttons/js/dataTables.buttons.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-responsive/js/dataTables.responsive.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-buttons/js/buttons.colVis.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-bs4/js/dataTables.bootstrap4.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-buttons-bs4/js/buttons.bootstrap4.min.js' %}"></script>
|
||||
<script src="{% static 'js/jquery.bootstrap.modal.forms.min.js' %}"></script>
|
||||
<script src="{% static 'js/satellites.js' %}"></script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,29 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %} - Search Results{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'lib/flag-icon-css/css/flag-icon.min.css' %}">
|
||||
{% endblock css %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid m-2">
|
||||
{% if results.count > 0 %}
|
||||
<h4>Your search returned multiple results:</h4>
|
||||
|
||||
{% else %}
|
||||
<h4>No results found</h4>
|
||||
<div>
|
||||
If you are looking for a satellite that we don't seem to have, please <a href="https://wiki.satnogs.org/Get_In_Touch" target="_blank">let us know</a>!
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="w-75">
|
||||
{% for satellite in results %}
|
||||
{% include 'includes/cards/satellite_card.html' with satellite=satellite %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
|
@ -1,59 +1,130 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load tags %}
|
||||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %} - Stats{% endblock %}
|
||||
|
||||
{% block top-menu-left %}
|
||||
<h5 class="mb-0 mr-3">Statistics</h5>
|
||||
{% endblock %}
|
||||
|
||||
{% block top-menu-right %}
|
||||
|
||||
<ul class="navbar-nav nav nav-pills" data-widget="treeview" role="menu" data-accordion="false" id="tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="dashboard-tab" data-toggle="tab" href="#dashboard" role="tab"
|
||||
aria-controls="dashboard" aria-selected="true"><i class="nav-icon fas fa-chart-line"></i>
|
||||
<p class="d-none d-lg-inline-block">Dashboard</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="sat-leaderboard-tab" data-toggle="tab" href="#sat-leaderboard" role="tab"
|
||||
aria-controls="sat-leaderboard" aria-selected="false">
|
||||
<i class="nav-icon fas fa-satellite"></i>
|
||||
<p class="d-none d-lg-inline-block">Satellites</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="user-leaderboard-tab" data-toggle="tab" href="#user-leaderboard" role="tab"
|
||||
aria-controls="user-leaderboard" aria-selected="false">
|
||||
<i class="nav-icon fas fa-house-user"></i>
|
||||
<p class="d-none d-lg-inline-block">Ground Stations</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Transmitter stats -->
|
||||
<div class="row text" id="transmitters-charts">
|
||||
<div class="col-md-12">
|
||||
<h2>Transmitters</h2>
|
||||
<!-- SatNOGS DB Stats -->
|
||||
<!-- The following div is managed by the tab menus -->
|
||||
<div class="col-12 tab-content pt-3 mx-2" id="myTabContent">
|
||||
|
||||
<!-- Dashboard panel -->
|
||||
<div class="tab-pane fade show active mx-1" id="dashboard" role="tabpanel" aria-labelledby="dashboard-tab">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-4">
|
||||
<div class="small-box small-box-satnogs">
|
||||
<div class="inner">
|
||||
<h3 id="stats-satellites">#</h3>
|
||||
<p>Total Satellites</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fas fa-satellite"></i>
|
||||
</div>
|
||||
<a href="{% url 'satellites' %}" class="small-box-footer">
|
||||
Satellites <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="small-box small-box-satnogs">
|
||||
<div class="inner">
|
||||
<h3 id="stats-transmitters">#</h3>
|
||||
<p>Total Transmitters</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fas fa-satellite-dish"></i>
|
||||
</div>
|
||||
<a href="{% url 'transmitters_list' %}" class="small-box-footer">
|
||||
Transmitters <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="small-box small-box-satnogs">
|
||||
<div class="inner">
|
||||
<h3 id="stats-alive">#</h3>
|
||||
<p>Alive Transmitters</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fas fa-satellite-dish"></i>
|
||||
</div>
|
||||
<a href="{% url 'transmitters_list' %}" class="small-box-footer">
|
||||
Transmitters <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="small-box small-box-satnogs">
|
||||
<div class="inner">
|
||||
<h3 id="stats-data">#</h3>
|
||||
<p>Total Data</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fas fa-database"></i>
|
||||
</div>
|
||||
<!-- <a href="#" class="small-box-footer">
|
||||
Data <i class="fas fa-arrow-circle-right"></i>
|
||||
</a> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="row stats" id="transmitters-numbers">
|
||||
<div class="col-md-4">
|
||||
<div class="col-xs-12 col-md-4">
|
||||
<div class="card satnogs-card mb-4">
|
||||
<div class="card-header background-satnogs-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="text-satnogs-header font-weight-bold m-0">Transmitter Modes</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="modes" width="300" height="300"></canvas>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-4">
|
||||
<div class="card satnogs-card mb-4">
|
||||
<div class="card-header background-satnogs-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="text-satnogs-header font-weight-bold m-0">Transmitter Bands</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="bands" width="300" height="300"></canvas>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="row">
|
||||
<p class="stats-hud">
|
||||
Total satellites
|
||||
<span class="stats-hud-num" id="stats-satellites">120</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="stats-hud">
|
||||
Total transmitters
|
||||
<span class="stats-hud-num" id="stats-transmitters">230</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="stats-hud">
|
||||
Alive transmitters
|
||||
<span class="stats-hud-num" id="stats-alive"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="stats-hud">
|
||||
Total data
|
||||
<span class="stats-hud-num" id="stats-data"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
{% if satellites and observers %}
|
||||
<!-- Data paylod stats -->
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h2>Satellites</h2>
|
||||
<table class="table table-hover">
|
||||
<div class="tab-pane fade px-2" id="sat-leaderboard" role="tabpanel"
|
||||
aria-labelledby="sat-leaderboard-tab">
|
||||
<div class="row justify-content-center">
|
||||
<h4>Satellites</h4>
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Norad ID</th>
|
||||
|
@ -76,10 +147,13 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Stations</h2>
|
||||
</div>
|
||||
<div class="tab-pane fade px-2" id="user-leaderboard" role="tabpanel"
|
||||
aria-labelledby="user-leaderboard-tab">
|
||||
<div class="row justify-content-center">
|
||||
<h4>Stations</h4>
|
||||
|
||||
<table class="table table-hover">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
|
@ -102,9 +176,10 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script src="{% static 'lib/chart.js/dist/Chart.min.js' %}"></script>
|
||||
<script src="{% static 'js/stats.js' %}"></script>
|
||||
<script src="{% static 'lib/chart.js/dist/Chart.min.js' %}"></script>
|
||||
<script src="{% static 'js/stats.js' %}"></script>
|
||||
{% endblock %}
|
|
@ -1,75 +1,76 @@
|
|||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %} - Transmitters List{% endblock %}
|
||||
{% block title %} - Transmitter List{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'lib/bootstrap-table/dist/bootstrap-table.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'lib/bootstrap-table/dist/extensions/filter-control/bootstrap-table-filter-control.min.css' %}">
|
||||
{% endblock css %}
|
||||
<link rel="stylesheet" href="{% static 'lib/datatables.net-bs4/css/dataTables.bootstrap4.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'lib/datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row trans">
|
||||
<table data-sortable="true"
|
||||
data-filter-control="true"
|
||||
data-search="true"
|
||||
data-show-columns="true"
|
||||
data-show-columns-search="true"
|
||||
id="transmitters-table">
|
||||
<div class="p-3">
|
||||
|
||||
<table id="transmitters" class="table table-sm display responsive table-striped" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-visible="false">UUID</th>
|
||||
<th data-sortable="true">Satellite</th>
|
||||
<th data-field="type"
|
||||
data-sortable="true"
|
||||
data-filter-control="select">Type</th>
|
||||
<th data-sortable="true">Description</th>
|
||||
<th data-sortable="true" data-sorter="freqSorter">Downlink</th>
|
||||
<th data-sortable="true" data-visible="false">Downlink Drift</th>
|
||||
<th data-sortable="true" data-visible="false">Uplink</th>
|
||||
<th data-sortable="true" data-visible="false">Uplink Drift</th>
|
||||
<th data-sortable="true" data-visible="false">Inverted</th>
|
||||
<th data-field="mode" data-filter-control="select">Mode</th>
|
||||
<th data-sortable="true">Baud</th>
|
||||
<th data-field="service"
|
||||
data-sortable="true"
|
||||
data-filter-control="select">Service</th>
|
||||
<th data-field="status"
|
||||
data-sortable="true"
|
||||
data-filter-control="select">Status</th>
|
||||
<th data-priority="1"></th>
|
||||
<th data-visible="false" data-priority="20">UUID</th>
|
||||
<th data-sortable="true" data-priority="1">Satellite</th>
|
||||
<th data-sortable="true" data-priority="4">Type</th>
|
||||
<th data-sortable="true" data-priority="1">Description</th>
|
||||
<th data-sortable="true" data-priority="2">Downlink</th>
|
||||
<th data-sortable="true" data-visible="false" data-priority="10">Downlink Drift</th>
|
||||
<th data-sortable="true" data-visible="false" data-priority="10">Uplink</th>
|
||||
<th data-sortable="true" data-visible="false" data-priority="10">Uplink Drift</th>
|
||||
<th data-sortable="true" data-visible="false" data-priority="10">Inverted</th>
|
||||
<th data-sortable="true" data-priority="3">Mode</th>
|
||||
<th data-sortable="true" data-priority="4">Baud</th>
|
||||
<th data-sortable="true" data-priority="10">Service</th>
|
||||
<th data-sortable="true" data-priority="10">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for trans in transmitters %}
|
||||
<tr>
|
||||
<td class='details-control'>
|
||||
<i class="fa fa-plus-square" aria-hidden="true"></i>
|
||||
</td>
|
||||
|
||||
<td>{{ trans.uuid }}</td>
|
||||
<td>
|
||||
{% if trans.satellite.norad_cat_id %}
|
||||
<a href="{% url 'satellite' norad=trans.satellite.norad_cat_id %}">
|
||||
{{ trans.satellite }}
|
||||
</a>
|
||||
{% else %}
|
||||
{{ trans.satellite }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ trans.type }}</td>
|
||||
<td>{{ trans.description }}</td>
|
||||
<td class="frequency">{{ trans.downlink_low | frq }}</td>
|
||||
<td class="frequency">{{ trans.downlink_low }}</td>
|
||||
<td>{{ trans.downlink_drift }}</td>
|
||||
<td class="frequency">{{ trans.uplink }}</td>
|
||||
<td>{{ trans.uplink_drift }}</td>
|
||||
<td>{{ trans.invert }}</td>
|
||||
<td>{{ trans.downlink_mode }}</td>
|
||||
<td>{{ trans.baud | floatformat }}</td>
|
||||
<td>{{ trans.baud }}</td>
|
||||
<td>{{ trans.service }}</td>
|
||||
<td>{{ trans.status }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script src="{% static 'lib/bootstrap-table/dist/bootstrap-table.min.js' %}"></script>
|
||||
<script src="{% static 'lib/bootstrap-table/dist/extensions/filter-control/bootstrap-table-filter-control.min.js' %}"></script>
|
||||
<script src="{% static 'js/transmitters.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net/js/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-buttons/js/dataTables.buttons.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-responsive/js/dataTables.responsive.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-buttons/js/buttons.colVis.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-bs4/js/dataTables.bootstrap4.min.js' %}"></script>
|
||||
<script src="{% static 'lib/datatables.net-buttons-bs4/js/buttons.bootstrap4.min.js' %}"></script>
|
||||
<script src="{% static 'js/transmitters.js' %}"></script>
|
||||
{% endblock %}
|
|
@ -1,24 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load tags %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %} - Settings{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="row text">
|
||||
<div class="col-md-12">
|
||||
<h2>Settings</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div>You can use this token to interact with the API.</div>
|
||||
<div>
|
||||
<code>{{ token }}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
|
@ -1,4 +1,4 @@
|
|||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
|
||||
<script src="{% static 'lib/dnt-helper/js/dnt-helper.js' %}"></script>
|
||||
<script src="{% static 'js/ga.js' %}"></script>
|
||||
|
|
|
@ -1 +1,10 @@
|
|||
<li><a href="/login/auth0">Sign Up / Log In</a></li>
|
||||
<nav>
|
||||
<ul class="nav nav-pills navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/login/auth0">
|
||||
<i class="nav-icon fas fa-sign-in-alt"></i>
|
||||
<p class="d-none d-lg-inline-block">Sign Up / Log In</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
|
@ -1,2 +1,12 @@
|
|||
<li><a href="{% url 'account_signup' %}">Sign Up</a></li>
|
||||
<li><a href="{% url 'account_login' %}">Log In</a></li>
|
||||
<nav>
|
||||
<ul class="nav nav-pills navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'account_signup' %}">
|
||||
<i class="nav-icon fas fa-user-plus"></i>
|
||||
<p class="d-none d-lg-inline-block">Sign Up</p>
|
||||
</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'account_login' %}">
|
||||
<i class="nav-icon fas fa-sign-in-alt"></i>
|
||||
<p class="d-none d-lg-inline-block">Log In</p>
|
||||
</a></li>
|
||||
</ul>
|
||||
</nav>
|
|
@ -0,0 +1,91 @@
|
|||
<div class="card card-outline card-satnogs shadow my-3">
|
||||
<a href="{% url 'satellite' norad=satellite.norad_cat_id %}">
|
||||
|
||||
<!-- Card header (Satellite name etc) -->
|
||||
<div class="card-header py-1">
|
||||
<div class="row">
|
||||
<div class="pl-1">
|
||||
<span class="card-title mr-1">{{ satellite.name }} <span class="text-sm text-truncate ml-1">{{ satellite.names }}</span></span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex ml-auto">
|
||||
{% if request.user.is_superuser and satellite.transmitter_suggestion_count %}
|
||||
<div class="mx-1">
|
||||
<span class="badge badge-warning" data-toggle="tooltip"
|
||||
title="Transmitter Suggestions">{{ satellite.transmitter_suggestion_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if satellite.countries %}
|
||||
<div>
|
||||
{% for country in satellite.countries %}
|
||||
<i class="align-middle flag-icon flag-icon-{{ country.code|lower }}"></i>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
|
||||
<!-- Satellite card body -->
|
||||
<div class="card-body satellite-card-body py-2 px-2">
|
||||
<div class="d-flex flex-row no-gutters text-nowrap align-items-center justify-content-between">
|
||||
<div class="d-flex flex-column float-left w-75 align-self-center">
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex satellite-card-body-row align-self-center justify-content-center" data-toggle="tooltip"
|
||||
title="Transmitters">
|
||||
<i class="fas fa-wifi"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex">
|
||||
{{ satellite.transmitters_count }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if satellite.telemetry_data_count %}
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex satellite-card-body-row align-self-center justify-content-center" data-toggle="tooltip"
|
||||
title="Data frames">
|
||||
<i class="fas fa-database"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex">
|
||||
{{ satellite.telemetry_data_count }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex satellite-card-body-row align-self-center justify-content-center" data-toggle="tooltip"
|
||||
title="Latest data timestamp">
|
||||
<i class="fas fa-clock"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex text-truncate">
|
||||
{{ satellite.latest_data.timestamp }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex satellite-card-body-row align-self-center justify-content-center" data-toggle="tooltip"
|
||||
title="Latest data submitter">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex text-truncate">
|
||||
{{ satellite.latest_data.station }}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex satellite-card-body-row align-self-center justify-content-center" data-toggle="tooltip"
|
||||
title="Data frames">
|
||||
<i class="fas fa-database"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex">
|
||||
No Data
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="float-right d-flex flex-column align-content-center">
|
||||
<img class="rounded img-fluid" src="{{ satellite.get_image }}" style="max-height: 82.5px;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
</a>
|
||||
</div>
|
|
@ -0,0 +1,182 @@
|
|||
<div class="card shadow card-outline {% if suggestion_card %}card-warning{% else %}card-satnogs{% endif %}">
|
||||
{% comment %}
|
||||
<div class="card-header align-items-center no-gutters">
|
||||
<div class="row px-2">
|
||||
<div class="col mr-2">
|
||||
<h5 class="card-title">{% if suggestion_card %}Suggestion - {% endif %}{{ transmitter.description }}</h5>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="row">
|
||||
<i class="fas fa-satellite fa-2x {% if satellite.status == 're-entered' %}text-satnogs-inactive{% elif transmitter.status == 'active' %}text-satnogs-active{% else %}text-satnogs-inactive{% endif %}"></i>
|
||||
<div class="btn-group" role="group">
|
||||
<btn class="btn btn-satnogs dropdown-toggle ml-3" data-toggle="dropdown" aria-expanded="false"
|
||||
id="dropdown-{{ transmitter.id }}"><i class="fas fa-bars"></i></btn>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown-{{ transmitter.id }}">
|
||||
{% if request.user.is_superuser and suggestion_card %}
|
||||
<form action="{% url 'transmitter_suggestion_handler' %}" method="post"
|
||||
id="transmitter_suggestion_handler-form">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="uuid" value="{{ transmitter.uuid }}">
|
||||
<button type="submit" name="approve" class="btn btn-satnogs btn-outline-success dropdown-item">
|
||||
<i class="fas fa-check-square mr-2"></i>
|
||||
Approve Suggestion
|
||||
</button>
|
||||
<button type="submit" name="reject" class="btn btn-satnogs btn-outline-danger dropdown-item">
|
||||
<i class="fas fa-minus-square mr-2"></i>
|
||||
Reject Suggestion
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<a class="dropdown-item" data-toggle="modal" data-target="#EditSuggestionModal-{{ transmitter.id }}">
|
||||
<i class="fas fa-edit mr-2"></i>
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="dropdown-item" data-toggle="modal" data-target="#TransmitterCitation-{{ transmitter.id }}">
|
||||
<i class="fas fa-quote-left mr-2"></i>
|
||||
Citation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endcomment %}
|
||||
<div class="card-header align-items-center no-gutters py-1">
|
||||
<div class="row">
|
||||
<span class="card-title align-self-center">{% if suggestion_card %}Suggestion - {% endif %}{{ transmitter.description }}</span>
|
||||
<div class="row ml-auto">
|
||||
<i class="fas fa-satellite fa-lg align-self-center {% if satellite.status == 're-entered' %}text-satnogs-inactive{% elif transmitter.status == 'active' %}text-satnogs-active{% else %}text-satnogs-inactive{% endif %}"></i>
|
||||
<div class="btn-group" role="group">
|
||||
<btn class="btn btn-satnogs dropdown-toggle ml-3" data-toggle="dropdown" aria-expanded="false"
|
||||
id="dropdown-{{ transmitter.id }}"><i class="fas fa-bars"></i></btn>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown-{{ transmitter.id }}">
|
||||
{% if request.user.is_superuser and suggestion_card %}
|
||||
<form action="{% url 'transmitter_suggestion_handler' %}" method="post"
|
||||
id="transmitter_suggestion_handler-form">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="uuid" value="{{ transmitter.uuid }}">
|
||||
<button type="submit" name="approve" class="btn btn-satnogs btn-outline-success dropdown-item">
|
||||
<i class="fas fa-check-square mr-2"></i>
|
||||
Approve Suggestion
|
||||
</button>
|
||||
<button type="submit" name="reject" class="btn btn-satnogs btn-outline-danger dropdown-item">
|
||||
<i class="fas fa-minus-square mr-2"></i>
|
||||
Reject Suggestion
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<a class="dropdown-item update-transmitter-link" data-toggle="modal" href="#"
|
||||
data-form-url="{% url 'update_transmitter' transmitter.id %}">
|
||||
<i class="fas fa-edit mr-2"></i>
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="dropdown-item" data-toggle="modal" data-target="#TransmitterCitation-{{ transmitter.id }}">
|
||||
<i class="fas fa-quote-left mr-2"></i>
|
||||
Citation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="col-12">
|
||||
{% if transmitter.type %}
|
||||
{% include "includes/field.html" with name="Type" value=transmitter.type %}
|
||||
{% endif %}
|
||||
{% if transmitter.service %}
|
||||
{% include "includes/field.html" with name="Service" value=transmitter.service %}
|
||||
{% endif %}
|
||||
{% if transmitter.downlink_mode %}
|
||||
{% include "includes/field.html" with name="Downlink Mode" value=transmitter.downlink_mode %}
|
||||
{% endif %}
|
||||
{% if transmitter.uplink_mode %}
|
||||
{% include "includes/field.html" with name="Uplink Mode" value=transmitter.uplink_mode %}
|
||||
{% endif %}
|
||||
{% if transmitter.baud %}
|
||||
{% include "includes/field.html" with name="Baud" value=transmitter.baud %}
|
||||
{% endif %}
|
||||
{% if transmitter.type == 'Transmitter' %}
|
||||
{% if transmitter.downlink_low %}
|
||||
{% include "includes/field.html" with name="Downlink" value=transmitter.downlink_low hz=transmitter.downlink_low %}
|
||||
{% endif %}
|
||||
{% if transmitter.downlink_drift %}
|
||||
{% include "includes/field.html" with name="Downlink Drifted" value=transmitter.downlink_drift hz=transmitter.downlink_drift class="drifted" freq_or=transmitter.downlink_low %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if transmitter.type == 'Transceiver' %}
|
||||
{% if transmitter.downlink_low %}
|
||||
{% include "includes/field.html" with name="Downlink" value=transmitter.downlink_low hz=transmitter.downlink_low %}
|
||||
{% endif %}
|
||||
{% if transmitter.downlink_drift %}
|
||||
{% include "includes/field.html" with name="Downlink Drifted" value=transmitter.downlink_drift hz=transmitter.downlink_drift class="drifted" freq_or=transmitter.downlink_low %}
|
||||
{% endif %}
|
||||
{% if transmitter.uplink_low %}
|
||||
{% include "includes/field.html" with name="Uplink" value=transmitter.uplink_low hz=transmitter.uplink_low %}
|
||||
{% endif %}
|
||||
{% if transmitter.uplink_drift %}
|
||||
{% include "includes/field.html" with name="Uplink Drifted" value=transmitter.uplink_drift hz=transmitter.uplink_drift class="drifted" freq_or=transmitter.uplink_low %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if transmitter.type == 'Transponder' %}
|
||||
{% if transmitter.downlink_low %}
|
||||
{% include "includes/field.html" with name="Downlink Low" value=transmitter.downlink_low hz=transmitter.downlink_low %}
|
||||
{% endif %}
|
||||
{% if transmitter.downlink_high %}
|
||||
{% include "includes/field.html" with name="Downlink High" value=transmitter.downlink_high hz=transmitter.downlink_high %}
|
||||
{% endif %}
|
||||
{% if transmitter.downlink_drift %}
|
||||
{% include "includes/field.html" with name="Downlink Drift" value=transmitter.downlink_drift hz=transmitter.downlink_drift %}
|
||||
{% endif %}
|
||||
{% if transmitter.uplink_low %}
|
||||
{% include "includes/field.html" with name="Uplink Low" value=transmitter.uplink_low hz=transmitter.uplink_low %}
|
||||
{% endif %}
|
||||
{% if transmitter.uplink_high %}
|
||||
{% include "includes/field.html" with name="Uplink High" value=transmitter.uplink_high hz=transmitter.uplink_high %}
|
||||
{% endif %}
|
||||
{% if transmitter.uplink_drift %}
|
||||
{% include "includes/field.html" with name="Uplink Drift" value=transmitter.uplink_drift hz=transmitter.uplink_drift %}
|
||||
{% endif %}
|
||||
{% if transmitter.invert %}
|
||||
{% include "includes/field.html" with name="Invert" value=transmitter.invert %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer align-items-baseline justify-content-between transmitter-card-footer">
|
||||
Updated on {{ transmitter.created|date:'Y-m-d H:i' }} by {{ transmitter.user }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Citation Modal -->
|
||||
<div class="modal fade" id="TransmitterCitation-{{ transmitter.id }}" tabindex="-1" role="dialog"
|
||||
aria-labelledby="CitationModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="CitationModalLabel">Citation for {{ transmitter.uuid }}</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ transmitter.citation }}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit Suggestion Modal -->
|
||||
{% comment %}
|
||||
<div class="modal fade transmitter_suggestion-modal" id="EditSuggestionModal-{{ transmitter.id }}" tabindex="-1"
|
||||
role="dialog" aria-labelledby="EditSuggestionModalLabel" aria-hidden="true">
|
||||
{% include 'includes/transmitter_suggestion_modal.html' with transmitter=transmitter %}
|
||||
</div>
|
||||
{% endcomment %}
|
|
@ -1,8 +1,8 @@
|
|||
<div class="row transmitter-element">
|
||||
<div class="col-md-5">
|
||||
<span class="label label-default">{{ name }}</span>
|
||||
<div class="col-md-6">
|
||||
<span class="badge badge-secondary satellite-detail-badge">{{ name }}</span>
|
||||
</div>
|
||||
<div class="col-md-7" {% if hz %}
|
||||
<div class="col-md-6" {% if hz %}
|
||||
{% if freq_or %}
|
||||
data-toggle="tooltip" data-placement="bottom" title="{{ hz }} ppb"
|
||||
{% else %}
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
<li><a href="/logout">Logout</a></li>
|
||||
<a class="nav-link" href="/logout">
|
||||
<i class="nav-icon fas fa-sign-out-alt"></i>
|
||||
<p>Logout</p>
|
||||
</a>
|
|
@ -1 +1,4 @@
|
|||
<li><a href="{% url 'account_logout' %}">Logout</a></li>
|
||||
<a class="nav-link" href="{% url 'account_logout' %}">
|
||||
<i class="nav-icon fas fa-sign-out-alt"></i>
|
||||
<p>Logout</p>
|
||||
</a>
|
|
@ -0,0 +1,33 @@
|
|||
{% load static %}
|
||||
<div class="row d-flex" id="search">
|
||||
<div class="col-lg-7">
|
||||
<input type="text" list="satellites-list"
|
||||
class="border rounded form-control form-control-sm satellite-search"
|
||||
placeholder="Search by Name or NORAD Cat ID"
|
||||
autocomplete="off">
|
||||
</div>
|
||||
<div class="col-lg-5 d-flex d-lg-flex align-self-center justify-content-lg-center align-items-lg-center">
|
||||
<p class="d-inline-flex align-items-lg-center statistics" title="satellites" data-toggle="tooltip">
|
||||
<img src="{% static 'img/satellites.png' %}">
|
||||
{{ statistics.total_satellites }}
|
||||
</p>
|
||||
<p class="d-inline-flex align-items-lg-center statistics" title="transmitters" data-toggle="tooltip">
|
||||
<img src="{% static 'img/transmitters.png' %}">
|
||||
{{ statistics.transmitters }}
|
||||
</p>
|
||||
{% if transmitter_suggestions %}
|
||||
<p class="d-inline-flex align-items-lg-center statistics" title="transmitter_suggestions" data-toggle="tooltip">
|
||||
<img src="{% static 'img/transmitter_suggestions.png' %}">
|
||||
{{ transmitter_suggestions }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="d-inline-flex align-items-lg-center statistics" title="telemetry" data-toggle="tooltip">
|
||||
<img src="{% static 'img/payloads.png' %}">
|
||||
{{ statistics.total_data }}
|
||||
</p>
|
||||
<p class="d-inline-flex align-items-lg-center statistics" title="contributors" data-toggle="tooltip">
|
||||
<img src="{% static 'img/contributors.png' %}">
|
||||
{{ contributors }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
{% load staticfiles %}
|
||||
{% load static %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'css/stage.css' %}">
|
||||
|
|
43
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "satnogs-db",
|
||||
"version": "0.1.0",
|
||||
"description": "Satellite Transmitter Suggestions Appp",
|
||||
"description": "Satellite and Transmitter Database",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://gitlab.com/librespacefoundation/satnogs/satnogs-db"
|
||||
|
@ -11,20 +11,29 @@
|
|||
"devDependencies": {
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-eslint": "^6.0.0",
|
||||
"gulp-stylelint": "^9.0.0",
|
||||
"stylelint": "^11.0.0"
|
||||
"gulp-stylelint": "^13.0.0",
|
||||
"minimist": "^1.2.5",
|
||||
"stylelint": "^13.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^3.4.1",
|
||||
"bootstrap-table": "^1.17.0",
|
||||
"chart.js": "^2.8.0",
|
||||
"admin-lte": "^3.0",
|
||||
"bootstrap": "^4.5.0",
|
||||
"chart.js": "^2.9.3",
|
||||
"datatables.net": "^1.10.21",
|
||||
"datatables.net-bs4": "^1.10.21",
|
||||
"datatables.net-buttons-bs4": "^1.6.2",
|
||||
"datatables.net-responsive": "^2.2.5",
|
||||
"dnt-helper": "github:schalkneethling/dnt-helper",
|
||||
"flag-icon-css": "^3.5.0",
|
||||
"flot": "^4.2.1",
|
||||
"gpredict.js": "github:kerel-fs/gpredict.js",
|
||||
"jquery": "^3.4.1",
|
||||
"mapbox-gl": "^1.3.1",
|
||||
"moment": "^2.24.0"
|
||||
"jquery": "^3.5.1",
|
||||
"mapbox-gl": "^1.11.0",
|
||||
"moment": "^2.27.0",
|
||||
"popper.js": "^1.16.1"
|
||||
},
|
||||
"assets": [
|
||||
"admin-lte/**/*",
|
||||
"bootstrap/dist/css/bootstrap.min.css",
|
||||
"bootstrap/dist/js/bootstrap.min.js",
|
||||
"bootstrap/dist/fonts/*",
|
||||
|
@ -33,11 +42,25 @@
|
|||
"bootstrap-table/dist/extensions/filter-control/bootstrap-table-filter-control.min.css",
|
||||
"bootstrap-table/dist/extensions/filter-control/bootstrap-table-filter-control.min.js",
|
||||
"chart.js/dist/Chart.min.js",
|
||||
"d3/dist/d3.min.js",
|
||||
"datatables.net/js/jquery.dataTables.min.js",
|
||||
"datatables.net-bs4/css/dataTables.bootstrap4.min.css",
|
||||
"datatables.net-bs4/js/dataTables.bootstrap4.min.js",
|
||||
"datatables.net-buttons/js/*",
|
||||
"datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css",
|
||||
"datatables.net-buttons-bs4/js/buttons.bootstrap4.min.js",
|
||||
"datatables.net-responsive/js/dataTables.responsive.min.js",
|
||||
"dnt-helper/js/dnt-helper.js",
|
||||
"flag-icon-css/**/*",
|
||||
"flot/dist/**/*",
|
||||
"gpredict.js/dist/gpredict.min.js",
|
||||
"jquery/dist/jquery.min.js",
|
||||
"mapbox-gl/dist/mapbox-gl.css",
|
||||
"mapbox-gl/dist/mapbox-gl.js",
|
||||
"moment/min/moment.min.js"
|
||||
"moment/min/moment.min.js",
|
||||
"pace/dist/**/*",
|
||||
"popper.js/dist/umd/popper.min.js",
|
||||
"sparklines/dist/**/*",
|
||||
"summernote/dist/**/*"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
# './contrib/refresh-requirements.sh to regenerate this file
|
||||
-r requirements.txt
|
||||
|
||||
Faker==4.1.1
|
||||
apipkg==1.5
|
||||
appdirs==1.4.4
|
||||
click==7.1.2
|
||||
coverage==5.2
|
||||
coverage==5.2.1
|
||||
distlib==0.3.1
|
||||
docopt==0.6.1
|
||||
docopts==0.6.1
|
||||
execnet==1.7.1
|
||||
factory-boy==2.12.0
|
||||
Faker==4.1.1
|
||||
filelock==3.0.12
|
||||
mock==4.0.2
|
||||
more-itertools==8.4.0
|
||||
|
@ -22,13 +22,13 @@ pluggy==0.13.1
|
|||
pur==5.3.0
|
||||
py==1.9.0
|
||||
pyparsing==2.4.7
|
||||
pytest==5.4.3
|
||||
pytest-cov==2.10.0
|
||||
pytest-django==3.9.0
|
||||
pytest-forked==1.2.0
|
||||
pytest-xdist==1.33.0
|
||||
pytest==5.4.3
|
||||
text-unidecode==1.3
|
||||
toml==0.10.1
|
||||
tox==3.16.1
|
||||
virtualenv==20.0.26
|
||||
virtualenv==20.0.28
|
||||
wcwidth==0.2.5
|
||||
|
|
|
@ -11,23 +11,27 @@ celery==4.3.0
|
|||
certifi==2020.6.20
|
||||
cffi==1.14.0
|
||||
chardet==3.0.4
|
||||
cryptography==2.9.2
|
||||
cryptography==3.0
|
||||
defusedxml==0.6.0
|
||||
dj-database-url==0.5.0
|
||||
Django==2.2.14
|
||||
django-allauth==0.42.0
|
||||
django-appconf==1.0.4
|
||||
django-avatar==5.0.0
|
||||
django-bootstrap-modal-forms==2.0.0
|
||||
django-compressor==2.4
|
||||
django-countries==6.1.2
|
||||
django-crispy-forms==1.9.2
|
||||
django-csp==3.6
|
||||
django-debug-toolbar==2.2
|
||||
django-filter==2.3.0
|
||||
django-fontawesome-5==1.0.18
|
||||
django-jsonfield==1.3.1
|
||||
django-redis-cache==2.0.0
|
||||
django-shortuuidfield==0.1.3
|
||||
django-widget-tweaks==1.4.8
|
||||
djangorestframework==3.10.3
|
||||
dnspython==1.16.0
|
||||
dnspython==2.0.0
|
||||
enum34==1.1.10
|
||||
eventlet==0.25.2
|
||||
frozendict==1.2
|
||||
|
@ -35,6 +39,7 @@ greenlet==0.4.16
|
|||
gunicorn==19.9.0
|
||||
h5py==2.10.0
|
||||
idna==2.10
|
||||
importlib-metadata==1.7.0
|
||||
influxdb==5.3.0
|
||||
kaitaistruct==0.8
|
||||
kombu==4.6.11
|
||||
|
@ -44,7 +49,7 @@ Markdown==3.2.2
|
|||
monotonic==1.5
|
||||
msgpack==0.6.1
|
||||
mysqlclient==1.4.6
|
||||
numpy==1.19.0
|
||||
numpy==1.19.1
|
||||
oauthlib==3.1.0
|
||||
Pillow==7.2.0
|
||||
pycparser==2.20
|
||||
|
@ -64,11 +69,11 @@ requests-oauthlib==1.3.0
|
|||
rjsmin==1.1.0
|
||||
rush==2018.12.1
|
||||
satellitetle==0.9.0
|
||||
satnogs-decoders~=1.0
|
||||
sentry-sdk==0.16.1
|
||||
satnogs-decoders==1.7.0
|
||||
sentry-sdk==0.16.2
|
||||
sgp4==2.12
|
||||
shortuuid==1.0.1
|
||||
simplejson==3.17.0
|
||||
simplejson==3.17.2
|
||||
six==1.15.0
|
||||
social-auth-app-django==4.0.0
|
||||
social-auth-core==3.3.3
|
||||
|
@ -78,3 +83,4 @@ Unipath==1.1
|
|||
uritemplate==3.0.1
|
||||
urllib3==1.24.3
|
||||
vine==1.3.0
|
||||
zipp==3.1.0
|
||||
|
|
|
@ -59,12 +59,17 @@ install_requires =
|
|||
satellitetle~=0.9.0
|
||||
# Unsorted
|
||||
influxdb~=5.3.0
|
||||
django-widget-tweaks~=1.4.2
|
||||
django-bootstrap-modal-forms~=2.0.0
|
||||
django-fontawesome-5
|
||||
satnogs-decoders~=1.0
|
||||
simplejson~=3.17.0
|
||||
uritemplate~=3.0.0
|
||||
PyYAML~=5.3.0
|
||||
h5py~=2.10.0
|
||||
PyLD~=2.0.0
|
||||
PyLD~=2.0.2
|
||||
# Metasat
|
||||
django-countries~=6.1.2
|
||||
# Debugging
|
||||
django-debug-toolbar~=2.2.0
|
||||
# Conflict workarounds
|
||||
|
|