diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 52ad579a0ac9396855b685a580622e64be492fa5..552d19358c4b1562490caac6088486e6483682c4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -93,8 +93,9 @@ integration-test: - cd integration # TODO: cache the integration image - docker compose build - - docker compose up -d atdb-backend ldv-specification-backend && sleep 30 + - docker compose up -d atdb-backend ldv-specification-backend - docker compose run integration + allow_failure: true # TODO: fix integration test diff --git a/ldvspec/docker/docker-compose-postgres-dev.yml b/ldvspec/docker/docker-compose-postgres-dev.yml index 74d55c7804a6d52f916b6ce74f1f03543a6172ea..2769910429ab49605891edf1002756efcc062bf2 100644 --- a/ldvspec/docker/docker-compose-postgres-dev.yml +++ b/ldvspec/docker/docker-compose-postgres-dev.yml @@ -16,5 +16,10 @@ services: - ldv-spec-db:/var/lib/postgresql/data restart: always + rabbitmq: + image: rabbitmq:3-management + ports: + - "5672:5672" + volumes: - ldv-spec-db: \ No newline at end of file + ldv-spec-db: diff --git a/ldvspec/ldvspec/settings/base.py b/ldvspec/ldvspec/settings/base.py index 83325a57d7bf230b5f75d4a12dd15628cadc8e6b..4261220228a12edc0774f1ef1953e18353ac0edd 100644 --- a/ldvspec/ldvspec/settings/base.py +++ b/ldvspec/ldvspec/settings/base.py @@ -40,6 +40,7 @@ INSTALLED_APPS = [ 'uws', 'crispy_forms', 'crispy_bootstrap5', + 'widget_tweaks', ] CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" @@ -149,4 +150,3 @@ else: SESSION_COOKIE_NAME = 'ldv-spec-sessionid' CSRF_COOKIE_NAME = 'ldv-spec-csrftoken' - diff --git a/ldvspec/ldvspec/settings/dev.py b/ldvspec/ldvspec/settings/dev.py index e5ae158c35da0876de08daba963086676853e29a..99590701aba3d171a9122316fedc7d14c748d4c1 100644 --- a/ldvspec/ldvspec/settings/dev.py +++ b/ldvspec/ldvspec/settings/dev.py @@ -10,11 +10,11 @@ CORS_ORIGIN_ALLOW_ALL = True DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'USER': 'atdb_admin', - 'PASSWORD': 'atdb123', + 'USER': 'postgres', + 'PASSWORD': 'secret', 'NAME': 'ldv-spec-db', 'HOST': 'localhost', - 'PORT': '5432', + 'PORT': '5433', }, } diff --git a/ldvspec/lofardata/forms.py b/ldvspec/lofardata/forms.py index f3adf6c2623e79800ae1fdf20037111322407de1..e7d085e76d1b999fd35ded43257d41182bfc9413 100644 --- a/ldvspec/lofardata/forms.py +++ b/ldvspec/lofardata/forms.py @@ -1,20 +1,33 @@ -from django import forms +from .models import WorkSpecification, DataProductFilter + from django.forms import ModelForm -from .models import WorkSpecification class WorkSpecificationForm(ModelForm): - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['inputs'].required = False + self.fields['predecessor_specification'].required = False + self.fields['filters'].required = False + + def _extract_filters(self): + filter_names = [filter_name[0] for filter_name in DataProductFilter.objects.all().values_list('field')] + filters = {} + for filter_name in filter_names: + if filter_name in self.data: + filters[filter_name] = self.data[filter_name] + return filters + + def clean(self): + self.cleaned_data = super().clean() + self.cleaned_data["filters"] = self._extract_filters() + return self.cleaned_data + class Meta: model = WorkSpecification - fields = ['filters', 'selected_workflow', 'processing_site', 'inputs', 'batch_size'] + fields = ['filters', 'selected_workflow', 'processing_site', 'predecessor_specification', 'batch_size'] labels = { - 'filters': 'Filters', 'selected_workflow': 'Selected workflow', 'processing_site': 'Processing Site (ATDB)', - 'inputs': 'Inputs', - 'batch_size': '# of files per ATDB tasks' + 'predecessor_specification': 'Predecessor work specification', + 'batch_size': 'Files per task' } diff --git a/ldvspec/lofardata/migrations/0009_auto_20221110_1307.py b/ldvspec/lofardata/migrations/0009_auto_20221110_1307.py new file mode 100644 index 0000000000000000000000000000000000000000..512cb1d6e0b28653c0b46f620fa73e65b263d7f2 --- /dev/null +++ b/ldvspec/lofardata/migrations/0009_auto_20221110_1307.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2 on 2022-11-10 13:07 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('lofardata', '0008_update_models_to_deal_with_gui'), + ] + + operations = [ + migrations.RemoveField( + model_name='workspecification', + name='predecessor_task', + ), + migrations.AlterField( + model_name='workspecification', + name='predecessor_specification', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='successor', to='lofardata.workspecification'), + ), + ] diff --git a/ldvspec/lofardata/models.py b/ldvspec/lofardata/models.py index 428da1d34b670796809501470abbc2559cfcc0e3..7a59d59ec5853fbd40ed5d6b59c5983876062448 100644 --- a/ldvspec/lofardata/models.py +++ b/ldvspec/lofardata/models.py @@ -5,6 +5,7 @@ from django.contrib.auth.models import User from django.contrib.postgres.fields import ArrayField from django.db import models from django.utils.translation import gettext_lazy as _ +from django_filters.rest_framework import FilterSet class DataLocation(models.Model): @@ -139,9 +140,8 @@ class WorkSpecification(models.Model): # Task ID's that were created in ATDB related_tasks = ArrayField(models.IntegerField(), null=True) - predecessor_task = models.IntegerField(null=True) predecessor_specification = models.ForeignKey('self', null=True, on_delete=models.DO_NOTHING, - related_name='successor') + related_name='successor', blank=True) # The query for gathering files has been executed is_ready = models.BooleanField(default=False) diff --git a/ldvspec/lofardata/static/favicon.ico b/ldvspec/lofardata/static/favicon.ico deleted file mode 100644 index 2549e55bc3d692e7eb34db9774338df576cded09..0000000000000000000000000000000000000000 Binary files a/ldvspec/lofardata/static/favicon.ico and /dev/null differ diff --git a/ldvspec/lofardata/static/lofardata/style.css b/ldvspec/lofardata/static/lofardata/style.css deleted file mode 100644 index 08798245a56c26b586fe0d988eda599b745434e8..0000000000000000000000000000000000000000 --- a/ldvspec/lofardata/static/lofardata/style.css +++ /dev/null @@ -1,193 +0,0 @@ -TD { - font-family: Raleway, serif; - font-size: 12pt; -} - -.defining, .staging, .fetching, .processing, .storing, .scrub, .scrubbing, .archiving { - font-style: italic; - color: green; -} - -.defined, .staged, .fetched, .processed, .stored, .validated, .scrubbed, .archived, .finished { - background-color: lemonchiffon; - color: blue; -} - -.active { - background-color: lemonchiffon; -} - -.max { - font-weight: bold; - background-color: lightgreen; -} - -.aggregate { - font-weight: bold; - background-color: lightgreen; -} - -.aggregate_failed { - font-weight: bold; - color: red; - background-color: lightgreen; -} - - -.error, .failed, .staging_failed, .staged_failed, .processed_failed, .scrubbed_failed, .stored_failed, .archived_failed, .on_hold { - color: red; - font-weight: bold; -} - -.processed, .ok, .running { - color: green; - font-weight: bold; -} - -.scrubbed { - color: darkgray; - font-style: italic; -} - -.processing, .processing_copying { - font-weight: bold; - background-color: lightyellow; -} - -p.title { - font-family: Raleway, serif; - font-size: 18pt; -} - -.footer { - font-family: Arial, serif; - font-size: 10pt; - font-style: italic; -} - -.ml-auto .dropdown-menu { - left: auto !important; - right: 0; -} - -.bigger { - font-size: 13pt; -} - -.info { - background-color: #E0F8F8; -} - -.form-signin { - width: 100%; - max-width: 330px; - padding: 15px; - margin: 0 auto; -} - -.form-signin .checkbox { - font-weight: 400; -} - -.form-signin .form-control { - position: relative; - box-sizing: border-box; - height: auto; - padding: 10px; - font-size: 16px; -} - -.form-signin .form-control:focus { - z-index: 2; -} - -.form-signin input[type="email"] { - margin-bottom: -1px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} - -.form-signin input[type="password"] { - margin-bottom: 10px; - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -.modal-body { - padding: 0 !important; -} - -.modal-dialog .modal-lg { - max-width: 75% !important; -} - -.modal-content { - overflow: scroll !important; -} - -.form-flex { - display: flex; -} - -.page { - position: relative; - min-height: 100vh; -} - -.content-wrap { - padding-bottom: 3.5rem; /* Footer height */ -} - -footer { - text-align: center; - padding: .4rem; - vertical-align: center; - display: block; - position: absolute; - margin-top: auto !important; - margin-bottom: 0; - bottom: 0; - left: 0; - background-color: #ded; - width: 100%; - - -webkit-box-shadow: 0 -2px 3px rgba(50, 50, 50, 0.75); - -moz-box-shadow: 0 -2px 3px rgba(50, 50, 50, 0.75); - box-shadow: 0 -2px 3px rgba(50, 50, 50, 0.75); -} - -footer p { - margin: auto; - text-shadow: 0 0 25px lightgrey; -} - -pre { - border-radius: 1rem; - padding: 1rem; - box-shadow: 2px 2px forestgreen; - color: black; - font-size: larger; - background-color: palegreen; -} - -#div_id_filters label { - display: none; -} - -#div_id_filters textarea { - width: 20rem; - pointer-events: none; - cursor: not-allowed; - color: gray; - background-color: lightgrey; - margin: 1rem auto; -} - -.info-text { - font-size: 2rem; - margin-bottom: 2rem; -} - -.bottom-bar { - justify-content: center; -} \ No newline at end of file diff --git a/ldvspec/lofardata/static/lofardata/styling/dias.css b/ldvspec/lofardata/static/lofardata/styling/dias.css new file mode 100644 index 0000000000000000000000000000000000000000..d1b6b292f7267382f3b93127abebba6d5a84b957 --- /dev/null +++ b/ldvspec/lofardata/static/lofardata/styling/dias.css @@ -0,0 +1,3698 @@ +@charset "UTF-8"; +*, +*::before, +*::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +dl { + margin: 0; +} + +dl dt, dl dd { + margin: 0; +} + +button, a, .button { + display: inline-block; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + margin: 0; + padding: 0; + border-width: 0; + font-weight: normal; + font-size: inherit; + text-decoration: none; + cursor: pointer; + line-height: 1.5; +} + +button { + #width: 0; + overflow: visible; +} + +button::-moz-focus-inner { + border: 0; + padding: 0; +} + +ul, ol { + margin: 0; + padding: 0; +} + +button, input, optgroup, select, textarea { + line-height: 1.5rem; + border: none; +} + +input, textarea { + width: 100%; + display: block; +} + +td, th { + padding: 0; + flex-grow: 1; + font-weight: inherit; +} + +/* Breakpoints ---------------------------------------------------------------------*/ +:root { + --primary: #00529b; + --primary--rgb: 0, 82, 155; + --primary--filter: invert(79%) sepia(60%) saturate(5371%) hue-rotate(199deg) brightness(122%) contrast(89%); + --primary--filter-checkbox: invert(35%) sepia(0%) saturate(5371%) hue-rotate(188deg) brightness(112%) contrast(139%); + --secondary: #00adee; + --secondary--rgb: 0, 173, 238; + --secondary--filter: invert(79%) sepia(60%) saturate(5371%) hue-rotate(199deg) brightness(122%) contrast(89%); + --secondary--filter-checkbox: invert(35%) sepia(0%) saturate(5371%) hue-rotate(188deg) brightness(112%) contrast(139%); + --red: #C11B15; + --red--rgb: 193, 27, 21; + --red--filter: invert(11%) sepia(100%) saturate(5099%) hue-rotate(358deg) brightness(86%) contrast(87%); + --warning: #F36B35; + --warning--rgb: 243, 107, 53; + --warning--filter: invert(74%) sepia(84%) saturate(5310%) hue-rotate(341deg) brightness(102%) contrast(91%); + --green: #00AA55; + --green--rgb: 0, 170, 85; + --green--filter: invert(44%) sepia(40%) saturate(1825%) hue-rotate(116deg) brightness(93%) contrast(103%); + --grey: #8c8c8c; + --light-grey: #BDBDBDFF; + --input: #585858; + --input-bg: #dae3e3; + --input-bg--darken: #dce0e0; + --border: #00adee; + --border--light: #ebedf2; + --background--main: white; + --white--filter: invert(100%); + --background--light: #f9fafc; + --background--dark: var(--text-dark); + --text: #585858; + --text--rgb: 88, 88, 88; + --text--filter: invert(36%) sepia(9%) saturate(345%) hue-rotate(182deg) brightness(94%) contrast(85%); + --highlight: rgba(var(--result--rgb), 1.0); + --faded: rgba(var(--text--rgb), 0.9); + --faded--filter: invert(33%) sepia(7%) saturate(16%) hue-rotate(177deg) brightness(86%) contrast(32%); + --medium-grey: #33363B; + --medium-grey--rgb: 51, 54, 59; + --text-dark: #262626; + --spacing: 2rem; +} + +@media (max-width: 1440px) { + :root { + --spacing: 1.5rem; + } +} + +@media (max-width: 767px) { + :root { + --spacing: 1rem; + } +} + +@font-face { + font-family: "icon-dias"; + src: url("../styling/fonts/icons/icon-dias.eot"); + src: url("../styling/fonts/icons/icon-dias.eot?#iefix") format("embedded-opentype"), url("../styling/fonts/icons/icon-dias.woff") format("woff"), url("../styling/fonts/icons/icon-dias.ttf") format("truetype"), url("../styling/fonts/icons/icon-dias.svg#icon-dias") format("svg"); + font-weight: normal; + font-style: normal; +} + +.center-text-and-icon { + display: flex; + align-items: center; +} + +.icon-after:after, .input--date:after, +.icon:before, +.section-toggle-invert + label:before, +.section-toggle + label:before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + text-decoration: none; + text-transform: none; + font-style: normal; + font-variant: normal; + text-rendering: auto; + font-family: "icon-dias", sans-serif; + font-weight: 400; + font-size: 1rem; + color: var(--primary); +} + +.icon--large:before, .icon--large:after { + font-size: 2rem; + line-height: 3rem; + width: 2rem; + text-align: center; + margin-top: -2px; +} + +.icon--medium:before, .icon--medium:after { + font-size: 1.5rem; + line-height: 2.3rem; + width: 1.5rem; + text-align: center; + margin-top: -2px; +} + +.icon--inline:before, .icon--inline:after { + right: 0.75rem; + top: 25%; + position: absolute; +} + +.icon.icon--alert:before, .section-toggle-invert + label.icon--alert:before, .section-toggle + label.icon--alert:before { + color: var(--warning); + opacity: 1; +} + +.icon--square { + width: 1.5rem; +} + +.icon--shadow { + text-shadow: 0 0 2px rgba(0, 0, 0, 0.25); +} + +.icon--color-inherit:before { + color: inherit; +} + +.icon--color-bright:before { + color: var(--light-grey); +} + +.icon--disabled { + color: var(--faded); +} + +.icon--disabled:before { + color: var(--faded); +} + +.icon-after--disabled { + color: var(--faded); +} + +.icon-after--disabled:after { + color: var(--faded); +} + +.icon-after--disabled { + color: var(--faded); +} + +.icon-after--disabled:after { + color: var(--faded); +} + +.icon--left:before { + margin-right: calc(var(--spacing) * 0.25); +} + +.icon--right:before { + margin-left: calc(var(--spacing) * 0.25); +} + +.icon--down:before { + position: relative; + top: calc(var(--spacing) * 0.1); +} + +.icon-after.icon-after--user:after, .icon-after--user.input--date:after, +.icon.icon--user:before, +.section-toggle-invert + label.icon--user:before, +.section-toggle + label.icon--user:before { + content: "b"; +} + +.icon-after.icon-after--globe:after, .icon-after--globe.input--date:after, +.icon.icon--globe:before, +.section-toggle-invert + label.icon--globe:before, +.section-toggle + label.icon--globe:before { + content: "c"; +} + +.icon-after.icon-after--facebook:after, .icon-after--facebook.input--date:after, +.icon.icon--facebook:before, +.section-toggle-invert + label.icon--facebook:before, +.section-toggle + label.icon--facebook:before { + content: "a"; +} + +.icon-after.icon-after--building:after, .icon-after--building.input--date:after, +.icon.icon--building:before, +.section-toggle-invert + label.icon--building:before, +.section-toggle + label.icon--building:before { + content: "d"; +} + +.icon-after.icon-after--random:after, .icon-after--random.input--date:after, +.icon.icon--random:before, +.section-toggle-invert + label.icon--random:before, +.section-toggle + label.icon--random:before { + content: "e"; +} + +.icon-after.icon-after--plus:after, .icon-after--plus.input--date:after, +.icon.icon--plus:before, +.section-toggle-invert + label.icon--plus:before, +.section-toggle + label.icon--plus:before { + content: "f"; +} + +.icon-after.icon-after--minus:after, .icon-after--minus.input--date:after, +.icon.icon--minus:before, +.section-toggle-invert + label.icon--minus:before, +.section-toggle + label.icon--minus:before { + content: "g"; +} + +.icon-after.icon-after--location:after, .icon-after--location.input--date:after, +.icon.icon--location:before, +.section-toggle-invert + label.icon--location:before, +.section-toggle + label.icon--location:before { + content: "h"; +} + +.icon-after.icon-after--chevron-up:after, .icon-after--chevron-up.input--date:after, +.icon.icon--chevron-up:before, +.section-toggle-invert + label.icon--chevron-up:before, +.section-toggle + label.icon--chevron-up:before { + content: "i"; +} + +.icon-after.icon-after--chevron-down:after, .icon-after--chevron-down.input--date:after, +.icon.icon--chevron-down:before, +.section-toggle-invert + label.icon--chevron-down:before, +input.section-toggle-invert:checked + label:before, +.section-toggle + label:before { + content: "j"; +} + +.icon-after.icon-after--search:after, .icon-after--search.input--date:after, +.icon.icon--search:before, +.section-toggle-invert + label.icon--search:before, +.section-toggle + label.icon--search:before { + content: "k"; +} + +.icon-after.icon-after--ellipsis-v:after, .icon-after--ellipsis-v.input--date:after, +.icon.icon--ellipsis-v:before, +.section-toggle-invert + label.icon--ellipsis-v:before, +.section-toggle + label.icon--ellipsis-v:before { + content: "l"; +} + +.icon-after.icon-after--info-circle:after, .icon-after--info-circle.input--date:after, +.icon.icon--info-circle:before, +.section-toggle-invert + label.icon--info-circle:before, +.section-toggle + label.icon--info-circle:before { + content: "m"; +} + +.icon-after.icon-after--file:after, .icon-after--file.input--date:after, +.icon.icon--file:before, +.section-toggle-invert + label.icon--file:before, +.section-toggle + label.icon--file:before { + content: "n"; +} + +.icon-after.icon-after--spinner:after, .icon-after--spinner.input--date:after, +.icon.icon--spinner:before, +.section-toggle-invert + label.icon--spinner:before, +.section-toggle + label.icon--spinner:before { + content: "o"; +} + +.icon-after.icon-after--check:after, .icon-after--check.input--date:after, +.icon.icon--check:before, +.section-toggle-invert + label.icon--check:before, +.section-toggle + label.icon--check:before { + content: "p"; +} + +.icon-after.icon-after--user-tie:after, .icon-after--user-tie.input--date:after, +.icon.icon--user-tie:before, +.section-toggle-invert + label.icon--user-tie:before, +.section-toggle + label.icon--user-tie:before { + content: "q"; +} + +.icon-after.icon-after--ban:after, .icon-after--ban.input--date:after, +.icon.icon--ban:before, +.section-toggle-invert + label.icon--ban:before, +.section-toggle + label.icon--ban:before { + content: "r"; +} + +.icon-after.icon-after--linkedin:after, .icon-after--linkedin.input--date:after, +.icon.icon--linkedin:before, +.section-toggle-invert + label.icon--linkedin:before, +.section-toggle + label.icon--linkedin:before { + content: "s"; +} + +.icon-after.icon-after--instagram:after, .icon-after--instagram.input--date:after, +.icon.icon--instagram:before, +.section-toggle-invert + label.icon--instagram:before, +.section-toggle + label.icon--instagram:before { + content: "t"; +} + +.icon-after.icon-after--times:after, .icon-after--times.input--date:after, +.icon.icon--times:before, +.section-toggle-invert + label.icon--times:before, +.section-toggle + label.icon--times:before { + content: "u"; +} + +.icon-after.icon-after--info:after, .icon-after--info.input--date:after, +.icon.icon--info:before, +.section-toggle-invert + label.icon--info:before, +.section-toggle + label.icon--info:before { + content: "v"; +} + +.icon-after.icon-after--exclamation:after, .icon-after--exclamation.input--date:after, +.icon.icon--exclamation:before, +.section-toggle-invert + label.icon--exclamation:before, +.section-toggle + label.icon--exclamation:before { + content: "w"; +} + +.icon-after.icon-after--chevron-left:after, .icon-after--chevron-left.input--date:after, +.icon.icon--chevron-left:before, +.section-toggle-invert + label.icon--chevron-left:before, +.section-toggle + label.icon--chevron-left:before { + content: "x"; +} + +.icon-after.icon-after--exclamation-triangle:after, .icon-after--exclamation-triangle.input--date:after, +.icon.icon--exclamation-triangle:before, +.section-toggle-invert + label.icon--exclamation-triangle:before, +.section-toggle + label.icon--exclamation-triangle:before { + content: "y"; +} + +.icon-after.icon-after--chevron-right:after, .icon-after--chevron-right.input--date:after, +.icon.icon--chevron-right:before, +.section-toggle-invert + label:before, +.section-toggle + label.icon--chevron-right:before, +input.section-toggle:checked + label:before { + content: "z"; +} + +.icon-after.icon-after--pen:after, .icon-after--pen.input--date:after, +.icon.icon--pen:before, +.section-toggle-invert + label.icon--pen:before, +.section-toggle + label.icon--pen:before { + content: "A"; +} + +.icon-after.icon-after--angle-down:after, .icon-after--angle-down.input--date:after, +.icon.icon--angle-down:before, +.section-toggle-invert + label.icon--angle-down:before, +.section-toggle + label.icon--angle-down:before { + content: "B"; +} + +.icon-after.icon-after--angle-up:after, .icon-after--angle-up.input--date:after, +.icon.icon--angle-up:before, +.section-toggle-invert + label.icon--angle-up:before, +.section-toggle + label.icon--angle-up:before { + content: "C"; +} + +.icon-after.icon-after--folders:after, .icon-after--folders.input--date:after, +.icon.icon--folders:before, +.section-toggle-invert + label.icon--folders:before, +.section-toggle + label.icon--folders:before { + content: "D"; +} + +.icon-after.icon-after--folder:after, .icon-after--folder.input--date:after, +.icon.icon--folder:before, +.section-toggle-invert + label.icon--folder:before, +.section-toggle + label.icon--folder:before { + content: "E"; +} + +.icon-after.icon-after--users:after, .icon-after--users.input--date:after, +.icon.icon--users:before, +.section-toggle-invert + label.icon--users:before, +.section-toggle + label.icon--users:before { + content: "F"; +} + +.icon-after.icon-after--angle-left:after, .icon-after--angle-left.input--date:after, +.icon.icon--angle-left:before, +.section-toggle-invert + label.icon--angle-left:before, +.section-toggle + label.icon--angle-left:before { + content: "H"; +} + +.icon-after.icon-after--angle-right:after, .icon-after--angle-right.input--date:after, +.icon.icon--angle-right:before, +.section-toggle-invert + label.icon--angle-right:before, +.section-toggle + label.icon--angle-right:before { + content: "I"; +} + +.icon-after.icon-after--sliders-h:after, .icon-after--sliders-h.input--date:after, +.icon.icon--sliders-h:before, +.section-toggle-invert + label.icon--sliders-h:before, +.section-toggle + label.icon--sliders-h:before { + content: "J"; +} + +.icon-after.icon-after--file-plus:after, .icon-after--file-plus.input--date:after, +.icon.icon--file-plus:before, +.section-toggle-invert + label.icon--file-plus:before, +.section-toggle + label.icon--file-plus:before { + content: "K"; +} + +.icon-after.icon-after--file-chart-line:after, .icon-after--file-chart-line.input--date:after, +.icon.icon--file-chart-line:before, +.section-toggle-invert + label.icon--file-chart-line:before, +.section-toggle + label.icon--file-chart-line:before { + content: "L"; +} + +.icon-after.icon-after--folder-plus:after, .icon-after--folder-plus.input--date:after, +.icon.icon--folder-plus:before, +.section-toggle-invert + label.icon--folder-plus:before, +.section-toggle + label.icon--folder-plus:before { + content: "M"; +} + +.icon-after.icon-after--save:after, .icon-after--save.input--date:after, +.icon.icon--save:before, +.section-toggle-invert + label.icon--save:before, +.section-toggle + label.icon--save:before { + content: "N"; +} + +.icon-after.icon-after--print:after, .icon-after--print.input--date:after, +.icon.icon--print:before, +.section-toggle-invert + label.icon--print:before, +.section-toggle + label.icon--print:before { + content: "O"; +} + +.icon-after.icon-after--file-export:after, .icon-after--file-export.input--date:after, +.icon.icon--file-export:before, +.section-toggle-invert + label.icon--file-export:before, +.section-toggle + label.icon--file-export:before { + content: "P"; +} + +.icon-after.icon-after--trash-alt:after, .icon-after--trash-alt.input--date:after, +.icon.icon--trash-alt:before, +.section-toggle-invert + label.icon--trash-alt:before, +.section-toggle + label.icon--trash-alt:before { + content: "Q"; +} + +.icon-after.icon-after--chart-network:after, .icon-after--chart-network.input--date:after, +.icon.icon--chart-network:before, +.section-toggle-invert + label.icon--chart-network:before, +.section-toggle + label.icon--chart-network:before { + content: "R"; +} + +.icon-after.icon-after--link:after, .icon-after--link.input--date:after, +.icon.icon--link:before, +.section-toggle-invert + label.icon--link:before, +.section-toggle + label.icon--link:before { + content: "S"; +} + +.icon-after.icon-after--archive:after, .icon-after--archive.input--date:after, +.icon.icon--archive:before, +.section-toggle-invert + label.icon--archive:before, +.section-toggle + label.icon--archive:before { + content: "T"; +} + +.icon-after.icon-after--arrow-right:after, .icon-after--arrow-right.input--date:after, +.icon.icon--arrow-right:before, +.section-toggle-invert + label.icon--arrow-right:before, +.section-toggle + label.icon--arrow-right:before { + content: "U"; +} + +.icon-after.icon-after--layer-plus:after, .icon-after--layer-plus.input--date:after, +.icon.icon--layer-plus:before, +.section-toggle-invert + label.icon--layer-plus:before, +.section-toggle + label.icon--layer-plus:before { + content: "V"; +} + +.icon-after.icon-after--map-marker-alt:after, .icon-after--map-marker-alt.input--date:after, +.icon.icon--map-marker-alt:before, +.section-toggle-invert + label.icon--map-marker-alt:before, +.section-toggle + label.icon--map-marker-alt:before { + content: "W"; +} + +.icon-after.icon-after--chart-bar:after, .icon-after--chart-bar.input--date:after, +.icon.icon--chart-bar:before, +.section-toggle-invert + label.icon--chart-bar:before, +.section-toggle + label.icon--chart-bar:before { + content: "X"; +} + +.icon-after.icon-after--mask:after, .icon-after--mask.input--date:after, +.icon.icon--mask:before, +.section-toggle-invert + label.icon--mask:before, +.section-toggle + label.icon--mask:before { + content: "Y"; +} + +.icon-after.icon-after--list-ul:after, .icon-after--list-ul.input--date:after, +.icon.icon--list-ul:before, +.section-toggle-invert + label.icon--list-ul:before, +.section-toggle + label.icon--list-ul:before { + content: "Z"; +} + +.icon-after.icon-after--phone-alt:after, .icon-after--phone-alt.input--date:after, +.icon.icon--phone-alt:before, +.section-toggle-invert + label.icon--phone-alt:before, +.section-toggle + label.icon--phone-alt:before { + content: "0"; +} + +.icon-after.icon-after--power-off:after, .icon-after--power-off.input--date:after, +.icon.icon--power-off:before, +.section-toggle-invert + label.icon--power-off:before, +.section-toggle + label.icon--power-off:before { + content: "1"; +} + +.icon-after.icon-after--rectangle-landscape:after, .icon-after--rectangle-landscape.input--date:after, +.icon.icon--rectangle-landscape:before, +.section-toggle-invert + label.icon--rectangle-landscape:before, +.section-toggle + label.icon--rectangle-landscape:before { + content: "2"; +} + +.icon-after.icon-after--bars:after, .icon-after--bars.input--date:after, +.icon.icon--bars:before, +.section-toggle-invert + label.icon--bars:before, +.section-toggle + label.icon--bars:before { + content: "3"; +} + +.icon-after.icon-after--arrow-to-left:after, .icon-after--arrow-to-left.input--date:after, +.icon.icon--arrow-to-left:before, +.section-toggle-invert + label.icon--arrow-to-left:before, +.section-toggle + label.icon--arrow-to-left:before { + content: "4"; +} + +.icon-after.icon-after--arrow-to-right:after, .icon-after--arrow-to-right.input--date:after, +.icon.icon--arrow-to-right:before, +.section-toggle-invert + label.icon--arrow-to-right:before, +.section-toggle + label.icon--arrow-to-right:before { + content: "5"; +} + +.icon-after.icon-after--archive-arrow-down:after, .icon-after--archive-arrow-down.input--date:after, +.icon.icon--archive-arrow-down:before, +.section-toggle-invert + label.icon--archive-arrow-down:before, +.section-toggle + label.icon--archive-arrow-down:before { + content: "6"; +} + +.icon-after.icon-after--archive-arrow-up:after, .icon-after--archive-arrow-up.input--date:after, +.icon.icon--archive-arrow-up:before, +.section-toggle-invert + label.icon--archive-arrow-up:before, +.section-toggle + label.icon--archive-arrow-up:before { + content: "7"; +} + +.icon-after.icon--arrow-to-bottom:after, .icon--arrow-to-bottom.input--date:after, +.icon.icon--arrow-to-bottom:before, +.section-toggle-invert + label.icon--arrow-to-bottom:before, +.section-toggle + label.icon--arrow-to-bottom:before { + content: "8"; +} + +.icon-after.icon-after--file-csv:after, .icon-after--file-csv.input--date:after, +.icon.icon--file-csv:before, +.section-toggle-invert + label.icon--file-csv:before, +.section-toggle + label.icon--file-csv:before { + content: "9"; +} + +.icon-after.icon-after--map:after, .icon-after--map.input--date:after, +.icon.icon--map:before, +.section-toggle-invert + label.icon--map:before, +.section-toggle + label.icon--map:before { + content: "!"; +} + +.icon-after.icon-after--graph:after, .icon-after--graph.input--date:after, +.icon.icon--graph:before, +.section-toggle-invert + label.icon--graph:before, +.section-toggle + label.icon--graph:before { + content: '"'; +} + +.icon-after.icon-after--twitter:after, .icon-after--twitter.input--date:after, +.icon.icon--twitter:before, +.section-toggle-invert + label.icon--twitter:before, +.section-toggle + label.icon--twitter:before { + content: "#"; +} + +.icon-after.icon-after--user-secret:after, .icon-after--user-secret.input--date:after, +.icon.icon--user-secret:before, +.section-toggle-invert + label.icon--user-secret:before, +.section-toggle + label.icon--user-secret:before { + content: "$"; +} + +.icon-after.icon-after--home:after, .icon-after--home.input--date:after, +.icon.icon--home:before, +.section-toggle-invert + label.icon--home:before, +.section-toggle + label.icon--home:before { + content: "%"; +} + +.icon-after.icon-after--envelope:after, .icon-after--envelope.input--date:after, +.icon.icon--envelope:before, +.section-toggle-invert + label.icon--envelope:before, +.section-toggle + label.icon--envelope:before { + content: "&"; +} + +.icon-after.icon-after--money-check-edit-alt:after, .icon-after--money-check-edit-alt.input--date:after, +.icon.icon--money-check-edit-alt:before, +.section-toggle-invert + label.icon--money-check-edit-alt:before, +.section-toggle + label.icon--money-check-edit-alt:before { + content: "'"; +} + +.icon-after.icon-after--calendar-plus:after, .icon-after--calendar-plus.input--date:after, +.icon.icon--calendar-plus:before, +.section-toggle-invert + label.icon--calendar-plus:before, +.section-toggle + label.icon--calendar-plus:before { + content: "("; +} + +.icon-after.icon-after--siren-on:after, .icon-after--siren-on.input--date:after, +.icon.icon--siren-on:before, +.section-toggle-invert + label.icon--siren-on:before, +.section-toggle + label.icon--siren-on:before { + content: ")"; +} + +.icon-after.icon-after--tag:after, .icon-after--tag.input--date:after, +.icon.icon--tag:before, +.section-toggle-invert + label.icon--tag:before, +.section-toggle + label.icon--tag:before { + content: "*"; +} + +.icon-after.icon-after--external-link-alt:after, .icon-after--external-link-alt.input--date:after, +.icon.icon--external-link-alt:before, +.section-toggle-invert + label.icon--external-link-alt:before, +.section-toggle + label.icon--external-link-alt:before { + content: "+"; +} + +.icon-after.icon-after--radar:after, .icon-after--radar.input--date:after, +.icon.icon--radar:before, +.section-toggle-invert + label.icon--radar:before, +.section-toggle + label.icon--radar:before { + content: ","; +} + +.icon-after.icon-after--balance-scale:after, .icon-after--balance-scale.input--date:after, +.icon.icon--balance-scale:before, +.section-toggle-invert + label.icon--balance-scale:before, +.section-toggle + label.icon--balance-scale:before { + content: "-"; +} + +.icon-after.icon-after--sign:after, .icon-after--sign.input--date:after, +.icon.icon--sign:before, +.section-toggle-invert + label.icon--sign:before, +.section-toggle + label.icon--sign:before { + content: "/"; +} + +.icon-after.icon-after--image, .icon-after--image.input--date, +.icon.icon--image:before, +.section-toggle-invert + label.icon--image:before, +.section-toggle + label.icon--image:before { + content: ";"; +} + +.icon-after.icon-after--pen-nib:after, .icon-after--pen-nib.input--date:after, +.icon.icon--pen-nib:before, +.section-toggle-invert + label.icon--pen-nib:before, +.section-toggle + label.icon--pen-nib:before { + content: ":"; +} + +.icon-after.icon-after--clock:after, .icon-after--clock.input--date:after, +.icon.icon--clock:before, +.section-toggle-invert + label.icon--clock:before, +.section-toggle + label.icon--clock:before { + content: "<"; +} + +.icon-after.icon-after--star:after, .icon-after--star.input--date:after, +.icon.icon--star:before, +.section-toggle-invert + label.icon--star:before, +.section-toggle + label.icon--star:before { + content: "="; +} + +.icon-after.icon-after--address-card:after, .icon-after--address-card.input--date:after, +.icon.icon--address-card:before, +.section-toggle-invert + label.icon--address-card:before, +.section-toggle + label.icon--address-card:before { + content: "?"; +} + +.icon-after.icon-after--comment-alt-exclamation:after, .icon-after--comment-alt-exclamation.input--date:after, +.icon.icon--comment-alt-exclamation:before, +.section-toggle-invert + label.icon--comment-alt-exclamation:before, +.section-toggle + label.icon--comment-alt-exclamation:before { + content: "@"; +} + +.icon-after.icon-after--comment-alt-dots:after, .icon-after--comment-alt-dots.input--date:after, +.icon.icon--comment-alt-dots:before, +.section-toggle-invert + label.icon--comment-alt-dots:before, +.section-toggle + label.icon--comment-alt-dots:before { + content: "["; +} + +.icon-after.icon-after--image-alt, .icon-after--image-alt.input--date, +.icon.icon--image-alt:before, +.section-toggle-invert + label.icon--image-alt:before, +.section-toggle + label.icon--image-alt:before { + content: ">"; +} + +.icon-after.icon-after--calendar-alt:after, .input--date:after, +.icon.icon--calendar-alt:before, +.section-toggle-invert + label.icon--calendar-alt:before, +.section-toggle + label.icon--calendar-alt:before { + content: "]"; +} + +.icon-after.icon-after--play:after, .icon-after--play.input--date:after, +.icon.icon--play:before, +.section-toggle-invert + label.icon--play:before, +.section-toggle + label.icon--play:before { + content: "^"; +} + +.icon-after.icon-after--pause:after, .icon-after--pause.input--date:after, +.icon.icon--pause:before, +.section-toggle-invert + label.icon--pause:before, +.section-toggle + label.icon--pause:before { + content: "_"; +} + +.icon-after.icon-after--hourglass-full:after, .icon-after--hourglass-full.input--date:after, +.icon.icon--hourglass-full:before, +.section-toggle-invert + label.icon--hourglass-full:before, +.section-toggle + label.icon--hourglass-full:before { + content: "{"; +} + +.icon-after.icon-after--hourglass-empty:after, .icon-after--hourglass-empty.input--date:after, +.icon.icon--hourglass-empty:before, +.section-toggle-invert + label.icon--hourglass-empty:before, +.section-toggle + label.icon--hourglass-empty:before { + content: "`"; +} + +.icon-after.icon-after--file-alt:after, .icon-after--file-alt.input--date:after, +.icon.icon--file-alt:before, +.section-toggle-invert + label.icon--file-alt:before, +.section-toggle + label.icon--file-alt:before { + content: "|"; +} + +.icon-after.icon-after--adjust:after, .icon-after--adjust.input--date:after, +.icon.icon--adjust:before, +.section-toggle-invert + label.icon--adjust:before, +.section-toggle + label.icon--adjust:before { + content: "}"; +} + +.icon-after.icon-after--dna:after, .icon-after--dna.input--date:after, +.icon.icon--dna:before, +.section-toggle-invert + label.icon--dna:before, +.section-toggle + label.icon--dna:before { + content: "~"; +} + +.icon-after.icon-after--database:after, .icon-after--database.input--date:after, +.icon.icon--database:before, +.section-toggle-invert + label.icon--database:before, +.section-toggle + label.icon--database:before { + content: "\\"; +} + +.icon-after.icon-after--tree-palm:after, .icon-after--tree-palm.input--date:after, +.icon.icon--tree-palm:before, +.section-toggle-invert + label.icon--tree-palm:before, +.section-toggle + label.icon--tree-palm:before { + content: "\e000"; +} + +.icon-after.icon-after--checkbox:after, .icon-after--checkbox.input--date:after, +.icon.icon--checkbox:before, +.section-toggle-invert + label.icon--checkbox:before, +.section-toggle + label.icon--checkbox:before { + content: "\e001"; +} + +.icon-after.icon-after--arrows:after, .icon-after--arrows.input--date:after, +.icon.icon--arrows:before, +.section-toggle-invert + label.icon--arrows:before, +.section-toggle + label.icon--arrows:before { + content: "\e002"; +} + +.icon-after.icon-after--bookmark:after, .icon-after--bookmark.input--date:after, +.icon.icon--bookmark:before, +.section-toggle-invert + label.icon--bookmark:before, +.section-toggle + label.icon--bookmark:before { + content: "\e003"; +} + +.icon-after.icon-after--bookmark-o:after, .icon-after--bookmark-o.input--date:after, +.icon.icon--bookmark-o:before, +.section-toggle-invert + label.icon--bookmark-o:before, +.section-toggle + label.icon--bookmark-o:before { + content: "\e004"; +} + +.icon-after.icon-after--file-code:after, .icon-after--file-code.input--date:after, +.icon.icon--file-code:before, +.section-toggle-invert + label.icon--file-code:before, +.section-toggle + label.icon--file-code:before { + content: "\e005"; +} + +.icon-after.icon-after--thumbs-up:after, .icon-after--thumbs-up.input--date:after, +.icon.icon--thumbs-up:before, +.section-toggle-invert + label.icon--thumbs-up:before, +.section-toggle + label.icon--thumbs-up:before { + content: "\e006"; +} + +.icon-after.icon-after--map-marker-check:after, .icon-after--map-marker-check.input--date:after, +.icon.icon--map-marker-check:before, +.section-toggle-invert + label.icon--map-marker-check:before, +.section-toggle + label.icon--map-marker-check:before { + content: "\e007"; +} + +.icon-after.icon-after--sticky-note:after, .icon-after--sticky-note.input--date:after, +.icon.icon--sticky-note:before, +.section-toggle-invert + label.icon--sticky-note:before, +.section-toggle + label.icon--sticky-note:before { + content: "\e008"; +} + +.icon-after.icon-after--camera:after, .icon-after--camera.input--date:after, +.icon.icon--camera:before, +.section-toggle-invert + label.icon--camera:before, +.section-toggle + label.icon--camera:before { + content: "\e009"; +} + +.icon-after.icon-after--file-upload:after, .icon-after--file-upload.input--date:after, +.icon.icon--file-upload:before, +.section-toggle-invert + label.icon--file-upload:before, +.section-toggle + label.icon--file-upload:before { + content: "\e00a"; +} + +.icon-after.icon-after--circle:after, .icon-after--circle.input--date:after, +.icon.icon--circle:before, +.section-toggle-invert + label.icon--circle:before, +.section-toggle + label.icon--circle:before { + content: "\e00b"; +} + +.icon-after.icon-after--copy:after, .icon-after--copy.input--date:after, +.icon.icon--copy:before, +.section-toggle-invert + label.icon--copy:before, +.section-toggle + label.icon--copy:before { + content: "\e00c"; +} + +.icon-after.icon-after--keyboard:after, .icon-after--keyboard.input--date:after, +.icon.icon--keyboard:before, +.section-toggle-invert + label.icon--keyboard:before, +.section-toggle + label.icon--keyboard:before { + content: "\e00d"; +} + +.icon-after.icon-after--cog:after, .icon-after--cog.input--date:after, +.icon.icon--cog:before, +.section-toggle-invert + label.icon--cog:before, +.section-toggle + label.icon--cog:before { + content: "\e00e"; +} + +.icon-after.icon-after--star-half-alt:after, .icon-after--star-half-alt.input--date:after, +.icon.icon--star-half-alt:before, +.section-toggle-invert + label.icon--star-half-alt:before, +.section-toggle + label.icon--star-half-alt:before { + content: "\e00f"; +} + +.icon-after.icon-after--star-empty:after, .icon-after--star-empty.input--date:after, +.icon.icon--star-empty:before, +.section-toggle-invert + label.icon--star-empty:before, +.section-toggle + label.icon--star-empty:before { + content: "\e010"; +} + +.icon-after.icon-after--eye:after, .icon-after--eye.input--date:after, +.icon.icon--eye:before, +.section-toggle-invert + label.icon--eye:before, +.section-toggle + label.icon--eye:before { + content: "\e011"; +} + +.icon-after.icon-after--google-account:after, .icon-after--google-account.input--date:after, +.icon.icon--google-account:before, +.section-toggle-invert + label.icon--google-account:before, +.section-toggle + label.icon--google-account:before { + content: "\e012"; +} + +.icon-after.icon-after--google-places:after, .icon-after--google-places.input--date:after, +.icon.icon--google-places:before, +.section-toggle-invert + label.icon--google-places:before, +.section-toggle + label.icon--google-places:before { + content: "\e013"; +} + +.icon-after.icon-after--review:after, .icon-after--review.input--date:after, +.icon.icon--review:before, +.section-toggle-invert + label.icon--review:before, +.section-toggle + label.icon--review:before { + content: "\e014"; +} + +.icon-after.icon-after--building-info:after, .icon-after--building-info.input--date:after, +.icon.icon--building-info:before, +.section-toggle-invert + label.icon--building-info:before, +.section-toggle + label.icon--building-info:before { + content: "\e015"; +} + +.icon-after.icon-after--galaxy:after, .icon-after--galaxy.input--date:after, +.icon.icon--galaxy:before, +.section-toggle-invert + label.icon--galaxy:before, +.section-toggle + label.icon--galaxy:before { + content: "🌌"; +} + +/* Text styles -------------------------------------------------------*/ +html { + font-family: Raleway; + font-size: 16px; + line-height: 1.5rem; + color: var(--text); +} + +@supports (font-feature-settings: normal) { + html { + font-feature-settings: "ss02" on; + } +} + +@media (max-width: 1440px) { + html { + font-size: 14px; + } +} + +.h1, .modal-dias__title, .section-toggle-invert, .section-toggle, +.h2, +.h3, +.item-list__title, +.h4, +h1, +h2, +h3, +h4 { + font-weight: 600; + color: var(--text-dark); +} + +.h1, .modal-dias__title, .section-toggle-invert, .section-toggle, +h1 { + font-size: 1.5rem; + line-height: 2rem; + margin: 0 0 1.5rem; +} + +.h2, +h2 { + font-size: 1.25rem; + line-height: 1.5rem; + margin: 1.5rem 0 0.5rem; +} + +.h3, .item-list__title, +h3 { + font-size: 1rem; + line-height: 1.5rem; + margin: 1.5rem 0 0.5rem; +} + +.h4, +h4 { + font-size: calc(1rem - 1px); + line-height: 1.5rem; + margin: 0; +} + +.title-wrapper { + display: flex; + flex-wrap: wrap; +} + +.title-wrapper .title { + margin: 0; +} + +.title-wrapper .title--left { + margin-right: calc(var(--spacing) * 0.25); +} + +.title--wide { + flex: 1 1 100%; +} + +.title.icon:before, .section-toggle-invert + label.title:before, .section-toggle + label.title:before { + margin-right: calc(var(--spacing) * 0.25); +} + +.subtitle { + font-size: calc(1em - 2px); + margin: 0; + color: var(--faded); + flex: 1 1 100%; +} + +time { + font-feature-settings: "tnum" on; +} + +p a { + color: var(--primary); + text-decoration: underline; +} + +p a:hover { + text-decoration: none; +} + +a { + color: var(--primary); +} + +.link { + text-decoration: underline; + display: inline-block; +} + +.link:hover { + cursor: pointer; +} + +.link:before { + top: 2px; + text-decoration: none; + position: relative; +} + +.link--faded { + color: var(--faded); +} + +.link--faded:before { + color: var(--faded); +} + +.link--plain-text { + color: var(--text); + text-decoration: none; +} + +.link--plain-text:visited { + color: var(--text); + text-decoration: none; +} + +.link-static-parent { + position: relative; +} + +.link--static-sibling { + z-index: 1; +} + +.link--static { + position: static; +} + +.link--static:after { + content: ""; + position: absolute; + z-index: 0; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.link--show-more { + margin-left: calc(var(--spacing) * 0.125); +} + +.link--small { + font-size: calc(1rem - 2px); +} + +@media (max-width: 1024px) { + .link--small { + font-size: calc(1rem - 1px); + } +} + +.link--red { + color: var(--red); +} + +.link--disabled { + color: var(--text); + cursor: not-allowed; +} + +.note-text { + color: var(--faded); + font-size: calc(1rem - 2px); + margin: 0; +} + +@media (max-width: 1024px) { + .note-text { + font-size: calc(1rem - 1px); + } +} + +.text--capitalized { + text-transform: capitalize; +} + +.text--only-first-letter-capitalized:first-letter { + text-transform: uppercase; +} + +.text--uppercased { + text-transform: uppercase; + font-size: 12px; +} + +.text--multiline { + white-space: pre-wrap; +} + +.text--faded { + color: var(--faded); +} + +.text--faded:before { + color: var(--faded); +} + +.text--small { + font-size: calc(1rem - 2px); +} + +@media (max-width: 1024px) { + .text--small { + font-size: calc(1rem - 1px); + } +} + +.text--semi-bold { + font-weight: 600; +} + +.text--bold { + font-weight: 700; + color: var(--text-dark); +} + +.text--title { + font-weight: 500; + color: var(--text-dark); +} + +.text--red { + color: var(--red); +} + +.text--white { + color: var(--background--main); +} + +.text--primary { + color: var(--primary); +} + +.editable-text { + color: var(--text); +} + +.editable-text .button { + padding-left: calc(var(--spacing) * 0.125); + padding-top: 0; +} + +.editable-text--footer { + margin-top: calc(var(--spacing) * 0.25); +} + +.h-navbar { + display: flex; + width: 100%; + justify-content: space-between; +} + +.h-navbar--dark { + background: var(--background--dark); +} + +.h-navbar ol, .h-navbar ul { + list-style: none outside none; +} + +.h-navbar-link { + color: var(--grey); +} + +.h-navbar-link:hover { + color: var(--light-grey); + text-decoration: none; +} + +.h-navbar-link--active { + color: white; +} + +.h-navbar-link--dropdown { + background: inherit; + font-size: inherit; +} + +.h-navbar-link--option { + background: var(--background--dark); +} + +.h-navbar-list { + display: flex; + flex-direction: row; +} + +.h-navbar-list__item { + height: 4rem; + display: flex; + align-items: center; +} + +.h-navbar-list__item + .h-navbar-list__item { + margin-left: 2rem; +} + +.h-navbar-list__item--active { + border-bottom: var(--primary); + border-bottom-width: 2px; + border-bottom-style: solid; +} + +.h-navbar-logo { + height: 4rem; + display: flex; + align-items: center; +} + +.v-navbar { + position: absolute; + height: 100vh; + display: flex; + flex-direction: column; + z-index: 3000; +} + +@media (max-width: 420px) { + .v-navbar { + height: 64px; + width: 100vw; + top: 0; + flex-direction: row; + } +} + +.v-navbar--dark { + background: var(--background--dark); +} + +.v-navbar .logo-link { + display: flex; + height: 64px; + width: 64px; + justify-content: center; +} + +.v-navbar .logo-link .v-nav-logo { + align-self: center; +} + +.v-navbar .v-navbar-list { + display: flex; + flex-direction: column; + flex: 1; + justify-content: space-between; +} + +@media (max-width: 420px) { + .v-navbar .v-navbar-list { + flex-direction: row; + } +} + +.v-navbar .v-navbar-list__wrapper { + display: flex; + flex-direction: column; +} + +@media (max-width: 420px) { + .v-navbar .v-navbar-list__wrapper { + flex-direction: row; + } +} + +.v-navbar .v-navbar-list__item { + transition: opacity .25s ease-in-out; + position: relative; + display: flex; + margin: 0; + justify-content: center; + text-decoration: none; + line-height: 24px; +} + +.v-navbar .v-navbar-list__item:hover { + opacity: 1; +} + +.v-navbar .v-navbar-list__item:after { + transition: background .25s ease-in-out, left .25s ease-in-out, top .25s ease-in-out; + position: absolute; + content: ""; + top: 0; + right: 0; + bottom: 0; + left: 100%; + opacity: 0.25; + background: transparent; + z-index: -1; +} + +@media (max-width: 420px) { + .v-navbar .v-navbar-list__item:after { + left: 0; + top: 100%; + } +} + +.v-navbar .v-navbar-list__item:hover:after { + left: 0; + background: var(--background--main); +} + +@media (max-width: 420px) { + .v-navbar .v-navbar-list__item:hover:after { + top: 0; + } +} + +.v-navbar .v-navbar-list__item--activated .v-navbar-list__link { + opacity: 1; +} + +.v-navbar .v-navbar-list__item--activated:before { + position: absolute; + content: ""; + top: 0; + right: 0; + bottom: 0; + width: 4px; + background: var(--secondary); +} + +@media (max-width: 420px) { + .v-navbar .v-navbar-list__item--activated:before { + top: inherit; + right: 0; + bottom: 0; + left: 0; + height: 4px; + width: auto; + } +} + +.v-navbar .v-navbar-list__item--activated-icon { + border-bottom: 2px solid var(--grey); +} + +.v-navbar .v-navbar-list__item--activated-icon .v-navbar-list__link { + opacity: 1; +} + +.v-navbar .v-navbar-list__item--activated-icon:before { + position: absolute; + top: 20%; + right: 5%; + bottom: 0; + color: var(--grey); +} + +@media (max-width: 420px) { + .v-navbar .v-navbar-list__item--activated-icon:before { + top: inherit; + right: 0; + bottom: 0; + left: 0; + height: 4px; + width: auto; + } +} + +.v-navbar .v-navbar-list__link { + color: var(--secondary); + text-align: center; + height: 64px; + width: 64px; + display: flex; + justify-content: center; + align-items: center; +} + +html { + scrollbar-width: thin; +} + +.content-wrapper { + margin-left: 5.5rem; + display: flex; + flex-direction: column; + flex: 1 1 auto; +} + +.content-wrapper--one-column { + align-items: center; + min-height: 100vh; +} + +@media (max-width: 420px) { + .content-wrapper { + margin-left: 0; + margin-top: 64px; + } +} + +.content-wrapper--main { + margin-left: 0; + flex: 10 1 auto; +} + +.content-wrapper__inner { + display: flex; + flex: 1 1 auto; + background: white; +} + +.content-wrapper__inner--fixed-width { + width: 10rem; +} + +.content-wrapper--main .content-wrapper__inner { + margin: 0 var(--spacing) var(--spacing); + flex-direction: column; + min-height: auto; +} + +.results-wrapper { + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.results-wrapper--one-column { + max-width: 1312px; + width: 100%; + padding: calc(var(--spacing) * 2); +} + +.results-wrapper__inner { + display: flex; + flex: 0 1 auto; + flex-wrap: wrap; + margin: 0; + padding: 2rem 0; + box-shadow: inset 0 -1px 0 0 var(--border); +} + +.results-wrapper__inner .section-wrapper { + display: flex; + flex: 1 1 auto; + flex-direction: column; + margin-top: var(--spacing); +} + +.results-wrapper__inner .section-wrapper--padding { + padding: 0 var(--spacing); +} + +.results-wrapper__inner:last-child { + box-shadow: none; +} + +.results-wrapper__inner:only-child { + padding: 0; +} + +.results-wrapper .single-wrapper { + flex: 1 1 auto; + justify-content: center; + align-items: center; +} + +.results-wrapper .single-wrapper__center { + text-align: center; +} + +.subject-wrapper { + padding: 0 0; +} + +.subject-wrapper .options-list__entry { + padding: 4px 0; +} + +.subject-wrapper > * + * { + margin-top: calc(var(--spacing) * 1); +} + +.wrapper--full-height { + height: 1000rem; +} + +.wrapper--border-bottom { + box-shadow: inset 0 -1px 0 0 var(--border); + padding-bottom: var(--spacing); + margin-bottom: var(--spacing); +} + +.sticky-wrapper { + position: -webkit-sticky; + position: sticky; + top: 2rem; + max-height: 100vh; + scrollbar-width: thin; +} + +.sidebar__inner .sticky-wrapper { + top: 0; + padding: var(--spacing); + overflow: auto; +} + +.sidebar__inner .sticky-wrapper > *:last-child { + margin-bottom: var(--spacing); +} + +/* Elements ------------------------ */ +.item-list { + display: flex; + flex-direction: column; + list-style: none; + box-shadow: inset 0 1px 0 0 var(--border); +} + +.item-list--bullets { + padding-left: calc(var(--spacing) * 0.625); +} + +.item-list--bullets > .item-list__entry { + list-style: disc; + padding-left: 0.25rem; +} + +.item-list--bullets > .item-list__entry--no-bullet { + list-style: none; + margin-left: -1.25em; +} + +.item-list--icons .item-list__entry { + display: flex; +} + +.item-list--icons .item-list__entry > * { + margin-left: calc(var(--spacing) * 0.125); +} + +.item-list--scroll { + max-height: 15rem; + overflow-y: auto; + box-shadow: inset 0 -1px 0 0 var(--border); +} + +.item-list--actions { + flex-direction: row; +} + +.item-list--actions .item-list__entry .button { + font-size: inherit; + border: none; + padding: 0.5rem; + color: var(--text); +} + +.item-list--actions .item-list__entry .button .icon:before, .item-list--actions .item-list__entry .button .section-toggle-invert + label:before, .item-list--actions .item-list__entry .button .section-toggle + label:before { + color: var(--text); + opacity: 0.75; +} + +.item-list--actions .item-list__entry .button--danger { + color: var(--red); +} + +.item-list--actions .item-list__entry .button--danger .icon:before, .item-list--actions .item-list__entry .button--danger .section-toggle-invert + label:before, .item-list--actions .item-list__entry .button--danger .section-toggle + label:before { + color: var(--red); +} + +.item-list__entry { + transition: background-color .25s ease-in-out, color .25s ease-in-out; + box-shadow: inset 0 -1px 0 0 var(--border); + flex: 1 1 auto; + position: relative; +} + +.item-list__entry.icon:before, .section-toggle-invert + label.item-list__entry:before, .section-toggle + label.item-list__entry:before, .item-list__entry .icon:before, .item-list__entry .section-toggle-invert + label:before, .item-list__entry .section-toggle + label:before { + margin-right: calc(var(--spacing) * 0.25); + top: 2px; + position: relative; +} + +.item-list__entry .dropdown-wrapper .dropdown-list__trigger { + opacity: 0; +} + +.item-list__entry:hover { + background: var(--background--light); +} + +.item-list__entry:hover:first-of-type { + box-shadow: inset 0 -1px 0 0 var(--border), inset 0 1px 0 0 var(--border); +} + +.item-list__entry:hover .item-list__link { + padding-left: 8px; +} + +.item-list__entry:hover .dropdown-wrapper .dropdown-list__trigger { + opacity: 1; +} + +.item-list__entry--inactive .item-list__link { + color: var(--faded); +} + +.item-list__entry--inactive .icon:before, .item-list__entry--inactive .section-toggle-invert + label:before, .item-list__entry--inactive .section-toggle + label:before { + color: var(--faded); +} + +.item-list__entry--inactive:hover { + color: var(--text); +} + +.item-list__entry--inactive:hover .icon:before, .item-list__entry--inactive:hover .section-toggle-invert + label:before, .item-list__entry--inactive:hover .section-toggle + label:before { + color: var(--primary); +} + +.item-list__entry--disabled .item-list__link { + cursor: not-allowed; + color: var(--faded); +} + +.item-list__entry--disabled .tooltip { + margin-right: calc(var(--spacing) * 0.25); + padding-top: 0.625rem; +} + +.item-list__entry--disabled .icon:before, .item-list__entry--disabled .section-toggle-invert + label:before, .item-list__entry--disabled .section-toggle + label:before { + color: var(--faded); +} + +.item-list__entry--disabled:hover { + background: transparent; +} + +.item-list__entry--disabled:hover .item-list__link { + padding-left: 0; + max-width: 100%; +} + +.item-list__entry--disabled:hover .dropdown-wrapper .dropdown-list__trigger { + opacity: 0; +} + +.item-list__entry .controls { + display: none; +} + +.item-list__link { + transition: padding .25s ease-in-out; + flex: 1 1 auto; + display: block; + padding: calc(var(--spacing) * 0.25) 0 calc(var(--spacing) * 0.375); + color: var(--text); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + cursor: pointer; +} + +.item-list__link--has-tag { + width: 85%; +} + +.item-list__title { + box-shadow: inset 0 -1px 0 0 var(--border); + margin: calc(var(--spacing) * 0.5) 0 0; + padding-bottom: calc(var(--spacing) * 0.5); + display: flex; +} + +.item-list__title:first-of-type { + margin: 0; +} + +.item-list__title.icon-after:after, .item-list__title.input--date:after { + color: var(--primary); + margin-left: 8px; +} + +@media (max-width: 1024px) { + .item-list__title { + margin-top: 0; + } +} + +.item-list__title--small { + font-size: 14px; + padding: 0; +} + +.item-list--no-border, .item-list--report-list, .item-list--plain-list, .item-list--actions { + box-shadow: none; +} + +.item-list--no-border > *, .item-list--report-list > *, .item-list--plain-list > *, .item-list--actions > * { + box-shadow: none; +} + +.item-list--row { + flex-direction: row; + flex-wrap: wrap; + flex: 1 1 100%; +} + +.item-list--row .item-list__entry { + flex: 0 0 auto; + margin-right: calc(var(--spacing) * 0.25); +} + +.item-list--row .item-list__title { + padding-bottom: 0; +} + +.item-list--no-hover .item-list__entry:hover, .item-list--report-list .item-list__entry:hover, .item-list--plain-list .item-list__entry:hover, .item-list--actions .item-list__entry:hover { + background: none; + box-shadow: none; +} + +.card .item-list--plain-list .item-list__link { + padding: 0; +} + +.item-list--results { + list-style: inside; + border-radius: 4px; + background: rgba(var(--primary--rgb), 0.1); + padding: 0 calc(var(--spacing) * 0.25); + font-size: calc(1rem - 2px); + color: var(--primary); + line-height: 1.5rem; +} + +@media (max-width: 1024px) { + .item-list--results { + font-size: calc(1rem - 1px); + } +} + +.item-list--results:hover { + padding: 0 calc(var(--spacing) * 0.25); +} + +.item-list--with-title { + box-shadow: none; +} + +.item-list--with-title .item-list__entry:hover:first-of-type { + box-shadow: inset 0 -1px 0 0 var(--border); +} + +.item-list--start-report .item-list__entry { + display: flex; +} + +.item-list--start-report .item-list__link.icon-after, .item-list--start-report .item-list__link.input--date { + max-width: calc(100% - 2rem); +} + +.item-list--start-report .item-list__link.icon-after:after, .item-list--start-report .item-list__link.input--date:after { + color: var(--faded); + margin-top: -12px; + position: absolute; + right: 8px; + top: 50%; +} + +.item-list--report-list > .item-list__entry + .item-list__entry { + margin-top: calc(var(--spacing) * 0.5); +} + +.item-list--report-list > .item-list__entry:hover .item-list__link { + padding-left: 0; + max-width: 100%; +} + +.item-list--report-list .item-list__link { + padding: calc(var(--spacing) * 0.25) 0 calc(var(--spacing) * 0.5); +} + +.item-list--report-list .card { + padding: 0 calc(var(--spacing) * 0.5); +} + +.item-list--small .item-list__entry { + padding: calc(var(--spacing) * 0.125) 0; +} + +.icon-spacer:before { + content: ""; + margin-right: calc(var(--spacing) * 0.25); +} + +.page-content { + flex-basis: 100%; +} + +.loader { + border-radius: 4px; + font-size: 1rem; + font-weight: normal; + color: var(--faded); + display: flex; + align-items: center; + align-self: center; + margin-left: calc(var(--spacing) * 0.5); +} + +.loader .icon, .loader .section-toggle-invert + label:before, .loader .section-toggle + label:before { + align-self: flex-start; +} + +.loader .icon:before, .loader .section-toggle-invert + label:before, .loader .section-toggle + label:before { + padding-top: 2px; +} + +.loader--finished { + background: rgba(var(--green--rgb), 0.25); + padding: 0 calc(0.25 * var(--spacing)); + color: var(--green); +} + +.loader--finished .icon:before, .loader--finished .section-toggle-invert + label:before, .loader--finished .section-toggle + label:before { + color: var(--green); +} + +.loader--failed { + background: rgba(var(--warning--rgb), 0.25); + padding: 0 calc(0.25 * var(--spacing)); + color: var(--warning); +} + +.loader--failed .icon:before, .loader--failed .section-toggle-invert + label:before, .loader--failed .section-toggle + label:before { + color: var(--warning); +} + +.tag { + border-radius: 4px; + display: inline-flex; + height: auto; + margin: 0 0.5rem 0.5rem 0; + font-size: calc(1rem - 2px); + padding: 0 0.5rem; + background: rgba(var(--medium-grey--rgb), 0.15); +} + +@media (max-width: 1024px) { + .tag { + font-size: calc(1rem - 1px); + } +} + +.tag--counter { + margin: 0 0 calc(-0.125 * var(--spacing)) calc(0.125 * var(--spacing)); + border-radius: 0.75rem; + color: var(--text); + font-size: calc(1rem - 2px); + line-height: 1rem; + padding: 0 0.375rem; + font-weight: 500; +} + +@media (max-width: 1024px) { + .tag--counter { + font-size: calc(1rem - 1px); + } +} + +.tag--margin-left { + margin-left: 0.5rem; +} + +.tag--right { + position: absolute; + right: 0; + top: 50%; + margin-top: -12px; + margin-right: 0; +} + +.dropdown-wrapper { + list-style: none; +} + +.dropdown-wrapper .dropdown-list__trigger { + position: absolute; + right: 0; + top: 50%; + bottom: 0; + text-decoration: none; + margin-top: -0.875rem; + cursor: pointer; +} + +.dropdown-wrapper .dropdown-list__trigger:before { + color: var(--faded); +} + +.dropdown-wrapper .dropdown-list__trigger:hover .dropdown-list { + display: block; +} + +.dropdown-wrapper .dropdown-list { + border-radius: 4px; + box-shadow: 0 2px 10px -4px rgba(var(--text--rgb), 0.35); + position: absolute; + display: none; + list-style: none; + flex-direction: column; + margin-top: 0; + z-index: 2000; +} + +.table .dropdown-wrapper .dropdown-list { + right: 0; +} + +@media (max-width: 767px) { + .dropdown-wrapper .dropdown-list { + right: 0; + } +} + +.dropdown-wrapper .dropdown-list__item:not(:last-child):not(:only-of-type) .dropdown-list__link { + box-shadow: inset 0 -1px 0 0 var(--border); +} + +.dropdown-wrapper .dropdown-list__item:first-of-type:not(:only-of-type) .dropdown-list__link { + border-radius: 4px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.dropdown-wrapper .dropdown-list__item:last-of-type:not(:only-of-type) .dropdown-list__link { + border-radius: 4px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.dropdown-wrapper .dropdown-list__item:only-of-type .dropdown-list__link { + border-radius: 4px; +} + +.dropdown-wrapper .dropdown-list__link { + display: flex; + background: var(--background--light); + padding: 4px 8px; + color: var(--text); +} + +.dropdown-wrapper .dropdown-list__link:before { + margin-right: calc(var(--spacing) * 0.25); + color: var(--faded); +} + +.dropdown-wrapper .dropdown-list__link:hover { + background: var(--border); +} + +.dropdown-wrapper .dropdown-list__link--delete { + color: var(--red); +} + +.dropdown-wrapper .dropdown-list__link--delete:before { + color: var(--red); +} + +.options-wrapper { + box-shadow: inset 0 1px 0 0 var(--border); + flex: 0 1 auto; + padding: var(--spacing) 0; + margin: var(--spacing) 0; +} + +.options-wrapper > * { + margin-bottom: calc(var(--spacing) * 1); +} + +.options-wrapper > *:last-child { + margin-bottom: 0; +} + +/* Accordion toggle ------------------------ */ +.section-toggle { + cursor: pointer; + align-self: flex-start; +} + +.section-toggle:before { + margin: 0.25rem calc(var(--spacing) * 0.25) 0 0; +} + +.section-toggle + label { + margin-bottom: 0; +} + +.section-toggle ~ .section-wrapper { + height: auto; + overflow: visible; + margin-top: var(--spacing); +} + +input.section-toggle:checked + label { + margin-bottom: 0; +} + +input.section-toggle:checked ~ .section-wrapper { + height: 0; + overflow: hidden; + margin-top: 0; + display: none; +} + +.section-toggle-invert { + cursor: pointer; + align-self: flex-start; +} + +.section-toggle-invert:before { + margin: 0 calc(var(--spacing) * 0.25) 0.25rem 0; +} + +.section-toggle-invert + label { + margin-bottom: 0; +} + +.section-toggle-invert ~ .section-wrapper { + height: 0; + overflow: hidden; + margin-top: 0; + display: none; +} + +input.section-toggle-invert:checked + label { + margin-bottom: 0 calc(var(--spacing) * 0.25) 0.25rem 0; +} + +input.section-toggle-invert:checked ~ .section-wrapper { + height: auto; + overflow: visible; + margin-top: var(--spacing); + display: flex; +} + +.flex-wrapper { + display: flex; +} + +.flex-wrapper--column { + flex-direction: column; +} + +.flex-wrapper--row { + flex-direction: row; +} + +.flex-wrapper--centered { + align-items: center; + justify-content: center; +} + +.flex-wrapper--space-between { + justify-content: space-between; +} + +.flex-wrapper--start { + justify-content: flex-start; +} + +.flex-wrapper--end { + justify-content: flex-end; +} + +.margin-top { + margin-top: calc(var(--spacing) * 0.25); +} + +.margin-right { + margin-right: calc(var(--spacing) * 0.25); +} + +.margin-bottom { + margin-bottom: calc(var(--spacing) * 0.25); +} + +.margin-left { + margin-left: calc(var(--spacing) * 0.25); +} + +/*SCROLLBAR*/ +/* width */ +::-webkit-scrollbar { + width: 1rem; + height: 1rem; +} + +/* Track */ +::-webkit-scrollbar-track { + box-shadow: inset 0 0 0.5rem var(--primary); + border-radius: 1rem; +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background: var(--primary); + border-radius: 1rem; +} + +/* Handle on hover */ +::-webkit-scrollbar-thumb:hover { + background: var(--primary); +} + +/* Height bar */ +.wrapper::-webkit-scrollbar-track-piece:end { + background: transparent; + margin-bottom: 1rem; +} + +.wrapper::-webkit-scrollbar-track-piece:start { + background: transparent; + margin-top: 1rem; +} + +.table { + text-align: left; + width: 100%; + border-collapse: collapse; + display: flex; + flex: 1 1 auto; + flex-direction: column; +} + +.table .table__header { + display: flex; + flex: 0 1 auto; + font-weight: 600; + color: var(--text-dark); + font-size: calc(1rem - 2px); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.table .table__header .table__row { + box-shadow: inset 0 -2px 0 0 var(--border); +} + +.table .table__header .table__row--dark { + box-shadow: inset 0 -2px 0 0 var(--primary); +} + +.table .table__header .table__cell.table__cell--sortable { + cursor: pointer; +} + +.table .table__header .table__cell.table__cell--sortable .icon, .table .table__header .table__cell.table__cell--sortable .section-toggle + label:before, .table .table__header .table__cell.table__cell--sortable .section-toggle-invert + label:before { + margin-left: 0.25rem; +} + +.table .table__header .table__cell.table__cell--sortable .icon--active::after, .table .table__header .table__cell.table__cell--sortable .icon--active::before { + color: var(--primary); +} + +.table .table__header .table__cell.table__cell--sortable .icon--inactive::after, .table .table__header .table__cell.table__cell--sortable .icon--inactive::before { + color: var(--text); + opacity: 0.5; +} + +.table .table__link { + display: contents; + color: inherit; +} + +.table .table__link:hover > .table__cell { + background: var(--background--light); +} + +.table .table__link--active > .table__cell, .table .table__link--active:hover > .table__cell { + background: rgba(var(--primary--rgb), 0.1); +} + +.table .table__content--scroll { + overflow-y: auto; +} + +.table .table__content--scroll-large { + max-height: 90vh; +} + +.table .table__content--scroll-small { + max-height: 45vh; +} + +.table .table__row { + transition: background .25s ease-in-out; + display: flex; + flex: 1 1 auto; + justify-content: space-between; + box-shadow: inset 0 -1px 0 0 var(--border); + position: relative; + line-height: inherit; +} + +.table .table__row--dark { + box-shadow: inset 0 -1px 0 0 var(--primary); +} + +.table .table__row--active > .table__cell, .table .table__row--active:hover > .table__cell { + background: rgba(var(--primary--rgb), 0.1); +} + +.table .table__row--column { + flex-direction: column; +} + +.table .table__row--column .table__cell { + padding-right: 0; +} + +.table .table__row--column .table__cell + .table__cell { + padding-top: 0; +} + +.table .table__row--padding { + padding: 0 calc(var(--spacing) * 0.5); +} + +.table .table__row--large, .table .table__row--large a { + line-height: 2.5rem; +} + +.table .table__row--unbordered { + box-shadow: none; +} + +.table .table__row--unbordered:first-child { + padding-top: calc(0.75rem - 0.125rem); +} + +.table .table__row--unbordered:last-child { + padding-bottom: calc(0.75rem - 0.125rem); +} + +.table .table__row--unbordered .table__cell { + padding: 0.125rem calc(var(--spacing) * 0.5) 0.125rem 0; +} + +@media (max-width: 560px) { + .table .table__row--socials { + flex-direction: column; + } + + .table .table__row--socials .table__cell--shrink { + padding-left: 0; + } +} + +.table .table__row--no-spacing { + justify-content: flex-start; + overflow: hidden; +} + +.table--hover .table__content .table__row:hover { + background: var(--background--light); +} + +.table .table__cell { + display: flex; + flex: 1; + padding: 0.75rem calc(var(--spacing) * 0.5) 0.75rem 0; +} + +.table .table__cell:last-child { + padding-right: 0; +} + +.table .table__cell--border-right { + border-right: 1px solid var(--secondary); + padding-left: 0.25rem; +} + +.table .table__cell--wrapper { + padding: 0; + flex-direction: column; +} + +.table .table__cell--center { + align-items: center; +} + +.table .table__cell--capitalized { + text-transform: capitalize; +} + +.table .table__cell--column { + flex-direction: column; +} + +.table .table__cell--wrap { + flex-wrap: wrap; +} + +.table .table__cell--truncate { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + display: inline; +} + +.table .table__cell--truncate a { + display: inline; +} + +.table .table__cell--break-word { + word-break: break-word; + display: inline; +} + +.table .table__cell--horizontal-center { + justify-content: center; +} + +.table .table__cell--break-all { + word-break: break-all; +} + +.table .table__cell--webhits { + flex-direction: column; + flex: 1 1 100%; + min-width: 0; +} + +.table .table__cell--webhits .webhit__link { + text-decoration: underline; +} + +.table .table__cell--webhits .webhit__url { + margin: 0; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + max-width: 18rem; +} + +.table .table__cell--webhits .webhit__url--alt { + font-size: calc(1rem - 2px); + color: var(--faded); + font-size: var(--small); + max-width: initial; +} + +@media (max-width: 1024px) { + .table .table__cell--webhits .webhit__url--alt { + font-size: calc(1rem - 1px); + } +} + +.table .table__cell--webhits .webhit__url--alt:hover { + text-decoration: underline; +} + +.table .table__cell--webhits .webhit__url--alt:before { + color: var(--faded); +} + +.table .table__cell--webhits .webhit__description { + margin: calc(var(--spacing) * 0.25) 0 0; +} + +.table .table__cell--terms { + display: inline; + flex-wrap: wrap; + align-items: flex-start; + flex: 1 1 100%; +} + +.table .table__cell--terms .result__label { + display: inline-flex; + margin-right: 0.25rem; +} + +.table .table__cell--title { + font-weight: 500; + color: var(--text-dark); +} + +.table .table__cell--full-width { + flex: 1 1 100%; +} + +.table .table__cell--shrink { + padding-left: 0.25rem; + flex: 0 1 auto; +} + +.table .table__cell--medium { + flex: 0 0 25%; +} + +.table .table__cell--medium-small { + flex: 0 0 12.5%; +} + +.table .table__cell--medium-small-fixed { + flex: 0 0 12rem; +} + +.table .table__cell--small { + flex: 0 0 6rem; +} + +.table .table__cell--extra-small { + flex: 0 0 4.5rem; +} + +.table .table__cell--mini { + flex: 0 0 3rem; +} + +.table .table__cell--extra-small-left { + flex: 0 0 4rem; + padding: 0.5rem 0; + margin-right: calc(var(--spacing) * 0.5); + overflow: hidden; +} + +.table .table__cell--space-between { + display: flex; + justify-content: space-between; +} + +.table--unbordered .table__header .table__row, +.table--unbordered .table__row { + box-shadow: none; +} + +.table--unbordered .table__cell { + padding-top: inherit; + padding-bottom: inherit; +} + +.table--options { + margin-top: calc(var(--spacing) * 0.5); +} + +.table--options .table__cell { + flex-wrap: wrap; +} + +.input { + background: var(--input-bg); + color: var(--text); + border-radius: 4px; + transition: background .25s ease-in-out, color .25s ease-in-out; + margin-right: 0.25rem; + max-width: 12rem; + padding: 0.75rem; +} + +.input:focus { + background: var(--input-bg--darken); +} + +.input.input--checkbox, .input.input--radio { + background: none; + padding: 0 0 0.75rem; +} + +.input--textarea { + min-height: 6rem; +} + +.input--date { + position: relative; +} + +.input--date:after { + color: var(--faded); +} + +.input--date::-webkit-calendar-picker-indicator { + margin: 0; + padding: 0; + background-image: none; + position: absolute; + right: 0.75rem; +} + +.input--no-radius-left { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.input--no-radius-right { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} + +.input--no-max-width { + max-width: 100%; +} + +.input__loader { + display: flex; + align-items: center; + padding: 0.5rem 0; + margin: 0; + color: var(--faded); +} + +.input__label { + font-weight: 600; + color: var(--text-dark); + margin: 0.5rem 0 0; + font-size: 14px; + display: block; +} + +.input__label--hidden { + display: none; +} + +.input__row { + display: flex; +} + +.input__row .input__column { + margin-right: calc(var(--spacing) * 0.5); + flex: 1 1 auto; +} + +.input__row .input__column:last-child { + margin-right: unset; +} + +.input__row .input__column--small { + flex-basis: 33.333%; +} + +.input__row .radio-label:not(:last-child) { + margin-right: calc(var(--spacing) * 0.5); +} + +/* Search --------------------------------------*/ +.input-wrapper { + position: relative; + display: flex; + align-items: center; +} + +.input-wrapper > .input { + padding-left: 2.5rem; +} + +.input-wrapper:before { + color: var(--faded); + left: 0.75rem; + top: 50%; + margin-top: -0.75rem; + position: absolute; + pointer-events: none; +} + +.button { + transition: background .25s ease-in-out, color .25s ease-in-out; + border-radius: 4px; + display: inline-flex; + flex: 0 0 auto; + align-items: center; + font-size: 1rem; + line-height: 1.5rem; + padding: 6px 14px; + color: var(--primary); + font-weight: 400; + background: transparent; + border: 2px solid transparent; + min-width: 2.5rem; +} + +.button .icon:before, .button .section-toggle + label:before, .button .section-toggle-invert + label:before { + transition: background .25s ease-in-out, color .25s ease-in-out; + margin-right: calc(var(--spacing) * 0.25); + font-size: 1rem; + line-height: 1rem; + position: relative; + top: calc(var(--spacing) * 0.125); +} + +.button--icon-button .icon:before, .button--icon-button .section-toggle + label:before, .button--icon-button .section-toggle-invert + label:before { + margin-right: 0; +} + +.button .spinner { + line-height: 1; +} + +.button--primary { + background: var(--primary); + color: white; + border: 2px solid var(--primary); +} + +.button--primary .icon:before, .button--primary .section-toggle + label:before, .button--primary .section-toggle-invert + label:before { + color: white; +} + +.button--primary .spinner { + filter: var(--white--filter); +} + +.button--primary:hover { + background: transparent; + color: var(--primary); +} + +.button--primary:hover .icon:before, .button--primary:hover .section-toggle + label:before, .button--primary:hover .section-toggle-invert + label:before { + color: var(--primary); +} + +.button--primary:hover .spinner { + filter: var(--primary--filter); +} + +.button--secondary { + background: transparent; + color: var(--primary); + border: 2px solid var(--primary); +} + +.button--secondary .icon:before, .button--secondary .section-toggle + label:before, .button--secondary .section-toggle-invert + label:before { + color: var(--primary); +} + +.button--secondary .spinner { + filter: var(--primary--filter); +} + +.button--secondary:hover { + background: var(--primary); + color: white; + border: 2px solid var(--primary); +} + +.button--secondary:hover .icon:before, .button--secondary:hover .section-toggle + label:before, .button--secondary:hover .section-toggle-invert + label:before { + color: white; +} + +.button--secondary:hover .spinner { + filter: var(--white--filter); +} + +.button--secondary .transparant { + background: none; +} + +.button--secondary .transparant:hover { + background: none; +} + +.button--secondary .active { + background: var(--light-grey); +} + +.button--red.button--primary { + background: var(--red); + border: 2px solid var(--red); +} + +.button--red.button--primary .icon:before, .button--red.button--primary .section-toggle + label:before, .button--red.button--primary .section-toggle-invert + label:before { + color: var(--background--main); +} + +.button--red.button--primary .spinner { + filter: var(--white--filter); +} + +.button--red.button--primary:hover { + color: var(--red); + background: transparent; +} + +.button--red.button--primary:hover .icon:before, .button--red.button--primary:hover .section-toggle + label:before, .button--red.button--primary:hover .section-toggle-invert + label:before { + color: var(--red); +} + +.button--red.button--primary:hover .spinner { + filter: var(--red--filter); +} + +.button--red.button--link { + color: var(--red); +} + +.button--red.button--link .icon:before, .button--red.button--link .section-toggle + label:before, .button--red.button--link .section-toggle-invert + label:before { + color: var(--red); +} + +.button--red.button--secondary { + color: var(--red); + border: 2px solid var(--red); + background: transparent; +} + +.button--red.button--secondary .icon:before, .button--red.button--secondary .section-toggle + label:before, .button--red.button--secondary .section-toggle-invert + label:before { + color: var(--red); +} + +.button--red.button--secondary .spinner { + filter: var(--red--filter); +} + +.button--red.button--secondary:hover { + background: var(--red); + color: var(--background--main); +} + +.button--red.button--secondary:hover .icon:before, .button--red.button--secondary:hover .section-toggle + label:before, .button--red.button--secondary:hover .section-toggle-invert + label:before { + color: var(--background--main); +} + +.button--red.button--secondary:hover .spinner { + filter: var(--white--filter); +} + +.button--green.button--primary { + background: var(--green); + border: 2px solid var(--green); +} + +.button--green.button--primary .icon:before, .button--green.button--primary .section-toggle + label:before, .button--green.button--primary .section-toggle-invert + label:before { + color: white; +} + +.button--green.button--primary .spinner { + filter: var(--white--filter); +} + +.button--green.button--primary:hover { + color: var(--green); + background: transparent; +} + +.button--green.button--primary:hover .icon:before, .button--green.button--primary:hover .section-toggle + label:before, .button--green.button--primary:hover .section-toggle-invert + label:before { + color: var(--green); +} + +.button--green.button--primary:hover .spinner { + filter: var(--green--filter); +} + +.button--green.button--primary.button--link { + color: var(--green); +} + +.button--green.button--primary.button--link .icon:before, .button--green.button--primary.button--link .section-toggle + label:before, .button--green.button--primary.button--link .section-toggle-invert + label:before { + color: var(--green); +} + +.button--green.button--primary.button--secondary { + color: var(--green); + border: 2px solid var(--green); + background: transparent; +} + +.button--green.button--primary.button--secondary .icon:before, .button--green.button--primary.button--secondary .section-toggle + label:before, .button--green.button--primary.button--secondary .section-toggle-invert + label:before { + color: var(--green); +} + +.button--green.button--primary.button--secondary .spinner { + filter: var(--green--filter); +} + +.button--green.button--primary.button--secondary:hover { + background: var(--green); + color: white; +} + +.button--green.button--primary.button--secondary:hover .icon:before, .button--green.button--primary.button--secondary:hover .section-toggle + label:before, .button--green.button--primary.button--secondary:hover .section-toggle-invert + label:before { + color: var(--background--main); +} + +.button--green.button--primary.button--secondary:hover .spinner { + filter: var(--white--filter); +} + +.button--readmore { + background: none; + padding: 0; + border: none; + display: inline-block; + -webkit-appearance: none; + text-decoration: underline; +} + +.button--readmore:before { + top: 2px; + text-decoration: none; + position: relative; +} + +.button--link { + background: none; + border: none; + text-decoration: underline; + padding-left: 0; + color: var(--secondary); +} + +.button--link:hover { + text-decoration: none; + filter: var(--primary--filter); +} + +.button--link--grey-text { + color: var(--text); + opacity: 0.75; +} + +.button--link--grey-text .icon:before, .button--link--grey-text .section-toggle + label:before, .button--link--grey-text .section-toggle-invert + label:before { + color: var(--text); + margin-right: calc(var(--spacing) * 0.125); +} + +.button--disabled:hover { + cursor: not-allowed; +} + +.button--disabled.button--primary { + background: var(--background--light); + color: var(--text); + border: 2px solid var(--grey); +} + +.button--disabled.button--primary .icon:before, .button--disabled.button--primary .section-toggle + label:before, .button--disabled.button--primary .section-toggle-invert + label:before { + color: var(--text); +} + +.button--disabled.button--primary:hover { + background: var(--background--light); + color: var(--text); + border: 2px solid var(--grey); +} + +.button--disabled.button--primary:hover .icon:before, .button--disabled.button--primary:hover .section-toggle + label:before, .button--disabled.button--primary:hover .section-toggle-invert + label:before { + color: var(--text); +} + +.button--disabled.button--primary:hover .spinner { + filter: var(--white--filter); +} + +.button--disabled.button--secondary { + color: var(--faded); + border: 2px solid var(--border); + background: transparent; +} + +.button--disabled.button--secondary .icon:before, .button--disabled.button--secondary .section-toggle + label:before, .button--disabled.button--secondary .section-toggle-invert + label:before { + color: var(--faded); +} + +.button--disabled.button--secondary .spinner { + filter: var(--faded--filter); +} + +.button--disabled.button--secondary:hover { + background: inherit; + color: var(--faded); +} + +.button--disabled.button--link, .button--disabled.button--link:hover { + background: none; + border: none; + color: var(--faded); + text-decoration: underline; + cursor: not-allowed; +} + +.button--disabled.button--link .icon:before, .button--disabled.button--link .section-toggle + label:before, .button--disabled.button--link .section-toggle-invert + label:before, .button--disabled.button--link:hover .icon:before { + color: var(--faded); +} + +.button--small { + padding: 2px 6px; +} + +.badge { + --badge-height: 16px; + background-color: var(--text); + color: white; + border-radius: calc(var(--badge-height) / 2); + min-width: var(--badge-height); + height: var(--badge-height); + white-space: nowrap; + padding: 0 0.5rem; + line-height: var(--badge-height); + display: inline-flex; + text-align: center; + justify-content: center; + align-items: center; + font-size: 12px; + font-weight: 500; +} + +.badge--green { + background: var(--green); +} + +.badge--red { + background: var(--red); +} + +.badge--orange { + background: var(--warning); +} + +.badge--primary { + background: var(--primary); +} + +.badge--secondary { + background: var(--secondary); +} + +.badge.link { + text-decoration: none; +} + +.badge--counter { + margin-left: 0.25rem; + background: rgba(var(--primary--rgb), 0.2); + color: var(--text); +} + +.badge--large { + border-radius: 0.75rem; + min-width: 1.5rem; + height: 1.5rem; +} + +.tooltip-dias { + content: "m"; + position: relative; + text-transform: initial; + cursor: pointer; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-decoration: none; + font-style: normal; + font-variant: normal; + text-rendering: auto; + font-family: "icon-dias", sans-serif; + line-height: inherit; + font-size: 1rem; + color: var(--primary); + margin-left: calc(var(--spacing) * 0.25); +} + +.tooltip-dias--red { + color: var(--red); +} + +.tooltip-dias--white { + color: var(--background--main); +} + +.tooltip-dias--without-margin { + margin-left: 0; +} + +/* Base styles for the entire tooltip */ +.tooltip-dias:after, +.tooltip-dias:before { + position: absolute; + visibility: hidden; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0); + opacity: 0; + -webkit-transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out, -webkit-transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24); + -moz-transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out, -moz-transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24); + transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out, transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24); + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + pointer-events: none; +} + +/* Show the entire tooltip on hover and focus */ +.tooltip-dias:focus:after, +.tooltip-dias:focus:before, +.tooltip-dias:hover:after, +.tooltip-dias:hover:before { + visibility: visible; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100); + opacity: 1; +} + +/* Base styles for the tooltip's directional arrow */ +.tooltip-dias:before { + z-index: 1001; + border: 6px solid transparent; + background: transparent; + content: ""; +} + +/* Base styles for the tooltip's content area */ +.tooltip-dias:after { + border-radius: 4px; + font-family: "Inter", sans-serif; + z-index: 1000; + padding: 8px; + max-width: 160px; + background-color: rgba(var(--primary--rgb), 0.9); + color: #fff; + content: attr(data-tooltip); + font-size: calc(1rem - 2px); + line-height: 1.25; +} + +@media (max-width: 1024px) { + .tooltip-dias:after { + font-size: calc(1rem - 1px); + } +} + +.tooltip-dias--red:after { + background-color: rgba(var(--red--rgb), 0.9); +} + +/* Directions */ +/* Top (default) */ +.tooltip-dias-top:after, +.tooltip-dias-top:before, +.tooltip-dias:after, +.tooltip-dias:before { + bottom: 100%; + left: 50%; +} + +.tooltip-dias-top:before, +.tooltip-dias:before { + margin-left: -6px; + margin-bottom: -0.75rem; + border-top-color: rgba(var(--primary--rgb), 0.9); +} + +.tooltip-dias-top.tooltip--red:before { + border-top-color: rgba(var(--red--rgb), 0.9); +} + +/* Horizontally align top/bottom tooltips */ +.tooltip-dias-top:after, +.tooltip-dias:after { + margin-left: -80px; +} + +.tooltip-dias-top:focus:after, +.tooltip-dias-top:focus:before, +.tooltip-dias-top:hover:after, +.tooltip-dias-top:hover:before, +.tooltip-dias:focus:after, +.tooltip-dias:focus:before, +.tooltip-dias:hover:after, +.tooltip-dias:hover:before { + -webkit-transform: translateY(-0.5rem); + -moz-transform: translateY(-0.5rem); + transform: translateY(-0.5rem); +} + +/* Left */ +.tooltip-dias-left:after, +.tooltip-dias-left:before { + right: 100%; + bottom: 50%; + left: auto; +} + +.tooltip-dias-left:before { + margin-left: 0; + margin-right: -12px; + margin-bottom: 0; + border-top-color: transparent; + border-left-color: rgba(var(--primary--rgb), 0.9); +} + +.tooltip-dias-left.tooltip--red:before { + border-left-color: rgba(var(--red--rgb), 0.9); +} + +.tooltip-dias-left:focus:after, +.tooltip-dias-left:focus:before, +.tooltip-dias-left:hover:after, +.tooltip-dias-left:hover:before { + -webkit-transform: translate(-0.5rem, 6px); + -moz-transform: translate(-0.5rem, 6px); + transform: translate(-0.5rem, 6px); +} + +/* Bottom */ +.tooltip-dias-bottom:after, +.tooltip-dias-bottom:before { + top: 100%; + bottom: auto; + left: 50%; +} + +.tooltip-dias-bottom:before { + margin-top: -12px; + margin-bottom: 0; + border-top-color: transparent; + border-bottom-color: rgba(var(--primary--rgb), 0.9); +} + +.tooltip-dias-bottom.tooltip--red:before { + border-bottom-color: rgba(var(--red--rgb), 0.9); +} + +.tooltip-dias-bottom:focus:after, +.tooltip-dias-bottom:focus:before, +.tooltip-dias-bottom:hover:after, +.tooltip-dias-bottom:hover:before { + -webkit-transform: translateY(0.5rem); + -moz-transform: translateY(0.5rem); + transform: translateY(0.5rem); +} + +/* Right */ +.tooltip-dias-right:after, +.tooltip-dias-right:before { + bottom: 50%; + left: 100%; +} + +.tooltip-dias-right:before { + margin-bottom: 0; + margin-left: -12px; + border-top-color: transparent; + border-right-color: rgba(var(--primary--rgb), 0.9); +} + +.tooltip-dias-right.tooltip--red:before { + border-right-color: rgba(var(--red--rgb), 0.9); +} + +.tooltip-dias-right:focus:after, +.tooltip-dias-right:focus:before, +.tooltip-dias-right:hover:after, +.tooltip-dias-right:hover:before { + -webkit-transform: translate(0.5rem, 6px); + -moz-transform: translate(0.5rem, 6px); + transform: translate(0.5rem, 6px); +} + +/* Vertically center tooltip content for left/right tooltips */ +.tooltip-dias-left:after, +.tooltip-dias-right:after { + margin-left: 0; + margin-bottom: -0.5rem; +} + +.modal-dias-wrapper { + display: flex; + justify-content: center; + align-items: center; + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; + z-index: 10000; +} + +.modal-dias { + padding: var(--spacing); + padding-bottom: 0; + width: 100%; + max-width: 80%; + max-height: 100%; + position: fixed; + z-index: 10000; + background: white; + overflow-y: auto; +} + +.modal-dias--padding { + padding-bottom: var(--spacing); +} + +.modal-dias--fit-content { + width: fit-content; +} + +.modal-dias .button--close { + position: absolute; + right: 0; + top: 0; + height: 3rem; + width: 3rem; + display: flex; + justify-content: center; + align-items: center; + background: var(--primary); + padding: 8px; +} + +.modal-dias .button--close:before { + color: white; +} + +.modal-dias--closed { + display: none; +} + +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 5000; + background: rgba(0, 0, 0, 0.75); +} + +.modal-dias__title { + margin: 0 0 calc(var(--spacing) * 0.5) 0; +} + +.modal-dias__content { + flex-grow: 1; + flex-direction: column; +} + +.modal-dias__footer { + margin: var(--spacing) 0; +} + +/* Checkbox --------------------------------------*/ +[type=checkbox]:checked, +[type=checkbox]:not(:checked) { + position: absolute; + left: -9999px; +} + +[type=checkbox]:checked + .checkbox__label, +[type=checkbox]:not(:checked) + .checkbox__label { + position: relative; + padding-left: 24px; + cursor: pointer; +} + +/* checkbox aspect */ +[type=checkbox]:checked + .checkbox__label:before, +[type=checkbox]:not(:checked) + .checkbox__label:before { + transition: transform .25s ease-in-out, opacity .25s ease-in-out; + content: ""; + position: absolute; + border-radius: 4px; + left: 0; + top: 2px; + width: 1rem; + height: 1rem; + background: var(--input-bg); +} + +/* checked mark aspect */ +[type=checkbox]:checked + .checkbox__label:after, +[type=checkbox]:not(:checked) + .checkbox__label:after { + transition: opacity .25s ease-in-out, transform .25s ease-in-out; + content: "p"; + position: absolute; + top: -2px; + left: 2px; + font-size: 12px; + color: var(--primary); + font-family: "icon-dias", sans-serif; +} + +/* checked mark aspect changes */ +[type=checkbox]:not(:checked) + .checkbox__label:after { + opacity: 0; + transform: scale(0); +} + +[type=checkbox]:checked + .checkbox__label:after { + opacity: 1; + transform: scale(1); +} + +/* disabled checkbox */ +[type=checkbox]:disabled:checked + .checkbox__label:before, +[type=checkbox]:disabled:not(:checked) + .checkbox__label:before { + background-color: var(--primary); +} + +[type=checkbox]:disabled:checked + .checkbox__label:after { + color: var(--text-dark); + opacity: 0.5; +} + +[type=checkbox]:disabled + .checkbox__label { + opacity: 0.5; +} + +/* accessibility */ +[type=checkbox]:checked:focus + .checkbox__label:before, +[type=checkbox]:not(:checked):focus + .checkbox__label:before { + border: 2px solid var(--primary); +} + +.input--select { + padding: calc(0.75rem - 1px) 2rem calc(0.75rem - 1px) 0.5rem; + width: 100%; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; +} + +.input--select::-ms-expand { + display: none; +} + +.input--select:focus { + outline: none; +} + +.input--select option { + line-height: 3rem; +} + +.input-select-wrapper { + position: relative; +} + +.input-select-wrapper:after { + color: var(--text); + pointer-events: none; +} + +.input-select-wrapper--transparent .input--select { + background: none; + padding: 0.25rem 0; + color: inherit; +} + +/* Toggle --------------------------------------*/ +.toggle-label { + position: relative; + padding-left: calc(2rem + 0.5rem); + cursor: pointer; +} + +[type=checkbox]:checked + .toggle-label:before, +[type=checkbox]:not(:checked) + .toggle-label:before { + content: ""; + position: absolute; + width: 2rem; + height: calc(2rem / 2); + vertical-align: middle; + top: 2px; + left: 0; + background-color: rgba(var(--medium-grey--rgb), 0.5); + border-radius: 0.5rem; + transition: background-color .25s ease-in-out; +} + +[type=checkbox]:checked + .toggle-label:after, +[type=checkbox]:not(:checked) + .toggle-label:after { + position: absolute; + content: ""; + width: calc(2rem / 2 - 2px); + height: calc(2rem / 2 - 2px); + left: 1px; + top: calc(1px + 2px); + background-color: white; + border-radius: 50%; + transition: opacity .25s ease-in-out; +} + +[type=checkbox]:checked + .toggle-label::before { + background-color: var(--green); +} + +[type=checkbox]:checked + .toggle-label:after { + transform: translateX(calc(2rem / 2)); +} + +.popup-bar { + border-radius: 4px; + padding: calc(var(--spacing) * 0.125) calc(var(--spacing) * 0.25); + display: flex; + flex: 1 1 100%; + margin-bottom: calc(var(--spacing) * 0.25); + background: rgba(var(--primary--rgb), 0.1); + color: var(--text); + z-index: 10000000; +} + +.popup-bar .image--spinner { + margin-top: calc(var(--spacing) * 0.125); +} + +.popup-bar--red { + background: rgba(var(--red--filter)); + color: var(--red); +} + +.popup-bar--red:before { + background: rgba(var(--red--rgb), 0.1); +} + +.popup-bar--color-inherit { + background: inherit; +} + +.popup-bar--fixed { + position: fixed; + left: 1rem; + bottom: 1rem; +} + +.popup-bar--fixed:before { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + content: ""; + border-radius: 4px; +} + +.popup-bar--extra { + border-radius: 4px; + position: fixed; + padding: calc(var(--spacing) * 0.25); + z-index: 10000; + bottom: 1rem; + left: 1rem; + display: flex; + flex-direction: column; +} + +.popup-bar--extra--main-message { + display: flex; + align-items: center; +} + +.popup-bar--extra--main-message .text { + flex: 1 1 auto; + margin: 0; +} + +.popup-bar--extra--main-message .icon--left::before { + color: var(--red); + font-size: large; +} + +.popup-bar--extra--sub-message { + color: var(--faded); + font-size: smaller; + margin: 0 1.7rem; +} + +.spinner { + transition: filter .25s ease-in-out; + background-size: contain; + background-repeat: no-repeat; + width: 1rem; + height: 1rem; + display: inline-block; +} + +.spinner--left { + margin-right: calc(var(--spacing) * 0.25); +} + +.spinner--right { + margin-left: calc(var(--spacing) * 0.25); +} + +.spinner--primary { + filter: var(--primary--filter); +} + +.spinner--text { + filter: var(--text--filter); +} + +.spinner--faded { + filter: var(--faded--filter); +} + +.image--spinner { + background-image: url("../styling/images/spinner.svg"); +} + +.logo { + height: 3.5rem; + background-color: inherit; +} + +.navbar-custom { + padding-left: 1.25rem; + padding-right: 1.25rem; + margin-top: 1.25rem; + height: 3rem; +} + +.custom-title-h1 { + margin-top: 1.5rem; +} + +.custom-badge-margin { + margin-top: 0.25rem; +} + +.custom-button-no-padding { + padding: 0; +} + +.custom-spinner-size { + width: 1.25rem; + height: 1.25rem; +} + +.custom-column-list { + -moz-column-count: 2; + -moz-column-gap: 2rem; + -webkit-column-count: 2; + -webkit-column-gap: 2rem; + column-count: 2; + column-gap: 2rem; +} + +.custom-atdb-task-modal { + min-height: 15rem; +} + +.custom-div-margin { + margin: 1rem; +} \ No newline at end of file diff --git a/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.eot b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.eot new file mode 100644 index 0000000000000000000000000000000000000000..47480eba73afb00c30fe4d61c1c36c1a06a027f0 Binary files /dev/null and b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.eot differ diff --git a/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.svg b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.svg new file mode 100644 index 0000000000000000000000000000000000000000..834a63ae1d07e4d52aff12d3c59e8856e79a3641 --- /dev/null +++ b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.svg @@ -0,0 +1,244 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"> +<svg xmlns="http://www.w3.org/2000/svg"> + <metadata>Generated by Fontastic.me</metadata> + <defs> + <font id="icon-wis" horiz-adv-x="512"> + <font-face font-family="icon-wis" units-per-em="512" ascent="480" descent="-32"/> + <missing-glyph horiz-adv-x="512"/> + + <glyph glyph-name="user" unicode="b" + d="M256 256c71 0 128 57 128 128 0 71-57 128-128 128-71 0-128-57-128-128 0-71 57-128 128-128z m90-32l-17 0c-22-10-47-16-73-16-26 0-51 6-73 16l-17 0c-74 0-134-60-134-134l0-42c0-27 22-48 48-48l352 0c27 0 48 21 48 48l0 42c0 74-60 134-134 134z"/> + <glyph glyph-name="globe" unicode="c" + d="M345 352c-15 89-49 152-89 152-40 0-74-63-88-152z m-185-96c0-22 1-44 3-64l186 0c2 20 3 42 3 64 0 22-1 43-3 64l-186 0c-2-21-3-42-3-64z m325 96c-29 68-87 120-158 142 24-34 41-85 50-142z m-300 142c-71-22-129-74-158-142l108 0c9 57 26 108 50 142z m310-174l-114 0c2-21 3-43 3-64 0-22-1-43-3-64l114 0c6 20 9 42 9 64 0 22-3 43-9 64z m-367-64c0 21 1 43 3 64l-114 0c-6-21-9-42-9-64 0-22 3-44 9-64l114 0c-2 21-3 42-3 64z m40-96c14-89 48-152 88-152 40 0 74 63 89 152z m159-142c71 22 129 74 158 142l-108 0c-9-57-26-108-50-142z m-300 142c29-68 87-120 158-142-24 34-41 85-50 142z"/> + <glyph glyph-name="facebook" unicode="a" + d="M375 224l14 93-89 0 0 60c0 25 13 50 53 50l40 0 0 79c0 0-37 6-72 6-73 0-121-44-121-125l0-70-81 0 0-93 81 0 0-224 100 0 0 224z"/> + <glyph glyph-name="building" unicode="d" + d="M468 32l-20 0 0 456c0 13-11 24-24 24l-336 0c-13 0-24-11-24-24l0-456-20 0c-7 0-12-5-12-12l0-20 448 0 0 20c0 7-5 12-12 12z m-308 404c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m0-96c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m52-148l-40 0c-7 0-12 5-12 12l0 40c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12z m76-160l-64 0 0 84c0 7 5 12 12 12l40 0c7 0 12-5 12-12z m64 172c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12l0 40c0 7 5 12 12 12l40 0c7 0 12-5 12-12z m0 96c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12l0 40c0 7 5 12 12 12l40 0c7 0 12-5 12-12z m0 96c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12l0 40c0 7 5 12 12 12l40 0c7 0 12-5 12-12z"/> + <glyph glyph-name="random" unicode="e" + d="M505 112l-79-73c-15-15-42-4-42 17l0 40-31 0c-3 0-6 1-9 4l-90 97 39 41 79-86 12 0 0 48c0 22 27 32 42 17l79-71c9-9 9-25 0-34z m-493 248l92 0 80-86 38 41-90 97c-2 3-6 4-9 4l-111 0c-7 0-12-5-12-12l0-32c0-7 5-12 12-12z m493 42l-79 71c-15 15-42 4-42-17l0-40-31 0c-3 0-6-1-9-4l-240-260-92 0c-7 0-12-5-12-12l0-32c0-7 5-12 12-12l111 0c3 0 7 1 9 4l240 260 12 0 0-48c0-21 27-32 42-17l79 73c9 9 9 25 0 34z"/> + <glyph glyph-name="plus" unicode="f" + d="M432 288l-144 0 0 144c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-144-144 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l144 0 0-144c0-9 7-16 16-16l32 0c9 0 16 7 16 16l0 144 144 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z"/> + <glyph glyph-name="minus" unicode="g" + d="M432 288l-352 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l352 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z"/> + <glyph glyph-name="location" unicode="h" + d="M256 344c-49 0-88-39-88-88 0-49 39-88 88-88 49 0 88 39 88 88 0 49-39 88-88 88z m0-128c-22 0-40 18-40 40 0 22 18 40 40 40 22 0 40-18 40-40 0-22-18-40-40-40z m240 64l-50 0c-11 87-79 155-166 166l0 50c0 9-7 16-16 16l-16 0c-9 0-16-7-16-16l0-50c-87-11-155-79-166-166l-50 0c-9 0-16-7-16-16l0-16c0-9 7-16 16-16l50 0c11-87 79-155 166-166l0-50c0-9 7-16 16-16l16 0c9 0 16 7 16 16l0 50c87 11 155 79 166 166l50 0c9 0 16 7 16 16l0 16c0 9-7 16-16 16z m-240-168c-79 0-144 65-144 144 0 79 65 144 144 144 79 0 144-65 144-144 0-79-65-144-144-144z"/> + <glyph glyph-name="chevron-up" unicode="i" + d="M273 381l194-194c10-9 10-24 0-34l-22-22c-10-10-25-10-34-1l-155 155-155-155c-9-9-24-9-34 1l-22 22c-10 10-10 25 0 34l194 194c9 10 25 10 34 0z"/> + <glyph glyph-name="chevron-down" unicode="j" + d="M239 131l-194 194c-10 9-10 24 0 34l22 22c10 10 25 10 34 1l155-155 155 155c9 9 24 9 34-1l22-22c10-10 10-25 0-34l-194-194c-9-10-25-10-34 0z"/> + <glyph glyph-name="search" unicode="k" + d="M505 69l-100 100c-4 4-10 7-17 7l-16 0c28 35 44 80 44 128 0 115-93 208-208 208-115 0-208-93-208-208 0-115 93-208 208-208 48 0 93 16 128 44l0-16c0-7 3-13 7-17l100-100c9-9 24-9 34 0l28 28c9 10 9 25 0 34z m-297 107c-71 0-128 57-128 128 0 71 57 128 128 128 71 0 128-57 128-128 0-71-57-128-128-128z"/> + <glyph glyph-name="ellipsis-v" unicode="l" + d="M256 328c40 0 72-32 72-72 0-40-32-72-72-72-40 0-72 32-72 72 0 40 32 72 72 72z m-72 104c0-40 32-72 72-72 40 0 72 32 72 72 0 40-32 72-72 72-40 0-72-32-72-72z m0-352c0-40 32-72 72-72 40 0 72 32 72 72 0 40-32 72-72 72-40 0-72-32-72-72z"/> + <glyph glyph-name="info-circle" unicode="m" + d="M256 504c-137 0-248-111-248-248 0-137 111-248 248-248 137 0 248 111 248 248 0 137-111 248-248 248z m0-110c23 0 42-19 42-42 0-23-19-42-42-42-23 0-42 19-42 42 0 23 19 42 42 42z m56-254c0-7-5-12-12-12l-88 0c-7 0-12 5-12 12l0 24c0 7 5 12 12 12l12 0 0 64-12 0c-7 0-12 5-12 12l0 24c0 7 5 12 12 12l64 0c7 0 12-5 12-12l0-100 12 0c7 0 12-5 12-12z"/> + <glyph glyph-name="file" unicode="n" + d="M288 376l0 136-200 0c-13 0-24-11-24-24l0-464c0-13 11-24 24-24l336 0c13 0 24 11 24 24l0 328-136 0c-13 0-24 11-24 24z m160 14l0-6-128 0 0 128 6 0c7 0 13-3 17-7l98-98c5-5 7-11 7-17z"/> + <glyph glyph-name="spinner" unicode="o" + d="M288 480c0-18-14-32-32-32-18 0-32 14-32 32 0 18 14 32 32 32 18 0 32-14 32-32z m-32-416c-18 0-32-14-32-32 0-18 14-32 32-32 18 0 32 14 32 32 0 18-14 32-32 32z m256 192c0 18-14 32-32 32-18 0-32-14-32-32 0-18 14-32 32-32 18 0 32 14 32 32z m-448 0c0 18-14 32-32 32-18 0-32-14-32-32 0-18 14-32 32-32 18 0 32 14 32 32z m34-126c-18 0-32-15-32-32 0-18 14-32 32-32 17 0 32 14 32 32 0 17-15 32-32 32z m316 0c-17 0-32-15-32-32 0-18 15-32 32-32 18 0 32 14 32 32 0 17-14 32-32 32z m-316 316c-18 0-32-14-32-32 0-17 14-32 32-32 17 0 32 15 32 32 0 18-15 32-32 32z"/> + <glyph glyph-name="check" unicode="p" + d="M174 73l-167 166c-10 10-10 26 0 36l37 36c10 10 26 10 36 0l112-112 240 240c10 10 26 10 36 0l37-36c10-10 10-26 0-36l-295-294c-10-10-26-10-36 0z"/> + <glyph glyph-name="user-tie" unicode="q" + d="M256 256c71 0 128 57 128 128 0 71-57 128-128 128-71 0-128-57-128-128 0-71 57-128 128-128z m96-33l-48-191-32 136 32 56-96 0 32-56-32-136-48 191c-71-3-128-61-128-133l0-42c0-27 22-48 48-48l352 0c27 0 48 21 48 48l0 42c0 72-57 130-128 133z"/> + <glyph glyph-name="ban" unicode="r" + d="M256 504c-137 0-248-111-248-248 0-137 111-248 248-248 137 0 248 111 248 248 0 137-111 248-248 248z m130-118c66-65 70-165 21-236l-257 257c71 49 171 45 236-21z m-260-260c-66 65-70 165-21 236l257-257c-71-49-171-45-236 21z"/> + <glyph glyph-name="linkedin" unicode="s" + d="M132 64l-93 0 0 299 93 0z m-46 340c-30 0-54 24-54 54 0 30 24 54 54 54 29 0 54-24 54-54 0-30-25-54-54-54z m394-340l-93 0 0 146c0 34 0 79-48 79-48 0-56-38-56-77l0-148-93 0 0 299 90 0 0-41 1 0c12 24 43 49 88 49 94 0 111-62 111-143l0-164z"/> + <glyph glyph-name="instagram" unicode="t" + d="M331 256c0-41-34-75-75-75-41 0-75 34-75 75 0 41 34 75 75 75 41 0 75-34 75-75z m148-92c-2-36-10-68-37-94-26-27-58-35-93-36-37-3-148-3-185 0-36 1-68 10-94 36-27 26-35 58-36 94-3 37-3 148 0 185 1 35 9 67 36 93 26 27 58 35 94 37 37 2 148 2 185 0 35-2 67-10 93-37 27-26 35-58 37-94 2-37 2-147 0-184z m-108 92c0 64-51 115-115 115-63 0-115-51-115-115 0-64 52-115 115-115 64 0 115 51 115 115z m32 120c0 14-12 26-27 26-15 0-27-12-27-26 0-15 12-27 27-27 15 0 27 12 27 27z"/> + <glyph glyph-name="times" unicode="u" + d="M323 256l100 100c12 12 12 32 0 45l-22 22c-13 12-33 12-45 0l-100-100-100 100c-12 12-32 12-45 0l-22-22c-12-13-12-33 0-45l100-100-100-100c-12-12-12-32 0-45l22-22c13-12 33-12 45 0l100 100 100-100c12-12 32-12 45 0l22 22c12 13 12 33 0 45z"/> + <glyph glyph-name="info" unicode="v" + d="M180 88l20 0 0 144-20 0c-11 0-20 9-20 20l0 48c0 11 9 20 20 20l112 0c11 0 20-9 20-20l0-212 20 0c11 0 20-9 20-20l0-48c0-11-9-20-20-20l-152 0c-11 0-20 9-20 20l0 48c0 11 9 20 20 20z m76 424c-40 0-72-32-72-72 0-40 32-72 72-72 40 0 72 32 72 72 0 40-32 72-72 72z"/> + <glyph glyph-name="exclamation" unicode="w" + d="M336 80c0-44-36-80-80-80-44 0-80 36-80 80 0 44 36 80 80 80 44 0 80-36 80-80z m-151 407l14-272c1-13 11-23 24-23l66 0c13 0 24 10 24 23l14 272c0 14-11 25-24 25l-94 0c-13 0-24-11-24-25z"/> + <glyph glyph-name="exclamation-triangle" unicode="y" + d="M506 92c17-28-4-64-37-64l-426 0c-33 0-54 36-37 64l213 370c16 29 58 29 74 0z m-250 77c-23 0-41-18-41-41 0-23 18-41 41-41 23 0 41 18 41 41 0 23-18 41-41 41z m-39 147l7-121c0-6 5-10 10-10l44 0c5 0 10 4 10 10l7 121c0 6-5 11-11 11l-56 0c-6 0-11-5-11-11z"/> + <glyph glyph-name="chevron-left" unicode="x" + d="M131 273l194 194c9 10 24 10 34 0l22-22c10-10 10-25 1-34l-155-155 155-155c9-9 9-24-1-34l-22-22c-10-10-25-10-34 0l-194 194c-10 9-10 25 0 34z"/> + <glyph glyph-name="chevron-right" unicode="z" + d="M381 239l-194-194c-9-10-24-10-34 0l-22 22c-10 10-10 25-1 34l155 155-155 155c-9 9-9 24 1 34l22 22c10 10 25 10 34 0l194-194c10-9 10-25 0-34z"/> + <glyph glyph-name="pen" unicode="A" + d="M291 419l128-128-278-278-114-13c-16-2-29 11-27 27l13 114z m207 19l-60 60c-19 19-49 19-68 0l-57-57 128-128 57 57c19 19 19 49 0 68z"/> + <glyph glyph-name="angle-down" unicode="B" + d="M239 160l-136 136c-9 9-9 24 0 34l23 22c9 10 24 10 34 0l96-96 96 96c10 10 25 10 34 0l23-22c9-10 9-25 0-34l-136-136c-9-10-25-10-34 0z"/> + <glyph glyph-name="angle-up" unicode="C" + d="M273 352l136-136c9-9 9-24 0-34l-23-22c-9-10-24-10-33 0l-97 96-96-96c-10-10-25-10-34 0l-23 22c-9 10-9 25 0 34l136 136c9 10 25 10 34 0z"/> + <glyph glyph-name="folders" unicode="D" + d="M77 192l0 166-39 0c-21 0-38-17-38-38l0-230c0-22 17-39 38-39l333 0c21 0 39 17 39 39l0 38-269 0c-35 0-64 29-64 64z m397 218l-154 0-51 51-128 0c-21 0-39-17-39-39l0-230c0-21 18-38 39-38l333 0c21 0 38 17 38 38l0 179c0 21-17 39-38 39z"/> + <glyph glyph-name="folder" unicode="E" + d="M464 384l-192 0-64 64-160 0c-27 0-48-21-48-48l0-288c0-27 21-48 48-48l416 0c27 0 48 21 48 48l0 224c0 27-21 48-48 48z"/> + <glyph glyph-name="users" unicode="F" + d="M77 282c28 0 51 23 51 51 0 28-23 51-51 51-28 0-51-23-51-51 0-28 23-51 51-51z m358 0c28 0 51 23 51 51 0 28-23 51-51 51-28 0-51-23-51-51 0-28 23-51 51-51z m26-26l-51 0c-14 0-27-6-36-15 32-18 55-49 60-87l52 0c15 0 26 11 26 25l0 26c0 28-23 51-51 51z m-205 0c50 0 90 40 90 90 0 49-40 89-90 89-50 0-90-40-90-89 0-50 40-90 90-90z m61-26l-6 0c-17-8-35-12-55-12-20 0-38 4-55 12l-6 0c-51 0-93-41-93-92l0-23c0-21 18-38 39-38l230 0c21 0 39 17 39 38l0 23c0 51-42 92-93 92z m-179 11c-9 9-22 15-36 15l-51 0c-28 0-51-23-51-51l0-26c0-14 11-25 26-25l52 0c5 38 28 69 60 87z"/> + <glyph glyph-name="stroopwafel" unicode="G" + d="M188 301l-45-45 45-45 45 45z m113 23l-45 45-45-45 45-45z m-90-136l45-45 45 45-45 45z m45 324c-141 0-256-115-256-256 0-141 115-256 256-256 141 0 256 115 256 256 0 141-115 256-256 256z m187-296l-12-11c-3-3-8-3-11 0l-28 28-45-45 33-34 17 17c4 3 9 3 12 0l11-11c3-3 3-8 0-11l-17-17 17-17c3-4 3-9 0-12l-11-11c-3-3-8-3-12 0l-17 17-17-17c-3-3-8-3-11 0l-11 11c-3 3-3 8 0 12l17 17-34 34-45-46 28-28c3-3 3-8 0-11l-11-12c-3-3-9-3-12 0l-28 29-28-29c-3-3-8-3-12 0l-11 12c-3 3-3 8 0 11l28 28-45 45-34-33 17-17c3-4 3-9 0-12l-11-11c-3-3-8-3-11 0l-17 17-17-17c-4-3-9-3-12 0l-11 11c-3 3-3 8 0 12l17 17-17 17c-3 3-3 8 0 11l11 11c3 3 8 3 12 0l17-17 34 34-46 45-28-28c-3-3-8-3-11 0l-12 11c-3 4-3 9 0 12l29 28-29 28c-3 3-3 8 0 12l12 11c3 3 8 3 11 0l28-28 45 45-33 34-17-17c-4-3-9-3-12 0l-11 11c-3 3-3 8 0 11l17 17-17 17c-3 4-3 9 0 12l11 11c3 3 8 3 12 0l17-17 17 17c3 3 8 3 11 0l11-11c3-3 3-8 0-12l-17-17 34-34 45 46-28 28c-3 3-3 8 0 11l11 12c4 3 9 3 12 0l28-29 28 29c3 3 8 3 12 0l11-12c3-3 3-8 0-11l-28-28 45-45 34 33-17 17c-3 4-3 9 0 12l11 11c3 3 8 3 11 0l17-17 17 17c4 3 9 3 12 0l11-11c3-3 3-8 0-12l-17-17 17-17c3-3 3-8 0-11l-11-11c-3-3-8-3-12 0l-17 17-33-34 45-45 28 28c3 3 8 3 11 0l12-11c3-4 3-9 0-12l-29-28 29-28c3-3 3-8 0-12z m-164 40l45-45 45 45-45 45z"/> + <glyph glyph-name="angle-left" unicode="H" + d="M160 273l136 136c9 9 24 9 34 0l22-23c10-9 10-24 0-34l-96-96 96-96c10-10 10-25 0-34l-22-23c-10-9-25-9-34 0l-136 136c-10 9-10 25 0 34z"/> + <glyph glyph-name="angle-right" unicode="I" + d="M352 239l-136-136c-9-9-24-9-34 0l-22 23c-10 9-10 24 0 33l96 97-96 96c-10 10-10 25 0 34l22 23c10 9 25 9 34 0l136-136c10-9 10-25 0-34z"/> + <glyph glyph-name="sliders-h" unicode="J" + d="M496 128l-336 0 0 16c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-16-80 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l80 0 0-16c0-9 7-16 16-16l32 0c9 0 16 7 16 16l0 16 336 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z m0 160l-80 0 0 16c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-16-336 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l336 0 0-16c0-9 7-16 16-16l32 0c9 0 16 7 16 16l0 16 80 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z m0 160l-208 0 0 16c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-16-208 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l208 0 0-16c0-9 7-16 16-16l32 0c9 0 16 7 16 16l0 16 208 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z"/> + <glyph glyph-name="file-plus" unicode="K" + d="M448 390l0-6-128 0 0 128 6 0c7 0 13-3 17-7l98-98c5-5 7-11 7-17z m-136-38l136 0 0-328c0-13-11-24-24-24l-336 0c-13 0-24 11-24 24l0 464c0 13 11 24 24 24l200 0 0-136c0-13 11-24 24-24z m48-140c0 7-5 12-12 12l-60 0 0 60c0 7-5 12-12 12l-40 0c-7 0-12-5-12-12l0-60-60 0c-7 0-12-5-12-12l0-40c0-7 5-12 12-12l60 0 0-60c0-7 5-12 12-12l40 0c7 0 12 5 12 12l0 60 60 0c7 0 12 5 12 12z"/> + <glyph glyph-name="file-chart-line" unicode="L" + d="M441 407l-98 98c-4 4-10 7-17 7l-6 0 0-128 128 0 0 6c0 6-2 12-7 17z m-153-31l0 136-200 0c-13 0-24-11-24-24l0-464c0-13 11-24 24-24l336 0c13 0 24 11 24 24l0 328-136 0c-13 0-24 11-24 24z m-96-299c0-7-6-13-13-13l-38 0c-7 0-13 6-13 13l0 70c0 7 6 13 13 13l38 0c7 0 13-6 13-13z m96 0c0-7-6-13-13-13l-38 0c-7 0-13 6-13 13l0 198c0 7 6 13 13 13l38 0c7 0 13-6 13-13z m32 134c0 7 6 13 13 13l38 0c7 0 13-6 13-13l0-134c0-7-6-13-13-13l-38 0c-7 0-13 6-13 13z"/> + <glyph glyph-name="folder-plus" unicode="M" + d="M464 384l-192 0-64 64-160 0c-27 0-48-21-48-48l0-288c0-27 21-48 48-48l416 0c27 0 48 21 48 48l0 224c0 27-21 48-48 48z m-96-168c0-9-7-16-16-16l-72 0 0-72c0-9-7-16-16-16l-16 0c-9 0-16 7-16 16l0 72-72 0c-9 0-16 7-16 16l0 16c0 9 7 16 16 16l72 0 0 72c0 9 7 16 16 16l16 0c9 0 16-7 16-16l0-72 72 0c9 0 16-7 16-16z"/> + <glyph glyph-name="save" unicode="N" + d="M466 382l-84 84c-9 9-21 14-34 14l-268 0c-27 0-48-21-48-48l0-352c0-27 21-48 48-48l352 0c27 0 48 21 48 48l0 268c0 13-5 25-14 34z m-210-286c-35 0-64 29-64 64 0 35 29 64 64 64 35 0 64-29 64-64 0-35-29-64-64-64z m96 305l0-101c0-7-5-12-12-12l-232 0c-7 0-12 5-12 12l0 104c0 7 5 12 12 12l229 0c3 0 6-1 8-4l3-3c3-2 4-5 4-8z"/> + <glyph glyph-name="print" unicode="O" + d="M448 320l0 115c0 8-3 16-9 22l-46 46c-6 6-14 9-22 9l-275 0c-18 0-32-14-32-32l0-160c-35 0-64-29-64-64l0-112c0-9 7-16 16-16l48 0 0-96c0-18 14-32 32-32l320 0c18 0 32 14 32 32l0 96 48 0c9 0 16 7 16 16l0 112c0 35-29 64-64 64z m-64-256l-256 0 0 96 256 0z m0 224l-256 0 0 160 192 0 0-48c0-9 7-16 16-16l48 0z m48-72c-13 0-24 11-24 24 0 13 11 24 24 24 13 0 24-11 24-24 0-13-11-24-24-24z"/> + <glyph glyph-name="file-export" unicode="P" + d="M341 375c0 6-2 11-6 15l-87 87c-4 4-9 7-15 7l-5 0 0-114 113 0z m167-165l-86 85c-8 9-24 3-24-10l0-57-57 0 0-57 57 0 0-58c0-13 16-19 24-10l86 85c5 6 5 16 0 22z m-337-25l0 28c0 8 6 15 14 15l156 0 0 113-121 0c-11 0-21 10-21 22l0 121-178 0c-11 0-21-10-21-22l0-412c0-12 10-22 21-22l299 0c12 0 21 10 21 22l0 121-156 0c-8 0-14 6-14 14z"/> + <glyph glyph-name="trash-alt" unicode="Q" + d="M64 48c0-27 21-48 48-48l288 0c27 0 48 21 48 48l0 336-384 0z m272 256c0 9 7 16 16 16 9 0 16-7 16-16l0-224c0-9-7-16-16-16-9 0-16 7-16 16z m-96 0c0 9 7 16 16 16 9 0 16-7 16-16l0-224c0-9-7-16-16-16-9 0-16 7-16 16z m-96 0c0 9 7 16 16 16 9 0 16-7 16-16l0-224c0-9-7-16-16-16-9 0-16 7-16 16z m320 176l-120 0-9 19c-4 8-13 13-22 13l-114 0c-9 0-18-5-22-13l-9-19-120 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l416 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z"/> + <glyph glyph-name="chart-network" unicode="R" + d="M461 307c28 0 51 23 51 51 0 29-23 52-51 52-28 0-51-23-51-52 0-28 23-51 51-51z m-410-38c-28 0-51-23-51-51 0-29 23-52 51-52 28 0 51 23 51 52 0 28-23 51-51 51z m360 30l-15 20-39-29 15-20z m50-145c-12 0-22-4-31-11l-77 46c3 9 5 19 5 29 0 49-40 89-89 89-7 0-13-1-20-2l-32 70c8 9 13 21 13 35 0 28-23 51-51 51-28 0-51-23-51-51 0-29 23-52 51-52 1 0 2 1 3 1l33-71c-22-16-36-41-36-70 0-50 40-90 90-90 25 0 48 11 65 28l76-46c0-2 0-5 0-8 0-28 23-51 51-51 28 0 51 23 51 51 0 29-23 52-51 52z m-192 25c-21 0-39 17-39 39 0 21 18 38 39 38 21 0 38-17 38-38 0-22-17-39-38-39z m-147 26l38 0 0 25-38 0z"/> + <glyph glyph-name="link" unicode="S" + d="M327 327c59-60 59-156 0-215 0 0 0 0 0 0l-68-68c-59-59-155-59-215 0-59 60-59 156 0 215l38 38c9 9 26 3 27-11 1-18 4-36 10-53 2-6 0-12-4-16l-13-14c-28-28-29-73-1-101 28-29 74-29 102-1l67 67c28 28 28 74 0 102-4 4-7 7-10 9-4 2-7 7-7 12-1 11 3 22 11 30l22 21c5 6 14 6 20 2 7-5 14-11 21-17z m141 141c-60 59-156 59-215 0l-68-68c0 0 0 0 0 0-59-59-59-155 0-215 7-6 14-12 21-17 6-4 15-4 20 2l22 21c8 8 12 19 11 30 0 5-3 10-7 12-3 2-6 5-10 9-28 28-28 74 0 102l67 67c28 28 74 28 102-1 28-28 27-73-1-101l-13-14c-4-4-6-10-4-16 6-17 9-35 10-53 1-14 18-20 27-11l38 38c59 59 59 155 0 215z"/> + <glyph glyph-name="archive" unicode="T" + d="M32 64c0-18 14-32 32-32l384 0c18 0 32 14 32 32l0 288-448 0z m160 212c0 7 5 12 12 12l104 0c7 0 12-5 12-12l0-8c0-7-5-12-12-12l-104 0c-7 0-12 5-12 12z m288 204l-448 0c-18 0-32-14-32-32l0-48c0-9 7-16 16-16l480 0c9 0 16 7 16 16l0 48c0 18-14 32-32 32z"/> + <glyph glyph-name="arrow-right" unicode="U" + d="M223 445l22 22c9 10 24 10 34 0l194-194c9-9 9-25 0-34l-194-194c-10-10-25-10-34 0l-22 22c-10 9-10 25 0 34l120 115-287 0c-13 0-24 11-24 24l0 32c0 13 11 24 24 24l287 0-120 115c-10 9-10 25 0 34z"/> + <glyph glyph-name="layer-plus" unicode="V" + d="M304 368l64 0 0-64c0-9 7-16 16-16l32 0c9 0 16 7 16 16l0 64 64 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16l-64 0 0 64c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-64-64 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16z m196-220l-59 26-161-73c-8-3-16-5-24-5-8 0-16 2-24 5l-161 73-59-26c-16-8-16-33 0-40l233-106c7-3 15-3 22 0l233 106c16 7 16 32 0 40z m-488 88l233-105c7-4 15-4 22 0l181 82 0 18c-15-4-31-7-48-7-88 0-161 65-174 149l-214-97c-16-7-16-32 0-40z"/> + <glyph glyph-name="map-marker-alt" unicode="W" + d="M236 10c-145 211-172 233-172 310 0 106 86 192 192 192 106 0 192-86 192-192 0-77-27-99-172-310-10-13-30-13-40 0z m20 230c44 0 80 36 80 80 0 44-36 80-80 80-44 0-80-36-80-80 0-44 36-80 80-80z"/> + <glyph glyph-name="chart-bar" unicode="X" + d="M333 192l38 0c7 0 13 6 13 13l0 134c0 7-6 13-13 13l-38 0c-7 0-13-6-13-13l0-134c0-7 6-13 13-13z m96 0l38 0c7 0 13 6 13 13l0 230c0 7-6 13-13 13l-38 0c-7 0-13-6-13-13l0-230c0-7 6-13 13-13z m-288 0l38 0c7 0 13 6 13 13l0 70c0 7-6 13-13 13l-38 0c-7 0-13-6-13-13l0-70c0-7 6-13 13-13z m96 0l38 0c7 0 13 6 13 13l0 198c0 7-6 13-13 13l-38 0c-7 0-13-6-13-13l0-198c0-7 6-13 13-13z m259-64l-432 0 0 304c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-336c0-18 14-32 32-32l464 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z"/> + <glyph glyph-name="mask" unicode="Y" + d="M257 410c-355 0-287-308-127-308 32 0 62 17 81 45l20 30c13 19 38 19 51 0l20-30c19-28 49-45 81-45 152 0 233 308-126 308z m-110-196c-33 0-54 21-64 33-4 5-4 13 0 18 10 12 31 33 64 33 33 0 54-21 64-33 4-5 4-13 0-18-10-12-31-33-64-33z m218 0c-33 0-54 21-64 33-4 5-4 13 0 18 10 12 31 33 64 33 33 0 54-21 64-33 4-5 4-13 0-18-10-12-31-33-64-33z"/> + <glyph glyph-name="list-ul" unicode="Z" + d="M48 464c-27 0-48-21-48-48 0-27 21-48 48-48 27 0 48 21 48 48 0 27-21 48-48 48z m0-160c-27 0-48-21-48-48 0-27 21-48 48-48 27 0 48 21 48 48 0 27-21 48-48 48z m0-160c-27 0-48-21-48-48 0-27 21-48 48-48 27 0 48 21 48 48 0 27-21 48-48 48z m448-16l-320 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l320 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z m0 320l-320 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l320 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z m0-160l-320 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l320 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z"/> + <glyph glyph-name="phone-alt" unicode="0" + d="M497 150l-112 48c-9 4-21 2-28-7l-49-60c-78 36-141 99-177 177l60 49c8 7 11 19 7 28l-48 112c-5 11-16 17-27 14l-104-24c-11-2-19-12-19-23 0-257 208-464 464-464 11 0 21 8 23 19l24 104c3 11-3 23-14 27z"/> + <glyph glyph-name="power-off" unicode="1" + d="M400 458c63-45 104-119 104-202 0-137-111-248-247-248-137 0-249 111-249 248 0 83 41 157 104 202 12 8 28 5 35-8l16-28c6-11 3-24-7-31-41-31-68-80-68-135 0-92 75-168 168-168 92 0 169 74 168 169 0 52-25 102-68 134-10 7-12 21-7 31l16 28c7 12 23 16 35 8z m-104-210l0 240c0 13-11 24-24 24l-32 0c-13 0-24-11-24-24l0-240c0-13 11-24 24-24l32 0c13 0 24 11 24 24z"/> + <glyph glyph-name="rectangle-landscape" unicode="2" + d="M464 64l-416 0c-26 0-48 21-48 48l0 288c0 26 22 48 48 48l416 0c27 0 48-22 48-48l0-288c0-27-21-48-48-48z"/> + <glyph glyph-name="bars" unicode="3" + d="M48 380l416 0c9 0 16 7 16 16l0 40c0 9-7 16-16 16l-416 0c-9 0-16-7-16-16l0-40c0-9 7-16 16-16z m0-160l416 0c9 0 16 7 16 16l0 40c0 9-7 16-16 16l-416 0c-9 0-16-7-16-16l0-40c0-9 7-16 16-16z m0-160l416 0c9 0 16 7 16 16l0 40c0 9-7 16-16 16l-416 0c-9 0-16-7-16-16l0-40c0-9 7-16 16-16z"/> + <glyph glyph-name="arrow-to-left" unicode="4" + d="M32 88l0 336c0 13 11 24 24 24l24 0c13 0 24-11 24-24l0-336c0-13-11-24-24-24l-24 0c-13 0-24 11-24 24z m281 66l-66 66 209 0c13 0 24 11 24 24l0 24c0 13-11 24-24 24l-209 0 66 66c9 9 9 24 0 33l-17 17c-10 10-25 10-34 0l-136-135c-9-9-9-25 0-34l136-135c9-10 24-10 34 0l17 17c9 9 9 24 0 33z"/> + <glyph glyph-name="arrow-to-right" unicode="5" + d="M480 424l0-336c0-13-11-24-24-24l-24 0c-13 0-24 11-24 24l0 336c0 13 11 24 24 24l24 0c13 0 24-11 24-24z m-280-66l65-66-209 0c-13 0-24-11-24-24l0-24c0-13 11-24 24-24l209 0-65-66c-10-9-10-24 0-34l17-17c9-9 24-9 33 0l136 136c9 9 9 25 0 34l-136 135c-9 10-24 10-33 0l-17-17c-10-9-10-24 0-33z"/> + <glyph glyph-name="archive-arrow-down" unicode="6" + d="M32 64c0-18 14-32 32-32l384 0c18 0 32 14 32 32l0 288-448 0z m448 416l-448 0c-18 0-32-14-32-32l0-48c0-9 7-16 16-16l480 0c9 0 16 7 16 16l0 48c0 18-14 32-32 32z m-113-320l-93-92c-5-5-11-7-17-7-6 0-13 2-17 7l-93 92c-4 5-7 11-7 17 0 7 3 13 7 17l11 11c5 5 11 7 17 7 7 0 13-3 18-7l32-35 0 126c0 6 3 12 7 17 5 4 11 7 17 7l16 0c6 0 12-3 17-7 4-5 7-11 7-17l0-126 32 35c5 4 11 7 18 7 6 0 12-2 17-7l11-11c9-9 9-24 0-34z"/> + <glyph glyph-name="archive-arrow-up" unicode="7" + d="M32 64c0-18 14-32 32-32l384 0c18 0 32 14 32 32l0 288-448 0z m448 416l-448 0c-18 0-32-14-32-32l0-48c0-9 7-16 16-16l480 0c9 0 16 7 16 16l0 48c0 18-14 32-32 32z m-333-256l93 92c5 5 11 7 17 7 6 0 13-2 17-7l93-92c4-5 7-11 7-17 0-7-3-13-7-17l-11-11c-5-5-11-7-17-7-7 0-13 3-18 7l-32 35 0-126c0-6-3-12-7-17-5-4-11-7-17-7l-16 0c-6 0-12 3-17 7-4 5-7 11-7 17l0 126-32-35c-5-4-11-7-18-7-6 0-12 2-17 7l-11 11c-9 9-9 24 0 34z"/> + <glyph glyph-name="arrow-to-bottom" unicode="8" + d="M424 32l-336 0c-13 0-24 11-24 24l0 24c0 13 11 24 24 24l336 0c13 0 24-11 24-24l0-24c0-13-11-24-24-24z m-66 280l-66-65 0 209c0 13-11 24-24 24l-24 0c-13 0-24-11-24-24l0-209-66 65c-9 10-24 10-33 0l-17-17c-10-9-10-24 0-33l135-136c9-9 25-9 34 0l135 136c10 9 10 24 0 33l-17 17c-9 10-24 10-33 0z"/> + <glyph glyph-name="file-csv" unicode="9" + d="M288 376l0 136-200 0c-13 0-24-11-24-24l0-464c0-13 11-24 24-24l336 0c13 0 24 11 24 24l0 328-136 0c-13 0-24 11-24 24z m-96-144c0-4-4-8-8-8l-8 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l8 0c4 0 8-4 8-8l0-16c0-4-4-8-8-8l-8 0c-27 0-48 21-48 48l0 32c0 27 21 48 48 48l8 0c4 0 8-4 8-8z m44-104l-12 0c-4 0-8 4-8 8l0 16c0 4 4 8 8 8l12 0c6 0 11 3 11 7 0 1-1 2-2 3l-22 19c-9 7-14 18-14 28 0 22 19 39 43 39l12 0c4 0 8-4 8-8l0-16c0-4-4-8-8-8l-12 0c-6 0-11-4-11-7 0-1 1-2 2-3l22-19c9-7 14-18 14-28 0-22-19-39-43-39z m84 120l0-21c0-20 6-40 16-57 10 17 16 37 16 57l0 21c0 4 4 8 8 8l16 0c4 0 8-4 8-8l0-21c0-35-13-69-36-94-3-3-8-5-12-5-4 0-9 2-12 5-23 25-36 59-36 94l0 21c0 4 4 8 8 8l16 0c4 0 8-4 8-8z m121 159l-98 98c-4 4-10 7-17 7l-6 0 0-128 128 0 0 6c0 6-2 12-7 17z"/> + <glyph glyph-name="map" unicode="!" + d="M0 379l0-308c0-10 10-17 20-13l122 56 0 341-124-50c-11-4-18-14-18-26z m171-265l170-57 0 341-170 57z m321 340l-122-56 0-341 124 50c11 4 18 14 18 26l0 308c0 10-10 17-20 13z"/> + <glyph glyph-name="graph" unicode=""" + d="M440 288c-28 0-53-16-65-41l-31 6c0 1 0 2 0 3 0 28-13 55-36 71l20 43c36-8 72 12 84 46 12 35-4 73-37 89-33 16-73 4-92-27-19-31-12-72 16-94l-20-43c-25 7-52 2-73-13l-73 74c19 31 13 71-16 94-29 23-70 21-96-5-26-26-28-67-5-96 23-29 63-35 94-16l74-73c-19-28-21-64-5-93l-63-52c-29 22-70 19-96-7-25-26-27-68-3-96 23-28 64-34 94-14 31 20 42 60 25 92l64 53c22-19 51-25 79-18l20-43c-28-22-36-63-16-94 19-31 59-43 92-27 33 16 49 54 37 89-12 34-48 54-84 46l-20 43c13 9 23 22 29 37l31-7c0-39 33-71 72-71 40 0 72 33 72 72 0 40-32 72-72 72z"/> + <glyph glyph-name="twitter" unicode="#" + d="M459 360c1-4 1-9 1-13 0-139-106-299-299-299-59 0-115 17-161 47 8-1 17-1 25-1 49 0 95 16 131 45-47 1-85 31-98 72 6 0 12-1 19-1 10 0 19 1 28 3-48 10-84 52-84 103l0 2c14-8 30-13 47-14-28 19-47 51-47 88 0 19 6 37 15 53 51-64 129-106 216-110-2 8-2 16-2 24 0 58 46 105 104 105 31 0 58-13 77-33 24 4 47 13 67 25-8-24-25-45-46-58 21 3 41 8 60 17-14-21-32-40-53-55z"/> + <glyph glyph-name="user-secret" unicode="$" + d="M416 204l24 62c4 11-4 22-15 22l-59 0c11 19 18 41 18 64l0 0c39 8 64 19 64 32 0 13-27 25-70 33-9 33-27 66-41 83-9 12-25 15-39 9l-28-14c-9-5-19-5-28 0l-28 14c-13 6-30 3-39-9-14-17-32-50-41-83-43-8-70-20-70-33 0-13 25-24 64-32l0 0c0-23 7-45 18-64l-58 0c-11 0-19-12-14-22l25-61c-40-23-67-66-67-115l0-45c0-25 20-45 45-45l358 0c25 0 45 20 45 45l0 45c0 48-26 90-64 114z m-208-172l-42 192 50-32 24-40z m96 0l-32 120 24 40 50 32z m42 298c-4-11-7-24-17-33-10-9-48-22-64 25-3 8-15 8-18 0-17-50-56-32-64-25-10 9-13 22-17 33 0 3-6 6-6 6l0 11c28-4 61-6 96-6 35 0 68 2 96 6l0-11c0 0-5-3-6-6z"/> + <glyph glyph-name="envelope" unicode="&" + d="M502 321c4 3 10 0 10-5l0-204c0-27-21-48-48-48l-416 0c-26 0-48 21-48 48l0 204c0 5 6 8 10 5 22-17 52-39 154-114 21-15 57-47 92-47 36 0 72 33 92 47 102 75 132 97 154 114z m-246-129c23 0 57 29 73 41 133 97 143 105 174 129 6 5 9 12 9 19l0 19c0 26-21 48-48 48l-416 0c-26 0-48-22-48-48l0-19c0-7 3-14 9-19 31-24 41-32 174-129 16-12 50-41 73-41z"/> + <glyph glyph-name="money-check-edit-alt" unicode="'" + d="M164 368l3-4 57 58-33 33c-7 8-20 8-27 0l-30-30c-8-8-8-20 0-27z m322-35l-136 0 96-96c9-10 15-23 15-37l0-59c0-7-6-13-13-13l-237 0c-3 0-6 3-6 6l0 13c0 4 3 7 6 7l131 0-52 51-79 0c-3 0-6 3-6 6l0 13c0 4 3 6 6 6l54 0-103 103-136 0c-15 0-26-12-26-26l0-230c0-14 11-26 26-26l460 0c15 0 26 12 26 26l0 230c0 14-11 26-26 26z m-371-205l0-13c0-3-3-6-6-6l-13 0c-4 0-6 3-6 6l0 13c-9 1-18 4-25 9-2 1-3 3-3 5 0 2 1 4 2 5l9 9c3 2 6 2 9 1 3-2 6-3 10-3l22 0c5 0 10 4 10 10 0 5-3 9-7 10l-36 11c-15 5-26 19-26 35 0 19 16 35 35 36l0 13c0 3 2 6 6 6l13 0c3 0 6-3 6-6l0-13c9-1 18-4 25-9 2-1 3-3 3-5 0-2-1-4-2-5l-10-9c-2-2-5-2-8-1-3 2-6 3-10 3l-23 0c-5 0-9-4-9-10 0-5 3-9 7-10l36-11c15-5 25-19 25-35 0-19-15-35-34-36z m255 33c5-5 12-7 18-7l34 0c7 0 13 5 13 12l0 34c0 7-2 14-7 18l-185 186-58-58z"/> + <glyph glyph-name="home" unicode="%" + d="M249 352l-164-135 0-146c0-8 7-14 15-14l99 0c8 0 14 7 14 14l0 85c0 8 7 15 15 15l56 0c8 0 15-7 15-15l0-85c0-3 1-7 4-10 2-2 6-4 10-4l99 0c8 0 15 6 15 14l0 146-164 135c-4 3-10 3-14 0z m259-92l-74 61 0 123c0 6-5 11-11 11l-50 0c-6 0-10-5-10-11l0-64-80 65c-16 13-38 13-54 0l-225-185c-5-4-5-10-2-15l23-28c2-2 4-3 7-3 3-1 6 0 8 2l209 172c4 3 10 3 14 0l209-172c4-4 11-3 15 1l23 28c1 2 2 5 2 8 0 3-2 5-4 7z"/> + <glyph glyph-name="calendar-plus" unicode="(" + d="M468 352l-424 0c-7 0-12 5-12 12l0 36c0 26 22 48 48 48l48 0 0 52c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-52 128 0 0 52c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-52 48 0c27 0 48-22 48-48l0-36c0-7-5-12-12-12z m-424-32l424 0c7 0 12-5 12-12l0-260c0-27-21-48-48-48l-352 0c-26 0-48 21-48 48l0 260c0 7 5 12 12 12z m316-140c0 7-5 12-12 12l-60 0 0 60c0 7-5 12-12 12l-40 0c-7 0-12-5-12-12l0-60-60 0c-7 0-12-5-12-12l0-40c0-7 5-12 12-12l60 0 0-60c0-7 5-12 12-12l40 0c7 0 12 5 12 12l0 60 60 0c7 0 12 5 12 12z"/> + <glyph glyph-name="siren-on" unicode=")" + d="M179 353c1 2 1 3 3 4 1 1 3 2 5 1l12-1c2-1 3-1 4-3 2-1 2-3 2-5l-20-144 212 0-20 160c-3 25-25 45-51 45l-140 0c-26 0-48-20-51-45l-20-160 45 0z m243-174l-332 0c-7 0-13-6-13-13l0-51c0-7 6-13 13-13l332 0c7 0 13 6 13 13l0 51c0 7-6 13-13 13z m-332 128c0 11-9 19-20 19l-51 0c-10 0-19-8-19-19 0-10 9-19 19-19l51 0c11 0 20 9 20 19z m403 19l-51 0c-11 0-20-8-20-19 0-10 9-19 20-19l51 0c10 0 19 9 19 19 0 11-9 19-19 19z m-420 74c5-4 13-5 19-2 6 3 10 10 11 17 0 7-3 13-9 17l-39 26c-5 4-13 4-19 1-6-3-10-9-11-16 0-7 3-14 9-17z m356-3c4 0 7 1 10 3l39 26c6 3 9 10 9 17-1 7-5 13-11 16-6 3-14 3-19-1l-39-26c-7-5-10-13-8-22 3-8 10-13 19-13z"/> + <glyph glyph-name="tag" unicode="*" + d="M0 260l0 204c0 27 21 48 48 48l204 0c13 0 25-5 34-14l212-212c19-19 19-49 0-68l-204-204c-19-19-49-19-68 0l-212 212c-9 9-14 21-14 34z m112 188c-27 0-48-21-48-48 0-27 21-48 48-48 27 0 48 21 48 48 0 27-21 48-48 48z"/> + <glyph glyph-name="external-link-alt" unicode="+" + d="M512 462l0-114c0-19-23-28-36-15l-32 32-217-216c-8-9-21-9-30 0l-20 20c-8 8-8 22 0 30l217 216-32 32c-14 14-4 37 15 37l114 0c11 0 21-10 21-22z m-150-219l-14-14c-4-4-7-10-7-15l0-129-284 0 0 285 235 0c5 0 11 2 15 6l14 14c13 14 4 37-15 37l-263 0c-24 0-43-19-43-43l0-313c0-23 19-43 43-43l313 0c23 0 42 20 42 43l0 157c0 19-23 28-36 15z"/> + <glyph glyph-name="radar" unicode="," + d="M504 256c0-137-111-248-248-248-137 0-248 111-248 248 0 137 111 248 248 248 50 0 98-15 139-43l30 30c7 7 17 7 23 0l11-11c7-6 7-16 0-23l-201-201 0 0 62 0c0-35-28-64-63-64-35-1-64 27-65 62-1 35 27 65 62 66l28 28c-8 3-17 4-26 4-53 0-96-43-96-96 0-53 43-96 96-96 53 0 96 43 96 96l64 0c0-80-58-145-135-157-5 8-14 13-25 13-11 0-20-5-25-13-68 11-121 64-132 132 8 5 13 14 13 25 0 11-5 20-13 25 12 76 77 135 157 135 27 0 52-7 75-20l24 24c-30 18-64 28-99 28-96 0-176-71-190-163-11-5-18-17-18-29 0-12 7-24 18-29 13-83 78-148 161-161 5-11 17-18 29-18 12 0 24 7 29 18 92 14 163 94 163 190z"/> + <glyph glyph-name="balance-scale" unicode="-" + d="M205 192l0 0c0 13 1 7-68 145-14 28-55 28-69 0-70-139-68-132-68-145l0 0c0-35 46-64 102-64 57 0 103 29 103 64z m-103 128l58-115-115 0z m410-128c0 13 1 7-68 145-14 28-55 28-69 0-69-139-68-132-68-145l0 0c0-35 46-64 103-64 56 0 102 29 102 64z m-160 13l58 115 57-115z m70-103l-140 0 0 236c18 8 33 25 37 46l103 0c7 0 13 6 13 13l0 25c0 7-6 13-13 13l-115 0c-12 16-30 26-51 26-21 0-39-10-51-26l-115 0c-7 0-13-6-13-13l0-25c0-7 6-13 13-13l103 0c4-21 19-38 37-46l0-236-140 0c-7 0-13-5-13-12l0-26c0-7 6-13 13-13l332 0c7 0 13 6 13 13l0 26c0 7-6 12-13 12z"/> + <glyph glyph-name="cannabis" unicode="." + d="M503 152c-1 1-32 17-76 26 64 75 84 161 85 165 1 6-1 11-5 15-3 3-7 5-11 5-1 0-2 0-3-1-4-1-87-19-161-79 0 1 0 2 0 4 0 119-60 214-63 218-2 4-8 7-13 7-5 0-11-3-13-7-3-4-63-99-63-218 0-2 0-3 0-4-74 60-157 78-161 79-1 1-2 1-3 1-4 0-8-2-11-5-4-4-6-9-5-15 1-4 21-90 85-165-44-9-75-25-76-26-6-3-9-8-9-14 0-6 3-12 9-15 2-1 60-31 133-31 6 0 12 0 18 0-12-22-17-38-17-39-2-6-1-12 4-16 4-5 10-6 16-4 2 0 37 12 77 39l0-64c0-4 4-8 8-8l16 0c4 0 8 4 8 8l0 64c40-27 75-39 77-39 6-2 12-1 16 4 5 4 6 10 4 16 0 1-5 17-16 39 5 0 11 0 17 0 73 0 131 30 133 31 6 3 9 9 9 15 0 6-3 11-9 14z"/> + <glyph glyph-name="sign" unicode="/" + d="M496 448l-368 0 0 48c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-48-48 0c-9 0-16-7-16-16l0-32c0-9 7-16 16-16l48 0 0-368c0-9 7-16 16-16l32 0c9 0 16 7 16 16l0 368 368 0c9 0 16 7 16 16l0 32c0 9-7 16-16 16z m-336-320l320 0 0 224-320 0z"/> + <glyph glyph-name="pen-nib" unicode=":" + d="M137 373c-21-6-37-21-44-41l-93-280 15-15 150 150c-3 7-5 14-5 21 0 27 21 48 48 48 27 0 48-21 48-48 0-27-21-48-48-48-7 0-14 2-21 5l-150-150 15-15 280 93c20 7 35 23 41 44l43 151-128 128z m361 65l-60 60c-19 19-49 19-68 0l-57-57 128-128 57 57c19 19 19 49 0 68z"/> + <glyph glyph-name="image" unicode=";" + d="M464 448l-416 0c-27 0-48-21-48-48l0-288c0-27 21-48 48-48l416 0c27 0 48 21 48 48l0 288c0 27-21 48-48 48z m-6-336l-404 0c-3 0-6 3-6 6l0 276c0 3 3 6 6 6l404 0c3 0 6-3 6-6l0-276c0-3-3-6-6-6z m-330 248c-22 0-40-18-40-40 0-22 18-40 40-40 22 0 40 18 40 40 0 22-18 40-40 40z m-32-200l320 0 0 80-88 88c-4 4-12 4-16 0l-120-120-40 40c-4 4-12 4-16 0l-40-40z"/> + <glyph glyph-name="clock" unicode="<" + d="M256 504c-137 0-248-111-248-248 0-137 111-248 248-248 137 0 248 111 248 248 0 137-111 248-248 248z m57-350l-88 64c-3 2-5 6-5 10l0 168c0 7 5 12 12 12l48 0c7 0 12-5 12-12l0-138 64-46c5-4 6-11 2-17l-28-39c-4-5-11-6-17-2z"/> + <glyph glyph-name="address-card" unicode="?" + d="M469 455l-426 0c-24 0-43-19-43-43l0-312c0-24 19-43 43-43l426 0c24 0 43 19 43 43l0 312c0 24-19 43-43 43z m-313-85c32 0 57-26 57-57 0-31-25-57-57-57-31 0-56 26-56 57 0 31 25 57 56 57z m100-211c0-9-9-17-20-17l-159 0c-11 0-20 8-20 17l0 17c0 29 27 52 60 52l4 0c11-5 23-8 35-8 13 0 25 3 36 8l4 0c33 0 60-23 60-52z m199 47c0-4-3-7-7-7l-128 0c-4 0-7 3-7 7l0 14c0 4 3 8 7 8l128 0c4 0 7-4 7-8z m0 57c0-4-3-7-7-7l-128 0c-4 0-7 3-7 7l0 14c0 4 3 7 7 7l128 0c4 0 7-3 7-7z m0 57c0-4-3-7-7-7l-128 0c-4 0-7 3-7 7l0 14c0 4 3 7 7 7l128 0c4 0 7-3 7-7z"/> + <glyph glyph-name="comment-alt-exclamation" unicode="@" + d="M448 512l-384 0c-35 0-64-29-64-64l0-288c0-35 29-64 64-64l96 0 0-84c0-10 11-16 19-10l125 94 144 0c35 0 64 29 64 64l0 288c0 35-29 64-64 64z m-192-336c-18 0-32 14-32 32 0 18 14 32 32 32 18 0 32-14 32-32 0-18-14-32-32-32z m25 110c0-8-7-14-15-14l-19 0c-9 0-16 6-16 14l-13 128c-1 10 6 18 16 18l44 0c10 0 17-8 16-18z"/> + <glyph glyph-name="comment-alt-dots" unicode="[" + d="M448 512l-384 0c-35 0-64-29-64-64l0-288c0-35 29-64 64-64l96 0 0-84c0-10 11-16 19-10l125 94 144 0c35 0 64 29 64 64l0 288c0 35-29 64-64 64z m-320-240c-18 0-32 14-32 32 0 18 14 32 32 32 18 0 32-14 32-32 0-18-14-32-32-32z m128 0c-18 0-32 14-32 32 0 18 14 32 32 32 18 0 32-14 32-32 0-18-14-32-32-32z m128 0c-18 0-32 14-32 32 0 18 14 32 32 32 18 0 32-14 32-32 0-18-14-32-32-32z"/> + <glyph glyph-name="image-alt" unicode=">" + d="M464 64l-416 0c-27 0-48 21-48 48l0 288c0 27 21 48 48 48l416 0c27 0 48-21 48-48l0-288c0-27-21-48-48-48z m-352 328c-31 0-56-25-56-56 0-31 25-56 56-56 31 0 56 25 56 56 0 31-25 56-56 56z m-48-264l384 0 0 112-88 88c-4 4-12 4-16 0l-136-136-56 56c-4 4-12 4-16 0l-72-72z"/> + <glyph glyph-name="calendar-alt" unicode="]" + d="M32 48c0-27 22-48 48-48l352 0c27 0 48 21 48 48l0 272-448 0z m320 196c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m0-128c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m-128 128c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m0-128c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m-128 128c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m0-128c0 7 5 12 12 12l40 0c7 0 12-5 12-12l0-40c0-7-5-12-12-12l-40 0c-7 0-12 5-12 12z m336 332l-48 0 0 48c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-48-128 0 0 48c0 9-7 16-16 16l-32 0c-9 0-16-7-16-16l0-48-48 0c-26 0-48-22-48-48l0-48 448 0 0 48c0 26-21 48-48 48z"/> + <glyph glyph-name="play" unicode="^" + d="M456 297l-352 208c-28 17-72 1-72-41l0-416c0-38 41-60 72-41l352 208c32 18 32 64 0 82z"/> + <glyph glyph-name="pause" unicode="_" + d="M176 33l-96 0c-26 0-48 21-48 48l0 352c0 26 22 48 48 48l96 0c27 0 48-22 48-48l0-352c0-27-21-48-48-48z m304 48l0 352c0 26-21 48-48 48l-96 0c-26 0-48-22-48-48l0-352c0-27 22-48 48-48l96 0c27 0 48 21 48 48z"/> + <glyph glyph-name="hourglass-full" unicode="{" + d="M424 448c13 0 24 11 24 24l0 16c0 13-11 24-24 24l-336 0c-13 0-24-11-24-24l0-16c0-13 11-24 24-24 0-91 51-168 121-192-70-24-121-101-121-192-13 0-24-11-24-24l0-16c0-13 11-24 24-24l336 0c13 0 24 11 24 24l0 16c0 13-11 24-24 24 0 91-51 168-121 192 70 24 121 101 121 192z"/> + <glyph glyph-name="hourglass-empty" unicode="`" + d="M432 464l4 0c7 0 12 5 12 12l0 24c0 7-5 12-12 12l-360 0c-7 0-12-5-12-12l0-24c0-7 5-12 12-12l4 0c0-81 32-166 97-208-65-42-97-128-97-208l-4 0c-7 0-12-5-12-12l0-24c0-7 5-12 12-12l360 0c7 0 12 5 12 12l0 24c0 7-5 12-12 12l-4 0c0 81-32 166-97 208 65 42 97 128 97 208z m-304 0l256 0c0-102-57-184-128-184-71 0-128 82-128 184z m256-416l-256 0c0 102 57 184 128 184 71 0 128-82 128-184z"/> + <glyph glyph-name="file-alt" unicode="|" + d="M288 376l0 136-200 0c-13 0-24-11-24-24l0-464c0-13 11-24 24-24l336 0c13 0 24 11 24 24l0 328-136 0c-13 0-24 11-24 24z m64-236c0-7-5-12-12-12l-168 0c-7 0-12 5-12 12l0 8c0 7 5 12 12 12l168 0c7 0 12-5 12-12z m0 64c0-7-5-12-12-12l-168 0c-7 0-12 5-12 12l0 8c0 7 5 12 12 12l168 0c7 0 12-5 12-12z m0 72l0-8c0-7-5-12-12-12l-168 0c-7 0-12 5-12 12l0 8c0 7 5 12 12 12l168 0c7 0 12-5 12-12z m96 114l0-6-128 0 0 128 6 0c7 0 13-3 17-7l98-98c5-5 7-11 7-17z"/> + <glyph glyph-name="adjust" unicode="}" + d="M8 256c0-137 111-248 248-248 137 0 248 111 248 248 0 137-111 248-248 248-137 0-248-111-248-248z m248-184l0 368c102 0 184-82 184-184 0-102-82-184-184-184z"/> + <glyph glyph-name="dna" unicode="~" + d="M32 18c-1-10 6-18 16-18l32 0c8 0 15 6 16 14 1 5 2 11 4 18l312 0c2-7 3-13 4-18 1-8 7-14 16-14l32 0c9 0 17 8 16 18-5 38-26 129-119 208-18-13-37-25-59-36 7-4 12-9 17-14l-127 0c21 18 47 36 78 51 173 86 204 219 210 267 1 10-6 18-16 18l-32 0c-8 0-15-6-16-14-1-5-2-11-4-18l-312 0c-2 7-3 13-4 18-1 8-7 14-16 14l-32 0c-9 0-17-8-16-18 5-43 31-154 160-238-128-84-155-195-160-238z m224 274c-25 14-46 29-64 44l128 0c-18-15-39-30-64-44z m131 124c-6-10-13-21-21-32l-220 0c-8 11-15 22-21 32z m-262-320c6 10 13 21 21 32l219 0c9-11 16-22 22-32z"/> + <glyph glyph-name="database" unicode="\" + d="M480 439l0-46c0-40-100-73-224-73-124 0-224 33-224 73l0 46c0 40 100 73 224 73 124 0 224-33 224-73z m0-103l0-103c0-40-100-73-224-73-124 0-224 33-224 73l0 103c48-33 136-49 224-49 88 0 176 16 224 49z m0-160l0-103c0-40-100-73-224-73-124 0-224 33-224 73l0 103c48-33 136-49 224-49 88 0 176 16 224 49z"/> + <glyph glyph-name="tree-palm" unicode="" + d="M359 410c-32 0-60-10-82-25-15 44-65 76-124 76-65 0-118-38-127-87-2-8 5-16 14-16l43 0 19 39 27-54c-3-2-6-4-8-7-46-46-57-110-29-152 5-6 15-7 21 0l117 117c9-84-9-172-21-218-4-16 9-32 25-32l44 0c13 0 24 9 26 22 12 91-10 189-21 234l107 0 20 39 19-39 43 0c9 0 16 8 14 16-9 49-62 87-127 87z"/> + <glyph glyph-name="checkbox" unicode="" + d="M432 480l-352 0c-26 0-48-22-48-48l0-352c0-27 22-48 48-48l352 0c27 0 48 21 48 48l0 352c0 26-21 48-48 48z"/> + <glyph glyph-name="arrows" unicode="" + d="M353 83l-74-74c-13-12-33-12-46 0l-74 74c-9 10-9 25 0 34l11 11c10 10 25 9 35 0l23-26 0 126-126 0 26-23c10-10 10-25 0-35l-11-11c-9-9-24-9-34 0l-74 74c-12 13-12 33 0 46l74 74c10 9 25 9 34 0l11-11c10-10 10-25 0-35l-26-23 126 0 0 126-23-26c-10-10-25-10-35 0l-11 11c-9 9-9 24 0 34l74 74c13 12 33 12 46 0l74-74c9-10 9-25 0-34l-11-11c-10-10-25-10-35 0l-23 26 0-126 126 0-26 23c-9 10-10 25 0 35l11 11c9 9 24 9 34 0l74-74c12-13 12-33 0-46l-74-74c-10-9-25-9-34 0l-11 11c-10 10-9 25 0 35l26 23-126 0 0-126 23 26c10 9 25 10 35 0l11-11c9-9 9-24 0-34z"/> + <glyph glyph-name="bookmark" unicode="" + d="M64 0l0 464c0 27 21 48 48 48l288 0c27 0 48-21 48-48l0-464-192 112z"/> + <glyph glyph-name="bookmark-o" unicode="" + d="M400 512l-288 0c-27 0-48-21-48-48l0-464 192 112 192-112 0 464c0 27-21 48-48 48z m0-428l-144 84-144-84 0 374c0 3 3 6 6 6l276 0c3 0 6-3 6-6z"/> + <glyph glyph-name="file-code" unicode="" + d="M448 390l0-6-128 0 0 128 6 0c6 0 13-3 17-7l98-98c4-4 7-11 7-17z m-136-38c-13 0-24 11-24 24l0 136-200 0c-13 0-24-11-24-24l0-464c0-13 11-24 24-24l336 0c13 0 24 11 24 24l0 328z m-125-241c-2-2-5-2-7 0l-65 61c-1 1-2 3-2 4 0 1 1 3 2 4l65 61c2 2 5 2 7 0l20-21c1-1 1-3 1-4 0-2 0-3-2-4l-40-36 40-36c2-1 2-2 2-4 0-1 0-3-1-4z m52-50l-28 8c-3 1-4 4-4 7l62 211c1 3 4 5 7 4l27-8c3-1 4-4 4-7l-62-211c-1-3-4-5-6-4z m160 111l-65-61c-2-2-5-2-7 0l-20 21c-1 1-1 3-1 4 0 2 0 3 2 4l40 36-40 36c-2 1-2 2-2 4 0 1 0 3 1 4l20 21c2 2 5 2 7 0l65-61c1-1 2-3 2-4 0-1-1-3-2-4z"/> + <glyph glyph-name="star" unicode="=" + d="M230 468l-58-118-129-19c-24-3-33-32-16-48l94-92-22-129c-4-24 20-41 41-30l116 61 116-61c21-11 45 6 41 30l-22 129 94 92c17 16 8 45-16 48l-129 19-58 118c-11 21-41 21-52 0z"/> + <glyph glyph-name="thumbs-up" unicode="" + d="M104 288l-80 0c-13 0-24-11-24-24l0-240c0-13 11-24 24-24l80 0c13 0 24 11 24 24l0 240c0 13-11 24-24 24z m-40-248c-13 0-24 11-24 24 0 13 11 24 24 24 13 0 24-11 24-24 0-13-11-24-24-24z m320 391c0-43-26-67-33-95l101 0c34 0 60-28 60-58 0-18-8-37-19-49l-1 0c10-24 9-56-9-80 9-26 0-58-16-75 4-17 2-32-6-44-21-30-71-30-114-30l-3 0c-48 0-88 18-120 32-16 7-36 16-52 16-7 0-12 5-12 12l0 214c0 3 1 6 4 8 39 39 56 81 89 113 14 15 20 38 25 59 5 19 14 58 34 58 24 0 72-8 72-81z"/> + <glyph glyph-name="map-marker-check" unicode="" + d="M256 512c-106 0-192-86-192-192 0-77 26-99 173-310 9-13 29-13 38 0 147 211 173 233 173 310 0 106-86 192-192 192z m114-164l-131-130c-4-4-11-4-16 0l-75 77c-5 4-4 11 0 15l26 26c4 4 11 4 15 0l43-43 97 97c4 4 11 4 15 0l26-26c4-5 4-12 0-16z"/> + <glyph glyph-name="sticky-note" unicode="" + d="M344 192l136 0 0 264c0 13-11 24-24 24l-400 0c-13 0-24-11-24-24l0-400c0-13 11-24 24-24l264 0 0 136c0 13 11 24 24 24z m129-55l-98-98c-4-5-11-7-17-7l-6 0 0 128 128 0 0-6c0-6-2-13-7-17z"/> + <glyph glyph-name="camera" unicode="" + d="M512 368l0-288c0-27-21-48-48-48l-416 0c-26 0-48 21-48 48l0 288c0 26 22 48 48 48l88 0 12 33c7 19 25 31 45 31l126 0c20 0 38-12 45-31l12-33 88 0c27 0 48-22 48-48z m-136-144c0 66-54 120-120 120-66 0-120-54-120-120 0-66 54-120 120-120 66 0 120 54 120 120z m-32 0c0-49-39-88-88-88-48 0-88 39-88 88 0 48 40 88 88 88 49 0 88-40 88-88z"/> + <glyph glyph-name="file-upload" unicode="" + d="M288 376l0 136-200 0c-13 0-24-11-24-24l0-464c0-13 11-24 24-24l336 0c13 0 24 11 24 24l0 328-136 0c-13 0-24 11-24 24z m65-216l-65 0 0-80c0-9-7-16-16-16l-32 0c-9 0-16 7-16 16l0 80-65 0c-14 0-22 17-11 27l96 96c7 7 17 7 24 0l96-96c11-10 3-27-11-27z m88 247l-98 98c-4 4-10 7-17 7l-6 0 0-128 128 0 0 6c0 6-2 12-7 17z"/> + <glyph glyph-name="circle" unicode="" + d="M256 504c-137 0-248-111-248-248 0-137 111-248 248-248 137 0 248 111 248 248 0 137-111 248-248 248z"/> + <glyph glyph-name="copy" unicode="" + d="M352 64l0-40c0-13-11-24-24-24l-272 0c-13 0-24 11-24 24l0 368c0 13 11 24 24 24l72 0 0-296c0-31 25-56 56-56z m0 344l0 104-168 0c-13 0-24-11-24-24l0-368c0-13 11-24 24-24l272 0c13 0 24 11 24 24l0 264-104 0c-13 0-24 11-24 24z m121 31l-66 66c-4 4-11 7-17 7l-6 0 0-96 96 0 0 6c0 6-3 13-7 17z"/> + <glyph glyph-name="keyboard" unicode="" + d="M469 85l-426 0c-24 0-43 19-43 43l0 256c0 24 19 43 43 43l426 0c24 0 43-19 43-43l0-256c0-24-19-43-43-43z m-355 239l0 35c0 6-5 11-11 11l-35 0c-6 0-11-5-11-11l0-35c0-6 5-11 11-11l35 0c6 0 11 5 11 11z m85 0l0 35c0 6-5 11-11 11l-35 0c-6 0-11-5-11-11l0-35c0-6 5-11 11-11l35 0c6 0 11 5 11 11z m85 0l0 35c0 6-4 11-10 11l-36 0c-6 0-10-5-10-11l0-35c0-6 4-11 10-11l36 0c6 0 10 5 10 11z m86 0l0 35c0 6-5 11-11 11l-35 0c-6 0-11-5-11-11l0-35c0-6 5-11 11-11l35 0c6 0 11 5 11 11z m85 0l0 35c0 6-5 11-11 11l-35 0c-6 0-11-5-11-11l0-35c0-6 5-11 11-11l35 0c6 0 11 5 11 11z m-299-86l0 36c0 6-4 10-10 10l-36 0c-6 0-10-4-10-10l0-36c0-6 4-10 10-10l36 0c6 0 10 4 10 10z m86 0l0 36c0 6-5 10-11 10l-35 0c-6 0-11-4-11-10l0-36c0-6 5-10 11-10l35 0c6 0 11 4 11 10z m85 0l0 36c0 6-5 10-11 10l-35 0c-6 0-11-4-11-10l0-36c0-6 5-10 11-10l35 0c6 0 11 4 11 10z m85 0l0 36c0 6-4 10-10 10l-36 0c-6 0-10-4-10-10l0-36c0-6 4-10 10-10l36 0c6 0 10 4 10 10z m-298-85l0 35c0 6-5 11-11 11l-35 0c-6 0-11-5-11-11l0-35c0-6 5-11 11-11l35 0c6 0 11 5 11 11z m256 0l0 35c0 6-5 11-11 11l-206 0c-6 0-11-5-11-11l0-35c0-6 5-11 11-11l206 0c6 0 11 5 11 11z m85 0l0 35c0 6-5 11-11 11l-35 0c-6 0-11-5-11-11l0-35c0-6 5-11 11-11l35 0c6 0 11 5 11 11z"/> + <glyph glyph-name="cog" unicode="" + d="M487 196l-42 25c4 23 4 47 0 70l42 25c5 2 8 8 6 14-11 35-30 67-55 94-4 4-10 5-15 3l-42-25c-18 15-39 27-61 35l0 49c0 6-4 11-9 12-37 8-75 8-110 0-5-1-9-6-9-12l0-49c-22-8-43-20-61-35l-42 24c-5 3-11 2-15-2-25-27-44-59-55-94-1-6 1-12 6-14l42-25c-4-23-4-47 0-70l-42-25c-5-3-7-8-6-14 11-35 30-68 55-94 4-5 10-6 15-3l42 25c18-16 39-27 61-35l0-49c0-6 4-11 10-12 36-8 74-8 109 0 5 1 9 6 9 12l0 49c22 8 43 20 61 35l43-25c4-3 11-2 14 3 25 26 44 58 55 94 2 6-1 11-6 14z m-231-20c-44 0-80 36-80 80 0 44 36 80 80 80 44 0 80-36 80-80 0-44-36-80-80-80z"/> + <glyph glyph-name="star-half-alt" unicode="" + d="M486 337l-140 20-63 127c-5 11-16 17-27 17-11 0-22-6-27-17l-63-127-140-20c-25-4-35-35-17-52l101-99-24-139c-3-20 13-36 31-36 4 0 9 2 14 4l125 66 125-66c5-2 10-4 14-4 18 0 34 16 30 36l-23 139 101 99c18 17 8 48-17 52z m-117-118l-17-17 4-24 19-108-98 51-21 11 0 303 49-98 10-22 24-3 109-16z"/> + <glyph glyph-name="star-empty" unicode="" + d="M469 331l-129 19-58 118c-11 21-41 21-52 0l-58-118-129-19c-24-3-33-32-16-48l94-92-22-129c-4-24 20-41 41-30l116 61 116-61c21-11 45 6 41 30l-22 129 94 92c17 16 8 45-16 48z m-124-125l21-123-110 58-110-58 21 123-90 87 124 18 55 112 55-112 124-18z"/> + <glyph glyph-name="eye" unicode="" + d="M509 269c-48 94-144 158-253 158-109 0-205-64-253-158-4-8-4-18 0-26 48-94 144-158 253-158 109 0 205 64 253 158 4 8 4 18 0 26z m-253-141c-71 0-128 57-128 128 0 71 57 128 128 128 71 0 128-57 128-128 0-71-57-128-128-128z m0 213c-8 0-15-1-22-3 12-17 10-40-5-55-15-15-38-17-55-5-10-35 4-72 35-93 30-20 70-19 99 4 29 22 41 60 29 95-12 34-44 57-81 57z"/> + <glyph glyph-name="google-places" unicode="" + d="M256 512c-106 0-192-86-192-192 0-77 27-99 172-310 10-14 30-14 40 0 145 211 172 233 172 310 0 106-86 192-192 192z m3-286c-56 0-100 45-100 100 0 55 44 100 100 100 27 0 49-10 67-26l-28-26c-7 7-20 15-39 15-34 0-62-28-62-63 0-35 28-63 62-63 39 0 54 28 56 43l-56 0 0 34 94 0c1-5 2-10 2-16 0-57-39-98-96-98z"/> + <glyph glyph-name="review" unicode="" + d="M448 512l-384 0c-35 0-64-29-64-64l0-288c0-35 29-64 64-64l96 0 0-84c0-10 11-16 19-10l125 94 144 0c35 0 64 29 64 64l0 288c0 35-29 64-64 64z m-63-185c-1-3-2-6-5-9l-50-49 11-70c2-8-4-16-12-17-3-1-7 0-10 1l-62 33-63-33c-11-6-24 4-22 16l12 70-51 49c-6 6-6 16 0 22 3 2 6 4 9 4l70 11 31 63c4 8 13 11 21 7 3-1 5-4 7-7l31-63 70-11c8-1 14-9 13-17z"/> + <glyph glyph-name="google-account" unicode="" + d="M293 358c0-56-46-102-103-102-56 0-102 46-102 102 0 57 46 103 102 103 57 0 103-46 103-103z m65-296c-7-7-16-11-27-11l-281 0c-22 0-39 17-39 39l0 33c0 59 48 107 108 107l13 0c18-8 38-12 58-12 21 0 41 4 59 12l13 0c16 0 31-3 44-9-8-16-13-35-13-55 0-46 27-85 65-104z m52 24c-45 0-80 36-80 80 0 45 35 80 80 80 21 0 39-7 53-21l-21-20c-6 5-17 12-32 12-28 0-50-23-50-51 0-28 22-50 50-50 31 0 43 23 45 34l-45 0 0 28 75 0c1-4 1-8 1-14 0-45-30-78-76-78z"/> + <glyph glyph-name="building-info" unicode="" + d="M306 62c-11 12-20 25-27 40-6 15-9 32-9 48 0 17 3 34 9 49 7 15 16 28 27 40 8 8 17 14 27 20l0 183c0 10-9 19-19 19l-269 0c-11 0-19-9-19-19l0-365-16 0c-6 0-10-5-10-10l0-16 319 0c-5 4-9 7-13 11z m-204 338c0 5 5 10 10 10l32 0c5 0 10-5 10-10l0-32c0-5-5-10-10-10l-32 0c-5 0-10 5-10 10z m0-77c0 5 5 10 10 10l32 0c5 0 10-5 10-10l0-32c0-5-5-9-10-9l-32 0c-5 0-10 4-10 9z m42-118l-32 0c-5 0-10 4-10 9l0 32c0 6 5 10 10 10l32 0c5 0 10-4 10-10l0-32c0-5-5-9-10-9z m61-128l-51 0 0 67c0 5 4 10 9 10l32 0c5 0 10-5 10-10z m51 137c0-5-4-9-10-9l-32 0c-5 0-9 4-9 9l0 32c0 6 4 10 9 10l32 0c6 0 10-4 10-10z m0 77c0-5-4-9-10-9l-32 0c-5 0-9 4-9 9l0 32c0 5 4 10 9 10l32 0c6 0 10-5 10-10z m0 77c0-5-4-10-10-10l-32 0c-5 0-9 5-9 10l0 32c0 5 4 10 9 10l32 0c6 0 10-5 10-10z m138-118c-54 0-99-45-99-100 0-54 45-99 99-99 55 0 100 45 100 99 0 55-45 100-100 100z m0-44c10 0 17-8 17-17 0-9-7-17-17-17-9 0-16 8-16 17 0 9 7 17 16 17z m23-102c0-3-2-5-5-5l-35 0c-3 0-5 2-5 5l0 10c0 2 2 4 5 4l5 0 0 26-5 0c-3 0-5 2-5 5l0 9c0 3 2 5 5 5l25 0c3 0 5-2 5-5l0-40 5 0c3 0 5-2 5-4z"/> + </font> + </defs> +</svg> diff --git a/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.ttf b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4b2da8dd663489cf34950a4e10aa2fd7f67a962a Binary files /dev/null and b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.ttf differ diff --git a/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.woff b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.woff new file mode 100644 index 0000000000000000000000000000000000000000..429680489382f9ed7e4b1a56f61dfd4019752eb6 Binary files /dev/null and b/ldvspec/lofardata/static/lofardata/styling/fonts/icons/icon-dias.woff differ diff --git a/ldvspec/lofardata/static/lofardata/ldvspec_logo.png b/ldvspec/lofardata/static/lofardata/styling/images/ldvspec_logo.png similarity index 100% rename from ldvspec/lofardata/static/lofardata/ldvspec_logo.png rename to ldvspec/lofardata/static/lofardata/styling/images/ldvspec_logo.png diff --git a/ldvspec/lofardata/static/lofardata/styling/images/ldvspec_logo_2.png b/ldvspec/lofardata/static/lofardata/styling/images/ldvspec_logo_2.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e79cb4ce4a5780c83c39ee192dbf1cdb49aa5e Binary files /dev/null and b/ldvspec/lofardata/static/lofardata/styling/images/ldvspec_logo_2.png differ diff --git a/ldvspec/lofardata/static/lofardata/styling/images/spinner.svg b/ldvspec/lofardata/static/lofardata/styling/images/spinner.svg new file mode 100644 index 0000000000000000000000000000000000000000..ef5b3b070564412120c07c9641d1351304a23343 --- /dev/null +++ b/ldvspec/lofardata/static/lofardata/styling/images/spinner.svg @@ -0,0 +1,58 @@ +<svg version="1.1" + class="svg-loader" + xmlns="http://www.w3.org/2000/svg" + x="0px" + y="0px" + viewBox="0 0 80 80" + xml:space="preserve" +> + <path + fill="#262626" + d="M10,40c0,0,0-0.4,0-1.1c0-0.3,0-0.8,0-1.3c0-0.3,0-0.5,0-0.8c0-0.3,0.1-0.6,0.1-0.9c0.1-0.6,0.1-1.4,0.2-2.1 + c0.2-0.8,0.3-1.6,0.5-2.5c0.2-0.9,0.6-1.8,0.8-2.8c0.3-1,0.8-1.9,1.2-3c0.5-1,1.1-2,1.7-3.1c0.7-1,1.4-2.1,2.2-3.1 + c1.6-2.1,3.7-3.9,6-5.6c2.3-1.7,5-3,7.9-4.1c0.7-0.2,1.5-0.4,2.2-0.7c0.7-0.3,1.5-0.3,2.3-0.5c0.8-0.2,1.5-0.3,2.3-0.4l1.2-0.1 + l0.6-0.1l0.3,0l0.1,0l0.1,0l0,0c0.1,0-0.1,0,0.1,0c1.5,0,2.9-0.1,4.5,0.2c0.8,0.1,1.6,0.1,2.4,0.3c0.8,0.2,1.5,0.3,2.3,0.5 + c3,0.8,5.9,2,8.5,3.6c2.6,1.6,4.9,3.4,6.8,5.4c1,1,1.8,2.1,2.7,3.1c0.8,1.1,1.5,2.1,2.1,3.2c0.6,1.1,1.2,2.1,1.6,3.1 + c0.4,1,0.9,2,1.2,3c0.3,1,0.6,1.9,0.8,2.7c0.2,0.9,0.3,1.6,0.5,2.4c0.1,0.4,0.1,0.7,0.2,1c0,0.3,0.1,0.6,0.1,0.9 + c0.1,0.6,0.1,1,0.1,1.4C74,39.6,74,40,74,40c0.2,2.2-1.5,4.1-3.7,4.3s-4.1-1.5-4.3-3.7c0-0.1,0-0.2,0-0.3l0-0.4c0,0,0-0.3,0-0.9 + c0-0.3,0-0.7,0-1.1c0-0.2,0-0.5,0-0.7c0-0.2-0.1-0.5-0.1-0.8c-0.1-0.6-0.1-1.2-0.2-1.9c-0.1-0.7-0.3-1.4-0.4-2.2 + c-0.2-0.8-0.5-1.6-0.7-2.4c-0.3-0.8-0.7-1.7-1.1-2.6c-0.5-0.9-0.9-1.8-1.5-2.7c-0.6-0.9-1.2-1.8-1.9-2.7c-1.4-1.8-3.2-3.4-5.2-4.9 + c-2-1.5-4.4-2.7-6.9-3.6c-0.6-0.2-1.3-0.4-1.9-0.6c-0.7-0.2-1.3-0.3-1.9-0.4c-1.2-0.3-2.8-0.4-4.2-0.5l-2,0c-0.7,0-1.4,0.1-2.1,0.1 + c-0.7,0.1-1.4,0.1-2,0.3c-0.7,0.1-1.3,0.3-2,0.4c-2.6,0.7-5.2,1.7-7.5,3.1c-2.2,1.4-4.3,2.9-6,4.7c-0.9,0.8-1.6,1.8-2.4,2.7 + c-0.7,0.9-1.3,1.9-1.9,2.8c-0.5,1-1,1.9-1.4,2.8c-0.4,0.9-0.8,1.8-1,2.6c-0.3,0.9-0.5,1.6-0.7,2.4c-0.2,0.7-0.3,1.4-0.4,2.1 + c-0.1,0.3-0.1,0.6-0.2,0.9c0,0.3-0.1,0.6-0.1,0.8c0,0.5-0.1,0.9-0.1,1.3C10,39.6,10,40,10,40z" + > + <animateTransform + attributeType="xml" + attributeName="transform" + type="rotate" + from="0 40 40" + to="360 40 40" + dur="0.8s" + repeatCount="indefinite" + /> + </path> + <path + fill="#00adee" + d="M62,40.1c0,0,0,0.2-0.1,0.7c0,0.2,0,0.5-0.1,0.8c0,0.2,0,0.3,0,0.5c0,0.2-0.1,0.4-0.1,0.7 + c-0.1,0.5-0.2,1-0.3,1.6c-0.2,0.5-0.3,1.1-0.5,1.8c-0.2,0.6-0.5,1.3-0.7,1.9c-0.3,0.7-0.7,1.3-1,2.1c-0.4,0.7-0.9,1.4-1.4,2.1 + c-0.5,0.7-1.1,1.4-1.7,2c-1.2,1.3-2.7,2.5-4.4,3.6c-1.7,1-3.6,1.8-5.5,2.4c-2,0.5-4,0.7-6.2,0.7c-1.9-0.1-4.1-0.4-6-1.1 + c-1.9-0.7-3.7-1.5-5.2-2.6c-1.5-1.1-2.9-2.3-4-3.7c-0.6-0.6-1-1.4-1.5-2c-0.4-0.7-0.8-1.4-1.2-2c-0.3-0.7-0.6-1.3-0.8-2 + c-0.2-0.6-0.4-1.2-0.6-1.8c-0.1-0.6-0.3-1.1-0.4-1.6c-0.1-0.5-0.1-1-0.2-1.4c-0.1-0.9-0.1-1.5-0.1-2c0-0.5,0-0.7,0-0.7 + s0,0.2,0.1,0.7c0.1,0.5,0,1.1,0.2,2c0.1,0.4,0.2,0.9,0.3,1.4c0.1,0.5,0.3,1,0.5,1.6c0.2,0.6,0.4,1.1,0.7,1.8 + c0.3,0.6,0.6,1.2,0.9,1.9c0.4,0.6,0.8,1.3,1.2,1.9c0.5,0.6,1,1.3,1.6,1.8c1.1,1.2,2.5,2.3,4,3.2c1.5,0.9,3.2,1.6,5,2.1 + c1.8,0.5,3.6,0.6,5.6,0.6c1.8-0.1,3.7-0.4,5.4-1c1.7-0.6,3.3-1.4,4.7-2.4c1.4-1,2.6-2.1,3.6-3.3c0.5-0.6,0.9-1.2,1.3-1.8 + c0.4-0.6,0.7-1.2,1-1.8c0.3-0.6,0.6-1.2,0.8-1.8c0.2-0.6,0.4-1.1,0.5-1.7c0.1-0.5,0.2-1,0.3-1.5c0.1-0.4,0.1-0.8,0.1-1.2 + c0-0.2,0-0.4,0.1-0.5c0-0.2,0-0.4,0-0.5c0-0.3,0-0.6,0-0.8c0-0.5,0-0.7,0-0.7c0-1.1,0.9-2,2-2s2,0.9,2,2C62,40,62,40.1,62,40.1z" + > + <animateTransform + attributeType="xml" + attributeName="transform" + type="rotate" + from="0 40 40" + to="-360 40 40" + dur="0.6s" + repeatCount="indefinite" + /> + </path> +</svg> \ No newline at end of file diff --git a/ldvspec/lofardata/static/update_workflow.js b/ldvspec/lofardata/static/update_workflow.js new file mode 100644 index 0000000000000000000000000000000000000000..06861df55b0bf6b51082b777817683988049fdd7 --- /dev/null +++ b/ldvspec/lofardata/static/update_workflow.js @@ -0,0 +1,37 @@ +function fetchAvailableWorkflows(ATDBurl) { + fetch(ATDBurl + 'workflows').then((response) => response.json()).then((data) => { + $.each(data.results, function (key, value) { + let workflowDropdownOption = $('<option>', {value: value.workflow_uri}).text(value.workflow_uri); + $('#id_selected_workflow').append(workflowDropdownOption); + }); + }).then(() => { + $('#id_selected_workflow').val($("#id_selected_workflow option:first").val()); + }) +} + + +function updateWorkflows(selectedProcessingSite) { + $('#id_selected_workflow').empty() + if (selectedProcessingSite === '') return + let processingSiteUrl = processingSite.replace('replace', selectedProcessingSite); + fetch(processingSiteUrl).then( + (response) => response.json()).then( + (data) => fetchAvailableWorkflows(data.url) + ) +} + +function selectedProcessingSite(event) { + let site = event.currentTarget.value + updateWorkflows(site); +} + +function onReady() { + let processingSite = $("#id_processing_site"); //#TODO: fix proc site initial on update + let initialProcessingSite = processingSite[0].value; + if (initialProcessingSite) { + updateWorkflows(initialProcessingSite) + } + processingSite.on('change', selectedProcessingSite); +} + +$(document).ready(onReady); \ No newline at end of file diff --git a/ldvspec/lofardata/tasks.py b/ldvspec/lofardata/tasks.py index 8cc0df993a97fa4ab4255cf062275cea61e4863f..0de18fb2ca18e81bd64c921292b55a41a845b553 100644 --- a/ldvspec/lofardata/tasks.py +++ b/ldvspec/lofardata/tasks.py @@ -1,18 +1,21 @@ import re -from typing import Any, List, Optional, Dict +from typing import Any, Dict, List, Optional from urllib.parse import urlparse import requests -from requests.auth import AuthBase -from requests.exceptions import RequestException - -from ldvspec.celery import app +from celery.utils.log import get_task_logger from lofardata.models import ( SUBMISSION_STATUS, ATDBProcessingSite, DataProduct, WorkSpecification, ) +from requests.auth import AuthBase +from requests.exceptions import RequestException + +from ldvspec.celery import app + +logger = get_task_logger(__name__) class RequestNotOk(Exception): @@ -22,6 +25,8 @@ class RequestNotOk(Exception): class WorkSpecificationNoSite(Exception): pass +class InvalidPredecessor(ValueError): + pass class SessionStore: """requests.Session Singleton""" @@ -40,7 +45,7 @@ def define_work_specification(workspecification_id): specification = WorkSpecification.objects.get(pk=workspecification_id) filters = specification.filters - dataproducts = DataProduct.objects.filter(**filters).order_by('surl') + dataproducts = DataProduct.objects.filter(**filters).order_by("surl") inputs = { "surls": [ {"surl": dataproduct.surl, "size": dataproduct.filesize} @@ -66,12 +71,12 @@ def _parse_surl(surl: str) -> dict: def _prepare_request_payload( - entries: List[dict], - filter_id: str, - workflow_url: str, - purge_policy: str = "no", - predecessor: int = None, - optional_parameters: Dict[str, Any] = None + entries: List[dict], + filter_id: str, + workflow_url: str, + purge_policy: str = "no", + predecessor: int = None, + optional_parameters: Dict[str, Any] = None, ): # Parse a single surl for info: # project, sas_id & location @@ -90,10 +95,7 @@ def _prepare_request_payload( for e in entries ] if optional_parameters: - inputs = { - **optional_parameters, - 'surls': inputs - } + inputs = {**optional_parameters, "surls": inputs} data = { "project": project_id, @@ -140,7 +142,7 @@ def split_entries_to_batches(entries: List[Any], batch_size: int) -> List[List[A num_batches += 1 if n_entries % batch_size else 0 for n in range(num_batches): - batches.append(entries[n * batch_size: (n + 1) * batch_size]) + batches.append(entries[n * batch_size : (n + 1) * batch_size]) return batches @@ -154,7 +156,7 @@ def insert_task_into_atdb(workspecification_id: int): pk=workspecification_id ) inputs: Dict[str, Any] = work_spec.inputs.copy() - entries: List[dict] = inputs.pop('surls') + entries: List[dict] = inputs.pop("surls") batches = split_entries_to_batches(entries, work_spec.batch_size) @@ -163,6 +165,16 @@ def insert_task_into_atdb(workspecification_id: int): raise WorkSpecificationNoSite() url = site.url + "tasks/" + # Task ID of the predecessor + atdb_predecessor_task_id: int | None = None + if work_spec.predecessor_specification is not None: + predecessor: WorkSpecification = work_spec.predecessor_specification + if len(predecessor.related_tasks != 1): + logger.error("Workspecification {} has no valid predecessor".format(work_spec.pk)) + raise InvalidPredecessor() + # Should only be 1 entry + atdb_predecessor_task_id = predecessor.related_tasks[0] + try: for batch in batches: payload = _prepare_request_payload( @@ -171,7 +183,7 @@ def insert_task_into_atdb(workspecification_id: int): filter_id=f"ldv-spec:{work_spec.pk}", workflow_url=work_spec.selected_workflow, purge_policy=work_spec.purge_policy, - predecessor=work_spec.predecessor_task, + predecessor=atdb_predecessor_task_id, ) res = sess.post(url, json=payload, auth=TokenAuth(site.access_token)) @@ -197,10 +209,10 @@ def insert_task_into_atdb(workspecification_id: int): def update_related_tasks( - work_spec: WorkSpecification, - delete: bool, - data: Optional[dict], - on_success_status: SUBMISSION_STATUS, + work_spec: WorkSpecification, + delete: bool, + data: Optional[dict], + on_success_status: SUBMISSION_STATUS, ): sess = SessionStore.get_session() diff --git a/ldvspec/lofardata/templates/lofardata/base.html b/ldvspec/lofardata/templates/lofardata/base.html index 6b380d28cad657e57de38d7342afcc8d862de71f..abf4ce143f5e7a76e909d4a23455c487d0c7c396 100644 --- a/ldvspec/lofardata/templates/lofardata/base.html +++ b/ldvspec/lofardata/templates/lofardata/base.html @@ -13,17 +13,11 @@ <!-- loads the path to static files --> <link href='https://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" - integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" - integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" - crossorigin="anonymous"></script> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.2/css/all.css" integrity="sha384-/rXc/GQVaYpyDdyxK+ecHPVYJSN9bmVFBvjA/9eOB+pb3F2w2N6fc5qB9Ew5yIns" crossorigin="anonymous"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> - <link rel="stylesheet" type="text/css" href="{% static 'lofardata/style.css' %}"/> - <link rel="icon" href="{% static 'favicon.ico' %}"> + <link rel="stylesheet" type="text/css" href="{% static 'lofardata/styling/dias.css' %}"> {% block extra_js %}{% endblock %} @@ -31,40 +25,44 @@ </head> <body> <div class="page"> -<nav class="navbar navbar-expand-lg navbar-light bg-light"> - <div class="container-fluid"> - <ul class="nav navbar-nav"> - <!-- Header --> - <li><a class="navbar-brand" href="{% url 'index' %}"> - <img src="{% static 'lofardata/ldvspec_logo.png' %}" height="30" alt=""> - Specification Service</a> + <nav class="h-navbar navbar-custom"> + <ol class="h-navbar-list"> + <li class="h-navbar-list__item"> + <a href="{% url 'index' %}"> + <img class="h-navbar-logo logo" + src="{% static 'lofardata/styling/images/ldvspec_logo_2.png' %}" alt=""/> + </a> </li> - - <li><a class="nav-link" href="{% url 'index' %}">Home</a></li> - {% if user.is_authenticated %} - <li><a class="nav-link" href="{% url 'specification' %}">Specification</a></li> + {% if user.is_authenticated and user.is_staff %} + <li class="h-navbar-list__item"> + <a class="button text--primary" + href="{% url 'admin:index' %}"> + Admin Page + </a> + </li> {% endif %} - <li><a class="nav-link" href="{% url 'api' %}">API</a></li> - <li><a class="nav-link" href="{% url 'admin:index' %}" target="_blank">Admin Page</a></li> - + </ol> + <ul class="h-navbar-list margin-right"> {% if user.is_authenticated %} - <a class="nav-link" href="{% url 'logout' %}" target="_blank">Logout ({{ user.get_username }})</a> - {% endif %} - {% if not user.is_authenticated %} - <a class="nav-link" href="{% url 'login' %}" target="_blank">Login</a> + <li class="h-navbar-list__item"> + Logged in as:<p class="text text--semi-bold margin-left"> {{ user.get_username }}</p> + </li> + <li class="h-navbar-list__item"> + <a class="button button--secondary margin-right" href="{% url 'logout' %}">Logout</a> + </li> + {% else %} + <li class="h-navbar-list__item"> + <a class="button button--secondary margin-right" href="{% url 'login' %}">Login</a> + </li> {% endif %} </ul> - </div> + </nav> -</nav> -<div class="content-wrap"> -<!-- to add blocks of code --> -{% block myBlock %} -{% endblock %} -</div> -<footer> - <p> {{ VERSION_STRING }} </p> -</footer> + <div class="content-wrap"> + <!-- to add blocks of code --> + {% block myBlock %} + {% endblock %} + </div> </div> </body> diff --git a/ldvspec/lofardata/templates/lofardata/index.html b/ldvspec/lofardata/templates/lofardata/index.html index 18bb35f320c03058fba6f6fcf0f1cdb57434a907..5e0a99b669efc9588417fb6965bc4d661d491377 100644 --- a/ldvspec/lofardata/templates/lofardata/index.html +++ b/ldvspec/lofardata/templates/lofardata/index.html @@ -1,19 +1,150 @@ {% extends 'lofardata/base.html' %} {% load static %} {% load crispy_forms_tags %} +{% load define_action %} {% block myBlock %} - <div class="container-fluid"> - <div class="row justify-content-md-center"> - <div class="col-md-auto mt-5">Welcome to the LDV specification service</div> + {% if user.is_authenticated %} + + <div class="flex-wrapper flex-wrapper--centered flex-wrapper--row"> + <h1 class="custom-title-h1">Work Specifications</h1> + <a class="button button--secondary button--icon-button margin-left" + title="Create a new work specification" + href="{% url 'specification-create' %}"> + <span class="icon icon--plus"></span></a> </div> - {% if user.is_authenticated %} - <div class="row justify-content-md-center mt-5 mb-5"> - <a class="col-md-2 btn btn-success" href="{% url 'specification' %}">Start specifying your task</a> + + <div class="table"> + <div class="table__header"> + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell">ID + <a class="tooltip-dias tooltip-dias-right" data-tooltip="Click on the id to view/edit">m</a> + </div> + <div class="table__cell">Status + <a class="tooltip-dias tooltip-dias-bottom" data-tooltip="The status w.r.t. ATDB">m</a> + </div> + <div class="table__cell">Processing Site + <a class="tooltip-dias tooltip-dias-bottom" + data-tooltip="The ATDB site where it is processed">m</a> + </div> + <div class="table__cell">Workflow + <a class="tooltip-dias tooltip-dias-bottom" data-tooltip="The pipeline">m</a> + </div> + <div class="table__cell table__cell--medium-small-fixed">Successors</div> + <div class="table__cell table__cell--medium-small-fixed">Predecessors</div> + <div class="table__cell">Actions</div> + </div> </div> - {% endif %} - </div> + <div class="table__content table__content--scroll"> + {% for specification in object_list %} + <div class="table__row table__row--dark table__row--padding" + data-spec-id="specification.id"> + <div class="table__cell"> + <a href="{% url 'specification-detail' pk=specification.id %}" + title="View the specification details">{{ specification.id }}</a> + </div> -{% endblock %} + <div class="table__cell"> + {% if specification.get_submission_status_display == "submitted" %} + {% define "green" as badgecolor %} + {% endif %} + {% if specification.get_submission_status_display == "error" %} + {% define "red" as badgecolor %} + {% endif %} + {% if specification.get_submission_status_display == "defining" %} + {% define "secondary" as badgecolor %} + {% endif %} + {% if specification.get_submission_status_display == "undefined" or specification.get_submission_status_display == "not submitted" %} + {% define "primary" as badgecolor %} + {% endif %} + <div class="badge badge--{{ badgecolor }}">{{ specification.get_submission_status_display }}</div> + </div> + <div class="table__cell table__cell--truncate"> + <a href="{{ specification.processing_site.url }}" + title="Go to {{ specification.processing_site.url }}"> + {{ specification.processing_site.name }} + <span class="icon icon--external-link-alt margin-left"></span> + </a> + </div> + + <div class="table__cell table__cell--truncate">{{ specification.selected_workflow }}</div> + + <div class="table__cell table__cell--medium-small-fixed"> + {% if specification.successor.count %} + {% for successor in specification.successor.all %} + <a href="{% url 'specification-detail' pk=successor.pk %}" + title="View successor details">{{ successor.pk }}</a> + {% if not forloop.last %}, {% endif %} + {% endfor %} + {% else %} + <div class="text">-</div> + {% endif %} + </div> + + <div class="table__cell table__cell--medium-small-fixed"> + {% if specification.predecessor_specification %} + <a href="{% url 'specification-detail' pk=specification.predecessor_specification.pk %}"> + {{ specification.predecessor_specification.pk }} + </a> + {% else %} + <div class="text">-</div> + {% endif %} + </div> + <!-- Actions --> + <div class="table__cell"> + <div class="flex-wrapper flex-wrapper--row"> + + <a class="button--icon-button margin-left margin-right" + href="{% url 'specification-update' pk=specification.pk %}"> + <span class="icon icon--pen"></span> + </a> + + {% if specification.successor.count %} + <a class="link--disabled button--icon-button margin-right" + title="Cannot delete this work specification since it has successors. Delete them first"> + <span class="icon icon--color-inherit icon--trash-alt"></span> + </a> + {% else %} + <a class="link--red button--icon-button margin-right" + href="{% url 'specification-delete' pk=specification.pk %}"> + <span class="icon icon--color-inherit icon--trash-alt"></span> + </a> + {% endif %} + <form + method="post" + action="{% url 'workspecification-submit' pk=specification.pk %}" + > + {% csrf_token %} + + {% if specification.get_submission_status_display == "submitted" or specification.get_submission_status_display == "defining" %} + <a class="link--disabled button--icon-button" + title="Tasks already present in ATDB"> + <span class="icon icon--color-inherit icon--play"></span> + </a> + {% else %} + <button type="submit" class="button--icon-button" title="Submit to ATDB"> + <span class="icon icon--play"></span> + </button> + {% endif %} + + </form> + + </div> + </div> + </div> + {% endfor %} + </div> + </div> + {% else %} + <div class="flex-wrapper flex-wrapper--centered flex-wrapper--column"> + <h1>Welcome to the LDV Specification tool</h1> + <h2>Log in to see/add/update work specifications</h2> + </div> + {% endif %} + <!-- <script> + $(document).ready(() => setInterval(() => window.location.reload(), 50000)) + </script> --> + +{% endblock %} diff --git a/ldvspec/lofardata/templates/lofardata/specification.html b/ldvspec/lofardata/templates/lofardata/specification.html deleted file mode 100644 index 313427cdfbf4a0dbe7e0e8c27a2cdcf8f072798b..0000000000000000000000000000000000000000 --- a/ldvspec/lofardata/templates/lofardata/specification.html +++ /dev/null @@ -1,363 +0,0 @@ -{% extends 'lofardata/base.html' %} -{% load static %} -{% load crispy_forms_tags %} - -{% block myBlock %} - <div class="container-fluid details-container"> - <div class="row"> - <div class="col-12"> - <div class="card"> - <div class="card-body"> - <div class="row"> - <div class="col-3"> - <div class="btn-group"> - <button type="button" class="btn btn-primary btn-sm dropdown-toggle" - data-bs-toggle="dropdown" aria-expanded="false"> - Select Specification - </button> - <ul class="dropdown-menu"> - {{ specifications_list | safe }} - </ul> - </div> - </div> - <div class="col-3"> - <a href="{% url 'specification' %}"> - <div> - <button class="btn btn-primary btn-sm"><i class="fas fa-folder-plus"></i> New - Specification - </button> - </div> - </a> - </div> - </div> - <hr> - <div class="row mb-5"> - <div class="col-1"><h4>ID {{ specification.id }} </h4></div> - <div class="btn-group col-3"> - <button type="button" class="btn btn-info btn-sm dropdown-toggle" - data-bs-toggle="dropdown" aria-expanded="false"> - ATDB tasks - </button> - <ul class="dropdown-menu"> - {% for related_task in specification.related_tasks %} - <li> - <a class="dropdown-item" - href="{{ specification.processing_site.url }}tasks/{{ related_task }}">{{ related_task }}</a> - </li> - {% endfor %} - </ul> - </div> - {% if specification.predecessor_specification %} - <h4 class="col-4 predecessor_link"> - Predecessor ID: - - <a href="{% url 'specification-detail' specification.predecessor_specification.pk %}"> - {{ specification.predecessor_specification.pk }}</a> - - </h4> - <div class="btn-group col-3"> - <button type="button" class="btn btn-info btn-sm dropdown-toggle" - data-bs-toggle="dropdown" aria-expanded="false"> - Predecessor ATDB tasks - </button> - <ul class="dropdown-menu"> - {% for related_task in specification.predecessor_specification.related_tasks %} - <li> - <a class="dropdown-item" - href="{{ specification.predecessor_specification.processing_site.url }}tasks/{{ related_task }}">{{ related_task }}</a> - </li> - {% endfor %} - </ul> - </div> - {% endif %} - - {% if specification.successor.count %} - - <div class="btn-group col-3 "> - <button type="button" class="btn btn-info btn-sm dropdown-toggle" - data-bs-toggle="dropdown" aria-expanded="false"> - Successors - </button> - <ul class="dropdown-menu"> - {% for successor in specification.successor.all %} - <li> - <a class="dropdown-item" - href="{% url 'specification-detail' successor.pk %}">Specification {{ successor.pk }}</a> - </li> - {% endfor %} - </ul> - </div> - {% endif %} - </div> - {% if specification.pk %} - <form class="post-form" action="{% url 'specification-detail' specification.pk %}" - method="POST"> - {% else %} - <form class="post-form" action="{% url 'specification' %}" method="POST"> - {% endif %} - - - {% csrf_token %} - <div> - <div class="row"> - - <div class="col-4"> - <row> - {{ form.processing_site|as_crispy_field }} - </row> - - <row> - {{ form.batch_size|as_crispy_field }} - </row> - </div> - - <div class="col-4"> - <label class="form-label" for="id_selected_workflow">Specified workflow - (ATDB)*</label> - <select id="id_selected_workflow" class="select form-select" - name="selected_workflow"> - <option value="---">Empty</option> - </select> - <div class="row">{{ form.filters|as_crispy_field }}</div> - </div> - - <div class="col-4"> - <div class="row"><h3>Filters</h3></div> - {% for filter in filters %} - <div class="row"> - <label class="form-label" - for="id_{{ filter.field }}">{{ filter.name }}*</label> - - {% if filter.filter_type == 'Free' %} - <input class="form-control custom-filter" type="text" - id="id_{{ filter.field }}" name="{{ filter.field }}" - data-filter="{{ filter.lookup_type }}" - value="{{ filter.default }}"> - {% elif filter.filter_type == 'Dropdown' %} - <select class="form-select select custom-filter" - id="id_{{ filter.field }}" name="{{ filter.field }}" - data-filter="{{ filter.lookup_type }}"> - {% for option in filter.choices %} - {% if filter.default == option.0 %} - <option selected - value="{{ option.0 }}">{{ option.0 }}</option> - {% else %} - <option value="{{ option.0 }}">{{ option.0 }}</option> - {% endif %} - {% endfor %} - </select> - {% else %} - <div class="warning">Not supported field</div> - {% endif %} - - </div> - {% endfor %} - - </div> - </div> - - {% if specification.filters is None %} - <div class="row"><span - class="info-text text-center">Please specify one of the filters.</span></div> - {% elif specification.is_ready == False %} - <div class="row"><h4>Loading...</h4></div> - {% else %} - <div class="row"> - <div class="col"> - <label for="total_size"><h5>Total size: </h5></label> - <span id="total_size">{{ total_file_size }}</span> - </div> - <div class="col"> - <label for="n_of_files"><h5># of files: </h5></label> - <span id="n_of_files">{{ number_of_files }}</span> - </div> - - <div class="col"> - <label for="size_per_task"><h5>Size per task: </h5></label> - <span id="size_per_task">{{ average_file_size_raw }}</span> - </div> - </div> - <div> - <label for="inputs_result"><h4>Inputs:</h4></label> - {{ specification.inputs|json_script:"inputs" }} - {{ form.inputs|as_crispy_field }} - </div> - {% endif %} - <div class="row bottom-bar"> - <div class="col-2"> - <button class="btn btn-success btn-sm" type="submit" name="save" value="save"><i - class="fas fa-check"></i> Save and preview - </button> - </div> - <div class="col-2"> - <button class="btn btn-success btn-sm" type="submit" name="save" - value="save_and_add_successor"><i class="fas fa-check"></i> Save and add - successor - </button> - </div> - <div class="col-3"><h5 id="id_submission_status">Submission - status: {{ specification.get_submission_status_display }}</h5></div> - <div class="col-2"> - <button class="btn btn-success btn-sm" type="submit" name="save" - value="save_and_send_to_atdb"><i class="fas fa-check"></i> Save and send to - ATDB - </button> - </div> - - </div> - </form> - </div> - </div> - - </div> - </div> - <script> - const state = { - selected_workflow: "{{ specification.selected_workflow }}", - specification_id: "{{ specification.pk }}", - is_ready: "{{ specification.is_ready }}", - filters: "{{ specification.filters | safe }}" - }; - - function fetchAvailableWorkflows(ATDBurl) { - fetch(ATDBurl + 'workflows').then((response) => response.json()).then((data) => { - $.each(data.results, function (key, value) { - $('#id_selected_workflow').append($('<option>', {value: value.workflow_uri}).text(value.workflow_uri)); - }); - }).then(() => { - if (state.selected_workflow !== 'None') { - $('#id_selected_workflow').val(state.selected_workflow) - } - }) - } - - function format_size(num) { - const suffixes = ["", "K", "M", "G", "T", "P", "E", "Z"] - for (let i = 0; i < suffixes.length; i++) { - if (Math.abs(num) <= Math.pow(1000.0, i + 1)) { - let value = Math.abs(num) / Math.pow(1000., i) - return value.toFixed(2) + ' ' + suffixes[i] + 'B'; - } - } - return null - } - - function delay(time) { - return new Promise(resolve => setTimeout(resolve, time)); - } - - function updateWorkflows(selectedProcessingSite) { - $('#id_selected_workflow').empty() - if (selectedProcessingSite === '') return - fetch('{% url 'processingsite-detail' 'replace' %}'.replace('replace', selectedProcessingSite)).then( - (response) => response.json()).then( - (data) => fetchAvailableWorkflows(data.url) - ) - } - - function selectedProcessingSite(event) { - let selectedProcessingSite = event.currentTarget.value - updateWorkflows(selectedProcessingSite); - } - - function setValueOfFilters(item) { - const value = item.value; - const name = item.name; - const query_type = item.getAttribute('data-filter') - const join_sign = query_type === 'exact' ? '' : '_' + query_type - const filters_textbox = $('#id_filters') - const current_filters = filters_textbox.val() !== "null" ? JSON.parse(filters_textbox.val()) : {}; - if (value === '' && current_filters[name + join_sign] !== undefined) { - delete current_filters[name + join_sign] - } else { - current_filters[name + join_sign] = value - } - - filters_textbox.val(JSON.stringify(current_filters, undefined, 2)) - } - - function changeFilter(event) { - setValueOfFilters(event.currentTarget); - } - - function updateSubmissionStatus(event) { - const submission_code_to_value = {{ submission_status | safe }}; - fetch("{% url 'workspecification-detail' specification.id %}").then( - (response) => response.json()).then((data) => { - const submission_status = submission_code_to_value[data['submission_status']]; - $('#id_submission_status').text('Submission status: ' + submission_status); - }) - } - - function attachSignals() { - $("#id_processing_site").on('change', selectedProcessingSite); - - $(".custom-filter").on('input', changeFilter); - $("select.custom-filter").on('change', changeFilter); - {% if specification %} - setInterval(updateSubmissionStatus, 1000); - {% endif %} - - console.log('current filters', state.filters) - if (state.filters === "None") { - console.log('Still defining task', state); - } else if (state.is_ready === "True") { - console.log('Results are ready', state); - } else { - console.log('It should reload', state); - delay(3000).then(() => location.reload(true)); - - } - - $("#id_batch_size").on('change', updateSizePerTask) - } - - function formatJSONField(field_name) { - try { - const data = JSON.parse($(field_name).val()); - $(field_name).text(JSON.stringify(data, undefined, 2)); - } catch (error) { - - } - } - - function updateSizePerTask() { - const number_of_files = {{ number_of_files }}; - let batchSize = $('#id_batch_size').val(); - - if (batchSize > number_of_files) { - batchSize = number_of_files; - $('#id_batch_size').val(batchSize) - } else if (batchSize < 0) { - batchSize = 0; - $('#id_batch_size').val(batchSize) - } - const totalFileSize = {{ total_file_size_raw }}; - const averageFileSize = {{ average_file_size_raw }}; - if (batchSize == 0) { - $('#size_per_task').text('{{ total_file_size }}') - } else { - const sizePerTask = averageFileSize * batchSize; - $('#size_per_task').text(sizePerTask); - formatDataSizes('#size_per_task') - } - - } - - function formatDataSizes(fieldName) { - $(fieldName).text(format_size($(fieldName).text())); - } - - function onReady() { - attachSignals(); - updateWorkflows($("#id_processing_site")[0].value); - formatJSONField('#id_inputs') - formatJSONField('#id_filters') - updateSizePerTask() - } - - $(document).ready(onReady); - </script> - - -{% endblock %} \ No newline at end of file diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html b/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html new file mode 100644 index 0000000000000000000000000000000000000000..0796773718cd9188f116a2c68b91e886e2e3fc04 --- /dev/null +++ b/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html @@ -0,0 +1,135 @@ +{% extends 'lofardata/index.html' %} +{% load static %} +{% load crispy_forms_tags %} +{% load define_action %} +{% load widget_tweaks %} + +{% block myBlock %} + <div class="overlay"> + <div class="modal-dias-wrapper"> + <div class="modal-dias modal-dias--fit-content"> + <a class="icon icon--times button--close" href="{% url 'index' %}"></a> + <header class="flex-wrapper flex-wrapper--centered flex-wrapper--column"> + {% if object.pk %} + <h2 class="title text text--primary">Edit Work Specification {{ object.pk }}</h2> + <form method="post" action="{% url 'specification-update' object.pk %}"> + {% else %} + <h2 class="title text text--primary">New Work Specification </h2> + <form method="post" action="{% url 'specification-create' %}"> + {% endif %} + + {% csrf_token %} + <div class="flex-wrapper flex-wrapper--row flex-wrapper--start"> + <div class="custom-div-margin"> + <h3 class="text text--primary text--title">Selection</h3> + <div class="flex-wrapper flex-wrapper--row" id="div_id_processing_site"> + <label class="input__label">{{ form.processing_site.label }}</label> + <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down"> + {% render_field form.processing_site class="input maxwidth-input input--select margin-left margin-bottom" %} + </div> + </div> + <div class="flex-wrapper flex-wrapper--row" id="div_id_selected_workflow"> + <label class="input__label" + for="id_selected_workflow">{{ form.selected_workflow.label }}*</label> + <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down margin-left margin-bottom"> + <select class="input input--select" id="id_selected_workflow" + name="selected_workflow"> + <option disabled value="---" selected>Select a processor first</option> + </select> + </div> + </div> + + <div class="flex-wrapper flex-wrapper--row" id="div_id_predecessor"> + <label class="input__label" + for="id_predecessor">{{ form.predecessor_specification.label }}</label> + <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down margin-left margin-bottom"> + {% render_field form.predecessor_specification class="input maxwidth-input input--select" %} + </div> + </div> + + <div class="flex-wrapper flex-wrapper--row" id="div_id_batch_size"> + <label class="input__label" + for="id_batch_size">{{ form.batch_size.label_tag }}</label> + {% render_field form.batch_size class="input maxwidth-input input--select margin-left margin-bottom" type="number" %} + </div> + </div> + + <div class="custom-div-margin"> + <h3 class="text text--primary text--title">Filters*</h3> + {% for filter in filters %} + {% if filter.filter_type == 'Free' %} + <div class="flex-wrapper"> + <label class="input__label" + for="id_{{ filter.field }}">{{ filter.name }}</label> + <input class="input input--text margin-left margin-bottom" + id="id_{{ filter.field }}" name="{{ filter.field }}" + placeholder="Enter {{ filter.name }}" type="text" + data-filter="{{ filter.lookup_type }}" + value="{{ filter.default }}"> + </div> + {% elif filter.filter_type == 'Dropdown' %} + <div class="flex-wrapper flex-wrapper--row" + id="div_id_filter_{{ filter.name }}"> + <label class="input__label" + for="id_{{ filter.field }}">{{ filter.name }}</label> + <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down margin-left margin-bottom"> + <select class="input input--select" + id="id_{{ filter.field }}" + name="{{ filter.field }}" + data-filter="{{ filter.lookup_type }}"> + {% for option in filter.choices %} + {% if filter.default == option.0 %} + <option selected + value="{{ option.0 }}">{{ option.0 }}</option> + {% else %} + <option value="{{ option.0 }}">{{ option.0 }}</option> + {% endif %} + {% endfor %} + </select> + </div> + </div> + {% else %} + <div class="text text--red">Not supported field</div> + {% endif %} + {% endfor %} + </div> + </div> + + <div class="flex-wrapper flex-wrapper--centered margin-bottom margin-top"> + <button class="button button--primary margin-right" + type="submit" + name="action" + value="Submit" + title="Submit the task to inspect the result. Send it later to ATDB.">Submit + </button> + <button class="button button--primary margin-right" type="submit" + value="Successor" + name="action" + title="Submit the task and add a successor task.">Add successor + </button> + <a class="button button--red button--primary margin-left" href="{% url 'index' %}">Cancel</a> + </div> + + </form> + </header> + {% if form.errors %} + <div class="popup-bar popup-bar--red"> + <span class="icon icon--left icon--color-inherit icon--times"></span> + <div class="flex-wrapper flex-wrapper--column"> + The input is invalid: + {% for field, errors in form.errors.items %} + {% for error in errors %} + <li class="text text--red text--faded">{{ field }}: {{ error }}</li> + {% endfor %} + {% endfor %} + </div> + </div> + {% endif %} + </div> + </div> + </div> + <script type="text/javascript"> + var processingSite = "{% url 'processingsite-detail' 'replace' %}" + </script> + <script src="{% static 'update_workflow.js' %}"></script> +{% endblock %} diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/delete.html b/ldvspec/lofardata/templates/lofardata/workspecification/delete.html new file mode 100644 index 0000000000000000000000000000000000000000..5c8a28e0e9495951eb8e6df32c68446ca84162d4 --- /dev/null +++ b/ldvspec/lofardata/templates/lofardata/workspecification/delete.html @@ -0,0 +1,32 @@ +{% extends 'lofardata/index.html' %} +{% load static %} +{% load crispy_forms_tags %} +{% load define_action %} +{% load widget_tweaks %} + +{% block myBlock %} + <div class="overlay"> + <div class="modal-dias-wrapper"> + <div class="modal-dias modal-dias--fit-content"> + <a class="icon icon--times button--close" href="{% url 'index' %}"></a> + <header class="flex-wrapper flex-wrapper--centered flex-wrapper--column"> + <h2 class="title">Delete Work Specification {{ object.pk }}?</h2> + <p class="text text--semi-bold">Deleting a work specification cannot be undone. </p> + <p>If the task has been sent to ATDB, it will not be + deleted there.</p> + </header> + <div class="flex-wrapper flex-wrapper--centered margin-bottom margin-top"> + <form method="post" action="{% url 'specification-delete' object.pk %}"> + {% csrf_token %} + <button class="button button--primary button--red margin-right" type="submit" + value="Confirm"> + Delete + </button> + </form> + <a class="button button--secondary margin-left" + href="{% url 'index' %}">Cancel</a> + </div> + </div> + </div> + </div> +{% endblock %} \ No newline at end of file diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/detail.html b/ldvspec/lofardata/templates/lofardata/workspecification/detail.html new file mode 100644 index 0000000000000000000000000000000000000000..77630b328e67c3c72c5812b05a0121880dd8b89a --- /dev/null +++ b/ldvspec/lofardata/templates/lofardata/workspecification/detail.html @@ -0,0 +1,204 @@ +{% extends 'lofardata/index.html' %} +{% load static %} +{% load define_action %} + + +{% block myBlock %} + <div class="overlay"> + <div class="modal-dias-wrapper"> + <div class="modal-dias"> + <a class="icon icon--times button--close" href="{% url 'index' %}"></a> + <header class="flex-wrapper flex-wrapper--centered flex-wrapper--column"> + + <h2 class="title text text--primary margin-right flex-wrapper flex-wrapper--row"> + + <span class="margin-top">Work Specification {{ object.pk }}</span> + + <a class="button button--secondary button--icon-button margin-left margin-right" + href="{% url 'specification-update' pk=object.pk %}"> + <span class="icon icon--pen"></span> + </a> + + {% if object.successor.count %} + <a class="button button--icon-button button--primary button--disabled margin-right" + title="Cannot delete this work specification since it has successors. Delete them first"> + <span class="icon icon--trash-alt"></span> + </a> + {% else %} + <a class="button button--secondary button--red button--icon-button margin-right" + href="{% url 'specification-delete' pk=object.pk %}"> + <span class="icon icon--trash-alt"></span> + </a> + {% endif %} + + <form + method="post" + action="{% url 'workspecification-submit' pk=object.pk %}" + > + {% csrf_token %} + + {% if object.get_submission_status_display == "submitted" or object.get_submission_status_display == "defining" %} + <a + class="button button--icon-button button--primary button--disabled" + title="Tasks already present in ATDB" + href="#" + > + <span class="icon icon--play"></span> + </a> + {% else %} + <button + type="submit" + class="button button--secondary button--icon-button" + title="Submit to ATDB" + > + <span class="icon icon--play"></span> + </button> + {% endif %} + + </form> + + </h2> + <div class="table margin-bottom"> + + <div class="table__header"> + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell">Property</div> + <div class="table__cell">Value</div> + </div> + </div> + <div class="table__content table__content--scroll"> + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Processing Site</div> + <div class="table__cell">{{ object.processing_site }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Selected workflow</div> + <div class="table__cell">{{ object.selected_workflow }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Successors</div> + <div class="table__cell"> + {% if object.successor.count %} + {% for successor in object.successor.all %} + <a href="{% url 'specification-detail' pk=successor.pk %}">{{ successor.pk }}</a> + {% endfor %} + {% else %} + <div class="text">-</div> + {% endif %} + </div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Predecessor</div> + <div class="table__cell"> + {% if object.predecessor_specification %} + <a href="{% url 'specification-detail' pk=object.predecessor_specification.pk %}"> + {{ object.predecessor_specification.pk }} + </a> + {% else %} + <div class="text">-</div> + {% endif %} + </div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Created on</div> + <div class="table__cell">{{ object.created_on }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Created by</div> + <div class="table__cell">{{ object.created_by }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Submission status</div> + <div class="table__cell"> + {% if object.get_submission_status_display == "submitted" %} + {% define "green" as badgecolor %} + {% endif %} + {% if object.get_submission_status_display == "error" %} + {% define "red" as badgecolor %} + {% endif %} + {% if object.get_submission_status_display == "defining" %} + {% define "secondary" as badgecolor %} + {% endif %} + {% if object.get_submission_status_display == "undefined" or object.get_submission_status_display == "not submitted" %} + {% define "primary" as badgecolor %} + {% endif %} + <div class="badge badge--{{ badgecolor }}">{{ object.get_submission_status_display }}</div> + </div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Filters</div> + <div class="table__cell"> {{ object.filters }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Files per task</div> + <div class="table__cell">{{ object.batch_size }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Purge policy</div> + <div class="table__cell">{{ object.purge_policy }}</div> + </div> + + {% if object.is_ready or object.is_defined %} + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Total size</div> + <div class="table__cell">{{ total_input_size }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Size per task</div> + <div class="table__cell">{{ size_per_task }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Number of files</div> + <div class="table__cell">{{ number_of_files }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Async Task Result</div> + <div class="table__cell">{{ object.async_task_result }}</div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">Inputs</div> + <div class="table__cell"> + <a class="button button--icon-button custom-button-no-padding" + href="{% url 'specification-inputs' object.pk %}"> + <span class="icon icon--bars"></span> + </a> + </div> + </div> + + <div class="table__row table__row--dark table__row--padding"> + <div class="table__cell table__cell--title">ATDB Tasks</div> + <div class="table__cell"> + {% if object.related_tasks %} + <a class="button button--icon-button custom-button-no-padding" + href="{% url 'specification-tasks' object.pk %}"> + <span class="icon icon--list-ul"></span> + </a> + {% else %} + <div class="text">-</div> + {% endif %} + </div> + </div> + {% endif %} + </div> + </div> + </header> + </div> + </div> + </div> + <script> + $(document).ready(() => setTimeout(() => window.location.reload(), 5000)) + </script> +{% endblock %} diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/inputs.html b/ldvspec/lofardata/templates/lofardata/workspecification/inputs.html new file mode 100644 index 0000000000000000000000000000000000000000..a21f010806ac034b0fdeaefaeae417125aa018b7 --- /dev/null +++ b/ldvspec/lofardata/templates/lofardata/workspecification/inputs.html @@ -0,0 +1,21 @@ +{% extends 'lofardata/index.html' %} +{% load static %} +{% load pretty_json %} + +{% block myBlock %} + <div class="overlay"> + <div class="modal-dias-wrapper"> + <div class="modal-dias modal-dias--fit-content"> + <a class="icon icon--times button--close" href="{% url 'specification-detail' object.pk %}"></a> + <header class="flex-wrapper flex-wrapper--centered flex-wrapper--column"> + <h2 class="title">Input fields + <a class="tooltip-dias tooltip-dias-bottom" data-tooltip="ATDB says nom nom nom (talk to Fanna or Klaas)">m</a> + </h2> + </header> + <div> + <pre>{{ object.inputs | pretty_json }}</pre> + </div> + </div> + </div> + </div> +{% endblock %} diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/tasks.html b/ldvspec/lofardata/templates/lofardata/workspecification/tasks.html new file mode 100644 index 0000000000000000000000000000000000000000..9ae4b4468f8466c1643cc28dd392ab5b1e0f2bda --- /dev/null +++ b/ldvspec/lofardata/templates/lofardata/workspecification/tasks.html @@ -0,0 +1,30 @@ +{% extends 'lofardata/index.html' %} +{% load static %} +{% load crispy_forms_tags %} +{% load define_action %} +{% load widget_tweaks %} + +{% block myBlock %} + <div class="overlay"> + <div class="modal-dias-wrapper"> + <div class="modal-dias modal-dias--fit-content custom-atdb-task-modal"> + <a class="icon icon--times button--close" href="{% url 'specification-detail' object.pk %}"></a> + <header class="flex-wrapper flex-wrapper--centered flex-wrapper--column"> + <h2 class="title">Linked ATDB tasks + <a class="tooltip-dias tooltip-dias-bottom" data-tooltip="Click on a task to see the ATDB Task details">m</a> + </h2> + </header> + <dl class="custom-list-gap margin-bottom"> + {% for related_task in object.related_tasks %} + <dd> + <a class="button button--link" + href="{{ object.processing_site.url }}tasks/{{ related_task }}"> + {{ related_task }} + </a> + </dd> + {% endfor %} + </dl> + </div> + </div> + </div> +{% endblock %} diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/update.html b/ldvspec/lofardata/templates/lofardata/workspecification/update.html new file mode 100644 index 0000000000000000000000000000000000000000..931a139819f9d1f9607fb8a2236d1f88edb71d1b --- /dev/null +++ b/ldvspec/lofardata/templates/lofardata/workspecification/update.html @@ -0,0 +1,101 @@ +{% extends 'lofardata/index.html' %} +{% load static %} +{% load crispy_forms_tags %} +{% load define_action %} +{% load widget_tweaks %} + +{% block myBlock %} + <div class="overlay"> + <div class="modal-dias-wrapper"> + <div class="modal-dias modal-dias--fit-content"> + <a class="icon icon--times button--close" href="{% url 'index' %}"></a> + <header class="flex-wrapper flex-wrapper--centered flex-wrapper--column"> + <h2 class="title text text--primary">Edit Work Specification {{ object.pk }}</h2> + <form method="post">{% csrf_token %} + <div class="flex-wrapper flex-wrapper--row flex-wrapper--start"> + <div class=""> + <h3 class="text text--primary text--title">Selection</h3> + <div class="flex-wrapper flex-wrapper--row" id="div_id_processing_site"> + <label class="input__label">{{ form.processing_site.label_tag }}*</label> + <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down"> + {% render_field form.processing_site class="input maxwidth-input input--select" %} + </div> + </div> + <div class="flex-wrapper flex-wrapper--row" id="div_id_selected_workflow"> + <label class="input__label" + for="id_selected_workflow">{{ form.selected_workflow.label_tag }}*</label> + <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down"> + <select class="input input--select" id="id_selected_workflow" + name="selected_workflow"> + <option value="---">TODO</option> + </select> + </div> + </div> + <div class="flex-wrapper flex-wrapper--row" id="div_id_predecessor"> + <label class="input__label" + for="id_predecessor">{{ form.predecessor_task.label_tag }}</label> + <input class="input input--text" id="field-name2" placeholder="None" + type="number"> + </div> + </div> + + {% if filters is not None %} + <div class=""> + <h3 class="text text--primary text--title">Filters</h3> + {% for filter in filters %} + {% if filter.filter_type == 'Free' %} + <div class="flex-wrapper"> + <label class="input__label" + for="filter_{{ filter.name }}">{{ filter.name }}</label> + <input class="input input--text margin-left" + id="filter_{{ filter.name }}" + placeholder="Enter {{ filter.name }}" type="text" + data-filter="{{ filter.lookup_type }}" + value="{{ filter.default }}"> + </div> + {% elif filter.filter_type == 'Dropdown' %} + <div class="flex-wrapper flex-wrapper--row" + id="div_id_filter_{{ filter.name }}"> + <label class="input__label" + for="filter_{{ filter.name }}">{{ filter.name }}</label> + <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down"> + <select class="input input--select" + id="filter_{{ filter.name }}" + data-filter="{{ filter.lookup_type }}"> + {% for option in filter.choices %} + {% if filter.default == option.0 %} + <option selected + value="{{ option.0 }}">{{ option.0 }}</option> + {% else %} + <option value="{{ option.0 }}">{{ option.0 }}</option> + {% endif %} + {% endfor %} + </select> + </div> + </div> + {% else %} + <div class="text text--red">Not supported field</div> + {% endif %} + {% endfor %} + </div> + {% endif %} + + + </div> + <div class="flex-wrapper flex-wrapper--centered margin-bottom margin-top"> + <button class="button button--primary margin-right" type="submit" value="Submit">Submit + </button> + <a class="button button--primary margin-left" href="{% url 'index' %}">Cancel</a> + </div> + + </form> + </header> + </div> + </div> + </div> + <script type="text/javascript"> + var processingSite = "{% url 'processingsite-detail' 'replace' %}" + </script> + <script src="{% static 'update_workflow.js' %}"></script> + +{% endblock %} \ No newline at end of file diff --git a/ldvspec/lofardata/templates/registration/login.html b/ldvspec/lofardata/templates/registration/login.html index ad2d056527ccb04598ef34f2d303da4ccb1161f7..823908ab48cefe13049cd1bd6be3394255b3607a 100644 --- a/ldvspec/lofardata/templates/registration/login.html +++ b/ldvspec/lofardata/templates/registration/login.html @@ -4,33 +4,47 @@ {% block myBlock %} -{% if form.errors %} -<p>Your username and password didn't match. Please try again.</p> -{% endif %} - -{% if next %} - {% if user.is_authenticated %} - <p>Your account doesn't have access to this page. To proceed, - please login with an account that has access.</p> - {% else %} - <p>Please login to see this page.</p> + {% if form.errors %} + <div class="popup-bar popup-bar--red"><span class="icon icon--left icon--color-inherit icon--times"></span> + Your username and password didn't match. Please try again. + </div> {% endif %} -{% endif %} - -<form class="form-signin" action="{% url 'login' %}" method="post" id="login-form"> - {% csrf_token %} - <h2 class="form-signin-heading">{{ message }}</h2> - <label for="id_username" class="sr-only">Email address</label> - <input type="text" name="username" id="id_username" class="form-control" placeholder="User Name" required autofocus> - <label for="id_password" class="sr-only">Password</label> - <input type="password" name="password" id="id_password" class="form-control" placeholder="Password" required> - <div class="checkbox"> - <label> - <input type="checkbox" value="remember-me"> Remember me - </label> + + {% if next %} + {% if user.is_authenticated %} + <p>Your account doesn't have access to this page. To proceed, + please login with an account that has access.</p> + {% else %} + <p>Please login to see this page.</p> + {% endif %} + {% endif %} + + <div class="flex-wrapper flex-wrapper--centered"> + <div> + <div class="login-form"> + <form method="post" action="{% url 'login' %}" id="login-form"> + {% csrf_token %} + <h2 class="form-signin-heading">{{ message }}</h2> + {% if redirect_field_value %} + <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/> + {% endif %} + <div> + <label for="id_username" class="input__label">Username</label> + <input id="id_username" class="input maxwidth-input" name="username" type="text" required> + </div> + + <div> + <label for="id_password" class="input__label">Password</label> + <input id="id_password" class="input maxwidth-input" name="password" type="password" required> + </div> + + <div class="flex-wrapper flex-wrapper--end"> + <button type="submit" class="button button--primary margin-right">Sign in</button> + </div> + </form> + </div> + </div> </div> - <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> -</form> {% endblock %} \ No newline at end of file diff --git a/ldvspec/lofardata/templatetags/__init__.py b/ldvspec/lofardata/templatetags/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ldvspec/lofardata/templatetags/define_action.py b/ldvspec/lofardata/templatetags/define_action.py new file mode 100644 index 0000000000000000000000000000000000000000..fa72d7923d8e3e54df0b4c1259619dc42f40481d --- /dev/null +++ b/ldvspec/lofardata/templatetags/define_action.py @@ -0,0 +1,8 @@ +from django import template + +register = template.Library() + + +@register.simple_tag +def define(val=None): + return val diff --git a/ldvspec/lofardata/templatetags/pretty_json.py b/ldvspec/lofardata/templatetags/pretty_json.py new file mode 100644 index 0000000000000000000000000000000000000000..17fa12315503374df97a68c86aaa2acf18b63077 --- /dev/null +++ b/ldvspec/lofardata/templatetags/pretty_json.py @@ -0,0 +1,10 @@ +import json + +from django import template + +register = template.Library() + + +@register.filter +def pretty_json(value): + return json.dumps(value, indent=2) \ No newline at end of file diff --git a/ldvspec/lofardata/tests/test_atdb_insert.py b/ldvspec/lofardata/tests/test_atdb_insert.py index 1552ffa00255bc6c15aac26c959cfb1ebda9070b..cf78204192637be0a2c731dcfb10f9e6811c40b0 100644 --- a/ldvspec/lofardata/tests/test_atdb_insert.py +++ b/ldvspec/lofardata/tests/test_atdb_insert.py @@ -49,9 +49,10 @@ class TestATDBInsertRequest(rtest.APITestCase): mocked_delay.assert_called_once_with("1") + # TODO: make a switch (now it always redirects to the front-end) self.assertEqual( res.status_code, - status.HTTP_202_ACCEPTED, + status.HTTP_302_FOUND, "Submitting job failed:\n" + str(res.content), ) diff --git a/ldvspec/lofardata/tests/test_util_funcs.py b/ldvspec/lofardata/tests/test_util_funcs.py index 59bd6363f82e8900cffd34a8f415f3a9ac2e06bc..ec2b6e2664f9a1eab850e8cebd64c13c5f39fee0 100644 --- a/ldvspec/lofardata/tests/test_util_funcs.py +++ b/ldvspec/lofardata/tests/test_util_funcs.py @@ -35,8 +35,9 @@ class ComputeInputSizes(unittest.TestCase): 'nested_files': [{'item1': {'class': 'File', 'size': 1}}, {'class': 'File', 'size': 1}], 'not_a_file': 'bla' } - result, number_of_files = compute_size_of_inputs(test_data) + result, number_of_files, average_file_size = compute_size_of_inputs(test_data) self.assertEqual(5, result) self.assertEqual(5, number_of_files) + self.assertEqual(1.0, average_file_size) diff --git a/ldvspec/lofardata/urls.py b/ldvspec/lofardata/urls.py index c3d0b652f791390acb058086668d62ad5a90e8c9..9e9a0f9ba460620f4892c09abdf6f5143fe00b00 100644 --- a/ldvspec/lofardata/urls.py +++ b/ldvspec/lofardata/urls.py @@ -7,6 +7,8 @@ from . import views router = DefaultRouter() router.register(r'workspecification', views.WorkSpecificationViewset, basename="workspecification") router.register(r'processing_site', views.ATDBProcessingSiteView, basename='processingsite') + + urlpatterns = [ # Perhaps both accounts and login could be moved to the ldv-spec main urls file? # authentication @@ -29,10 +31,14 @@ urlpatterns = [ ), name='openapi-schema'), path('api/v1/', include(router.urls)), # GUI - path('', views.index, name='index'), + path('', views.Specifications.as_view(), name='index'), path('api/', views.api, name='api'), - path('specification/', views.specification_view, name='specification'), - path('specification/<int:pk>/', views.specification_view, name='specification-detail'), + path('specification/<int:pk>/', views.WorkSpecificationDetailView.as_view(), name='specification-detail'), + path('specification/add/', views.WorkSpecificationCreateUpdateView.as_view(), name='specification-create'), + path('specification/update/<int:pk>/', views.WorkSpecificationCreateUpdateView.as_view(), name='specification-update'), + path('specification/delete/<int:pk>/', views.WorkSpecificationDeleteView.as_view(), name='specification-delete'), + path('specification/inputs/<int:pk>/', views.WorkSpecificationInputsView.as_view(), name='specification-inputs'), + path('specification/tasks/<int:pk>/', views.WorkSpecificationATDBTasksView.as_view(), name='specification-tasks'), # Workaround for injecting the urls from the ModelViewSet, which requires a "Router" diff --git a/ldvspec/lofardata/views.py b/ldvspec/lofardata/views.py index 939f98a7c0d9deb3e147c910bb936d31b522321a..eb7f5af1745721adb92eb12bd450ef9247e50615 100644 --- a/ldvspec/lofardata/views.py +++ b/ldvspec/lofardata/views.py @@ -1,40 +1,71 @@ -import humanize +import time +from typing import Tuple + from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist -from django.shortcuts import redirect -from django.shortcuts import render +from django.http import HttpResponseRedirect +from django.shortcuts import redirect, render from django.urls import reverse +from django.views.generic import CreateView, DeleteView, DetailView, UpdateView +from django.views.generic.list import ListView from django_filters import rest_framework as filters from rest_framework import generics, status, viewsets from rest_framework.decorators import action from rest_framework.response import Response +from rest_framework.reverse import reverse_lazy from rest_framework.schemas.openapi import AutoSchema from .forms import WorkSpecificationForm -from .models import DataProduct, DataProductFilter, DataLocation, WorkSpecification, ATDBProcessingSite,\ - DataFilterType, SUBMISSION_STATUS -from .serializers import DataProductSerializer, \ - DataProductFlatSerializer, DataLocationSerializer, \ - WorkSpecificationSerializer, ATDBProcessingSiteSerializer +from .models import ( + ATDBProcessingSite, + DataFilterType, + DataLocation, + DataProduct, + DataProductFilter, + WorkSpecification, +) +from .serializers import ( + ATDBProcessingSiteSerializer, + DataLocationSerializer, + DataProductFlatSerializer, + DataProductSerializer, + WorkSpecificationSerializer, +) from .tasks import insert_task_into_atdb -def compute_size_of_inputs(inputs: dict) -> (int, int): +def compute_size_of_inputs(inputs: dict) -> Tuple[int, int, int]: total_size = 0 number_of_files = 0 - if isinstance(inputs, dict) and 'size' in inputs: - total_size = inputs['size'] + if isinstance(inputs, dict) and "size" in inputs: + total_size = inputs["size"] number_of_files = 1 - elif isinstance(inputs, dict) or isinstance(inputs, list) or isinstance(inputs, tuple): + elif ( + isinstance(inputs, dict) + or isinstance(inputs, list) + or isinstance(inputs, tuple) + ): values = inputs if isinstance(inputs, dict): values = inputs.values() for value in values: - item_total, item_count = compute_size_of_inputs(value) + item_total, item_count, _ = compute_size_of_inputs(value) total_size += item_total number_of_files += item_count - return total_size, number_of_files + + average_file_size = total_size / number_of_files if number_of_files else 0 + return total_size, number_of_files, average_file_size + + +def format_size(num, suffix="B"): + if num == 0: + return "-" + for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]: + if abs(num) < 1024.0: + return f"{num:3.1f}{unit}{suffix}" + num /= 1024.0 + return f"{num:.1f}Yi{suffix}" class DynamicFilterSet(filters.FilterSet): @@ -47,7 +78,7 @@ class DynamicFilterSet(filters.FilterSet): def _load_filters(self): if self.Meta.filter_class is None: - raise Exception('Define filter_class meta attribute') + raise Exception("Define filter_class meta attribute") for item in self.Meta.filter_class.objects.all(): field_obj = self.Meta.model._meta.get_field(item.field) filter_class, *_ = self.filter_for_lookup(field_obj, item.lookup_type) @@ -67,95 +98,132 @@ class DataProductFilterSet(DynamicFilterSet): # ---------- GUI Views ----------- -def index(request): +def api(request): atdb_hosts = ATDBProcessingSite.objects.values("name", "url") - return render(request, "lofardata/index.html", {"atdb_hosts": atdb_hosts}) + return render(request, "lofardata/api.html", {"atdb_hosts": atdb_hosts}) -def api(request): - atdb_hosts = ATDBProcessingSite.objects.values('name', 'url') - return render(request, "lofardata/api.html", {'atdb_hosts': atdb_hosts}) +def preprocess_filters_specification_view(specification): + dataproduct_filters = DataProductFilter.objects.all() + for dataproduct_filter in dataproduct_filters: + if ( + specification is not None + and specification.filters + and dataproduct_filter.field in specification.filters + ): + dataproduct_filter.default = specification.filters[dataproduct_filter.field] + else: + dataproduct_filter.default = "" + + if dataproduct_filter.filter_type == DataFilterType.DROPDOWN: + dataproduct_filter.choices = DataProduct.objects.distinct( + dataproduct_filter.field + ).values_list(dataproduct_filter.field) + return dataproduct_filters -def construct_specifications_list(): - results = '' - for specification in WorkSpecification.objects.all(): - url = reverse('specification-detail', args=(str(specification.pk),)) - line = f'<li><a class="dropdown-item" href="{url}">{str(specification)}</a></li>' - results += line - return results +class Specifications(ListView): + serializer_class = WorkSpecificationSerializer + template_name = "lofardata/index.html" + model = WorkSpecification + ordering = ["-created_on"] + + def get_queryset(self): + queryset = WorkSpecification.objects.all() + current_user: User = self.request.user + if current_user.is_staff or current_user.is_superuser: + return queryset.order_by("-created_on") + return queryset.filter(created_by=current_user.id).order_by("-created_on") -def handle_specification_view_post(request, specification): - form = WorkSpecificationForm(request.POST, instance=specification) - if form.is_valid(): - object_to_save = request.POST['save'] +class WorkSpecificationCreateUpdateView(UpdateView): + template_name = "lofardata/workspecification/create_update.html" + model = WorkSpecification + form_class = WorkSpecificationForm - if object_to_save == 'save': + def get_object(self, queryset=None): + if self.kwargs.__len__() == 0 or self.kwargs["pk"] is None: + specification = WorkSpecification() + else: + specification = WorkSpecification.objects.get(pk=self.kwargs["pk"]) + return specification + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + try: + specification = WorkSpecification.objects.get(pk=context["object"].pk) + except ObjectDoesNotExist: + specification = None + context["filters"] = preprocess_filters_specification_view(specification) + return context + + def create_successor(self, specification): + successor = WorkSpecification() + successor.predecessor_specification = specification + successor.processing_site = specification.processing_site + successor.save() + return self.get_success_url(pk=successor.pk) + + def form_valid(self, form): + action_ = form.data["action"] + specification = form.instance + if action_ == "Submit": specification.async_task_result = None specification.is_ready = False + if action_ == "Send": + insert_task_into_atdb.delay(specification.pk) + if action_ == "Successor": specification.save() - return redirect('specification-detail', specification.pk) - elif object_to_save == 'save_and_send_to_atdb': - specification.save() - res = insert_task_into_atdb.delay(specification.pk) - return redirect('specification-detail', specification.pk) - elif object_to_save == 'save_and_add_successor': - specification.save() - successor = WorkSpecification() successor.predecessor_specification = specification successor.processing_site = specification.processing_site - successor.save() - return redirect('specification-detail', successor.pk) + successor.selected_workflow = specification.selected_workflow + return HttpResponseRedirect(self.create_successor(specification)) + return super().form_valid(form) -def preprocess_filters_specification_view(specification): - dataproduct_filters = DataProductFilter.objects.all() - for dataproduct_filter in dataproduct_filters: - if specification.filters and dataproduct_filter.field in specification.filters: - dataproduct_filter.default = specification.filters[dataproduct_filter.field] + def get_success_url(self, **kwargs): + if kwargs.__len__() == 0 or kwargs["pk"] is None: + return reverse_lazy("index") else: - dataproduct_filter.default = '' + return reverse_lazy("specification-update", kwargs={"pk": kwargs["pk"]}) - if dataproduct_filter.filter_type == DataFilterType.DROPDOWN: - dataproduct_filter.choices = DataProduct.objects.distinct(dataproduct_filter.field).values_list( - dataproduct_filter.field) - return dataproduct_filters + +class WorkSpecificationDetailView(DetailView): + template_name = "lofardata/workspecification/detail.html" + model = WorkSpecification + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + specification = WorkSpecification.objects.get(pk=context["object"].pk) + context["filters"] = preprocess_filters_specification_view(specification) + total_input_size, number_of_files, average_file_size = compute_size_of_inputs( + specification.inputs + ) + context["number_of_files"] = number_of_files + context["total_input_size"] = format_size(total_input_size) + context["size_per_task"] = format_size( + average_file_size * specification.batch_size + if specification.batch_size > 0 + else total_input_size + ) + return context + + +class WorkSpecificationDeleteView(DeleteView): + template_name = "lofardata/workspecification/delete.html" + model = WorkSpecification + success_url = reverse_lazy("index") -def specification_view(request, pk=None): - try: - # retrieve existing specification - specification = WorkSpecification.objects.get(pk=pk) - except ObjectDoesNotExist: - # start new specification - specification = WorkSpecification() - - specifications_list = construct_specifications_list() - # a POST means that the form is filled in and should be stored in the - form = WorkSpecificationForm(instance=specification) - if request.method == "POST": - return handle_specification_view_post(request, specification) - - dataproduct_filters = preprocess_filters_specification_view(specification) - - total_input_size, number_of_files = compute_size_of_inputs(specification.inputs) - - average_file_size = total_input_size / number_of_files if number_of_files else 0 - submission_status_dict = {item[0]: item[1] for item in SUBMISSION_STATUS.choices} - return render(request, "lofardata/specification.html", { - 'form': form, - 'specification': specification, - 'total_file_size': humanize.naturalsize(total_input_size), - 'total_file_size_raw': total_input_size, - 'number_of_files': number_of_files, - 'average_file_size': humanize.naturalsize(average_file_size), - 'average_file_size_raw': average_file_size, - 'specifications_list': specifications_list, - 'submission_status': submission_status_dict, - 'filters': dataproduct_filters - }) +class WorkSpecificationInputsView(DetailView): + template_name = "lofardata/workspecification/inputs.html" + model = WorkSpecification + + +class WorkSpecificationATDBTasksView(DetailView): + template_name = "lofardata/workspecification/tasks.html" + model = WorkSpecification # ---------- REST API views ---------- @@ -174,7 +242,7 @@ class ATDBProcessingSiteView(viewsets.ReadOnlyModelViewSet): model = ATDBProcessingSite serializer_class = ATDBProcessingSiteSerializer - queryset = ATDBProcessingSite.objects.all().order_by('pk') + queryset = ATDBProcessingSite.objects.all().order_by("pk") class DataProductDetailsView(generics.RetrieveUpdateDestroyAPIView): @@ -224,6 +292,8 @@ class WorkSpecificationViewset(viewsets.ModelViewSet): @action(detail=True, methods=["POST"]) def submit(self, request, pk=None) -> Response: # TODO: check that there are some matches in the request? - # TODO: how to specify the filter? - res = insert_task_into_atdb.delay(pk) - return Response({"detail": "accepted"}, status=status.HTTP_202_ACCEPTED) + insert_task_into_atdb.delay(pk) + + time.sleep(1) # allow for some time to pass + + return redirect("specification-detail", pk=pk) diff --git a/ldvspec/requirements/base.txt b/ldvspec/requirements/base.txt index 831a959ebebdf244153aa77b4fa1f380e410a2a2..5ce7dcebce6248b62802046b3cff71477627943d 100644 --- a/ldvspec/requirements/base.txt +++ b/ldvspec/requirements/base.txt @@ -15,4 +15,5 @@ sshtunnel==0.4.0 django-uws==0.2.dev355575 django-crispy-forms==1.14.0 crispy-bootstrap5==0.6 -humanize==4.4.0 \ No newline at end of file +humanize==4.4.0 +django-widget-tweaks \ No newline at end of file