Compare commits
2 Commits
fix/issue2
...
feature/te
| Author | SHA1 | Date | |
|---|---|---|---|
| 62e890245e | |||
| 138846d84d |
@ -16,5 +16,3 @@ POSTGRES_PORT=
|
||||
# MAIL
|
||||
EMAIL_HOST_USER=
|
||||
EMAIL_HOST_PASSWORD=
|
||||
# MATOMO
|
||||
MATOMO_SITE_ID
|
||||
|
||||
@ -1,116 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
env:
|
||||
POSTGRES_USER: ${{ vars.POSTGRES_USER }}
|
||||
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
|
||||
POSTGRES_DB: ${{ vars.POSTGRES_DB }}
|
||||
ports:
|
||||
- ${{ vars.POSTGRES_PORT}}:5432
|
||||
options: >-
|
||||
--health-cmd="pg_isready -U postgres"
|
||||
--health-interval=10s
|
||||
--health-timeout=5s
|
||||
--health-retries=5
|
||||
|
||||
#redis:
|
||||
# image: redis:7
|
||||
# ports:
|
||||
# - 6379:6379
|
||||
# options: >-
|
||||
# --health-cmd "redis-cli ping"
|
||||
# --health-interval=10s
|
||||
# --health-timeout=5s
|
||||
# --health-retries=5
|
||||
|
||||
env:
|
||||
RUNNER_TOOL_CACHE: /toolcache
|
||||
EP_DATA_DIR: /opt/enviPy/
|
||||
ALLOWED_HOSTS: 127.0.0.1,localhost
|
||||
DEBUG: True
|
||||
LOG_LEVEL: DEBUG
|
||||
MODEL_BUILDING_ENABLED: True
|
||||
APPLICABILITY_DOMAIN_ENABLED: True
|
||||
ENVIFORMER_PRESENT: True
|
||||
ENVIFORMER_DEVICE: cpu
|
||||
FLAG_CELERY_PRESENT: False
|
||||
PLUGINS_ENABLED: True
|
||||
SERVER_URL: http://localhost:8000
|
||||
ADMIN_APPROVAL_REQUIRED: True
|
||||
REGISTRATION_MANDATORY: True
|
||||
LOG_DIR: ''
|
||||
# DB
|
||||
POSTGRES_SERVICE_NAME: postgres
|
||||
POSTGRES_DB: ${{ vars.POSTGRES_DB }}
|
||||
POSTGRES_USER: ${{ vars.POSTGRES_USER }}
|
||||
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
|
||||
POSTGRES_PORT: 5432
|
||||
# SENTRY
|
||||
SENTRY_ENABLED: False
|
||||
# MS ENTRA
|
||||
MS_ENTRA_ENABLED: False
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install system tools via apt
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y postgresql-client redis-tools openjdk-11-jre-headless
|
||||
|
||||
- name: Setup ssh
|
||||
run: |
|
||||
echo "${{ secrets.ENVIPY_CI_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
ssh-keyscan git.envipath.com >> ~/.ssh/known_hosts
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add ~/.ssh/id_ed25519
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
- name: Setup venv
|
||||
run: |
|
||||
uv sync --locked --all-extras --dev
|
||||
|
||||
- name: Wait for services
|
||||
run: |
|
||||
until pg_isready -h postgres -U postgres; do sleep 2; done
|
||||
# until redis-cli -h redis ping; do sleep 2; done
|
||||
|
||||
- name: Run Django Migrations
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
python manage.py migrate --noinput
|
||||
|
||||
- name: Run Django tests
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
python manage.py test tests --exclude-tag slow
|
||||
5
.gitignore
vendored
@ -10,8 +10,3 @@ scratches/
|
||||
data/
|
||||
|
||||
.DS_Store
|
||||
|
||||
node_modules/
|
||||
static/css/output.css
|
||||
|
||||
*.code-workspace
|
||||
|
||||
@ -8,7 +8,6 @@ repos:
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
exclude: ^static/images/
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.13.3
|
||||
@ -21,15 +20,6 @@ repos:
|
||||
- id: ruff-format
|
||||
types_or: [python, pyi]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: prettier-jinja-templates
|
||||
name: Format Jinja templates with Prettier
|
||||
entry: pnpm exec prettier --plugin=prettier-plugin-jinja-template --parser=jinja-template --write
|
||||
language: system
|
||||
types: [file]
|
||||
files: ^templates/.*\.html$
|
||||
|
||||
# - repo: local
|
||||
# hooks:
|
||||
# - id: django-check
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-jinja-template", "prettier-plugin-tailwindcss"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "templates/**/*.html",
|
||||
"options": {
|
||||
"parser": "jinja-template"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
22
README.md
@ -7,13 +7,11 @@ These instructions will guide you through setting up the project for local devel
|
||||
### Prerequisites
|
||||
|
||||
- Python 3.11 or later
|
||||
- [uv](https://github.com/astral-sh/uv) - Python package manager
|
||||
- **Docker and Docker Compose** - Required for running PostgreSQL database
|
||||
- [uv](https://github.com/astral-sh/uv) - A fast Python package installer and resolver.
|
||||
- **Docker and Docker Compose** - Required for running the PostgreSQL database.
|
||||
- Git
|
||||
- Make
|
||||
|
||||
> **Note:** This application requires PostgreSQL (uses `ArrayField`). Docker is the easiest way to run PostgreSQL locally.
|
||||
|
||||
> **Note:** This application requires PostgreSQL, which uses `ArrayField`. Docker is the recommended way to run PostgreSQL locally.
|
||||
|
||||
### 1. Install Dependencies
|
||||
|
||||
@ -25,12 +23,7 @@ Then, sync the project dependencies. This will create a virtual environment in `
|
||||
uv sync --dev
|
||||
```
|
||||
|
||||
Note on RDkit installation: if you have rdkit installed on your system globally with a different version of python, the installation will try to link against that and subsequent calls fail. Only option remove global rdkit and rerun sync.
|
||||
|
||||
---
|
||||
|
||||
The frontend requires `pnpm` to correctly display in development.
|
||||
[Install it here](https://pnpm.io/installation).
|
||||
> **Note on RDkit:** If you have a different version of rdkit installed globally, the dependency installation may fail. If this happens, please uninstall the global version and run `uv sync` again.
|
||||
|
||||
### 2. Set Up Environment File
|
||||
|
||||
@ -51,7 +44,6 @@ uv run poe setup
|
||||
```
|
||||
|
||||
This single command will:
|
||||
|
||||
1. Start the PostgreSQL database using Docker Compose.
|
||||
2. Run database migrations.
|
||||
3. Bootstrap initial data (anonymous user, default packages, models).
|
||||
@ -62,12 +54,9 @@ After setup, start the development server:
|
||||
uv run poe dev
|
||||
```
|
||||
|
||||
This will start the css-watcher as well as the django-development server,
|
||||
The application will be available at `http://localhost:8000`.
|
||||
|
||||
**Note:** The development server automatically starts a CSS watcher (`pnpm run dev`) alongside the Django server to rebuild CSS files when changes are detected. This ensures your styles are always up-to-date during development.
|
||||
|
||||
#### Other useful Poe commands
|
||||
#### Other useful Poe commands:
|
||||
|
||||
You can list all available commands by running `uv run poe --help`.
|
||||
|
||||
@ -77,7 +66,6 @@ uv run poe db-down # Stop PostgreSQL
|
||||
uv run poe migrate # Run migrations only
|
||||
uv run poe bootstrap # Bootstrap data only
|
||||
uv run poe shell # Open the Django shell
|
||||
uv run poe build # Build frontend assets and collect static files
|
||||
uv run poe clean # Remove database volumes (WARNING: destroys all data)
|
||||
```
|
||||
|
||||
|
||||
@ -52,6 +52,28 @@ INSTALLED_APPS = [
|
||||
"migration",
|
||||
]
|
||||
|
||||
|
||||
# Add the TENANT providing implementations for
|
||||
# Required
|
||||
# - Package
|
||||
# - Compound (TODO)
|
||||
# - CompoundStructure (TODO)
|
||||
# Optional
|
||||
# - PackageManager (TODO)
|
||||
# - GroupManager (TODO)
|
||||
# - SettingManager (TODO)
|
||||
TENANT = os.environ.get("TENANT", "public")
|
||||
INSTALLED_APPS.append(TENANT)
|
||||
PACKAGE_IMPLEMENTATION = f"{TENANT}.Package"
|
||||
PACKAGE_MODULE_PATH = f"{TENANT}.models.Package"
|
||||
|
||||
|
||||
def GET_PACKAGE_MODEL():
|
||||
from django.apps import apps
|
||||
|
||||
return apps.get_model(TENANT, "Package")
|
||||
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
]
|
||||
@ -87,14 +109,11 @@ TEMPLATES = [
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"epdb.context_processors.package_context",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
ALLOWED_HTML_TAGS = {"b", "i", "u", "br", "em", "mark", "p", "s", "strong"}
|
||||
|
||||
WSGI_APPLICATION = "envipath.wsgi.application"
|
||||
|
||||
# Database
|
||||
@ -246,7 +265,6 @@ LOGGING = {
|
||||
ENVIFORMER_PRESENT = os.environ.get("ENVIFORMER_PRESENT", "False") == "True"
|
||||
ENVIFORMER_DEVICE = os.environ.get("ENVIFORMER_DEVICE", "cpu")
|
||||
|
||||
|
||||
# If celery is not present set always eager to true which will cause delayed tasks to block until finished
|
||||
FLAG_CELERY_PRESENT = os.environ.get("FLAG_CELERY_PRESENT", "False") == "True"
|
||||
if not FLAG_CELERY_PRESENT:
|
||||
@ -347,14 +365,6 @@ LOGIN_EXEMPT_URLS = [
|
||||
"/password_reset/",
|
||||
"/reset/",
|
||||
"/microsoft/",
|
||||
"/terms",
|
||||
"/privacy",
|
||||
"/cookie-policy",
|
||||
"/about",
|
||||
"/contact",
|
||||
"/jobs",
|
||||
"/cite",
|
||||
"/legal",
|
||||
]
|
||||
|
||||
# MS AD/Entra
|
||||
@ -369,6 +379,3 @@ if MS_ENTRA_ENABLED:
|
||||
MS_ENTRA_AUTHORITY = f"https://login.microsoftonline.com/{MS_ENTRA_TENANT_ID}"
|
||||
MS_ENTRA_REDIRECT_URI = os.environ["MS_REDIRECT_URI"]
|
||||
MS_ENTRA_SCOPES = os.environ.get("MS_SCOPES", "").split(",")
|
||||
|
||||
# Site ID 10 -> beta.envipath.org
|
||||
MATOMO_SITE_ID = os.environ.get("MATOMO_SITE_ID", "10")
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
from django.contrib import admin
|
||||
from django.conf import settings as s
|
||||
|
||||
from .models import (
|
||||
User,
|
||||
UserPackagePermission,
|
||||
Group,
|
||||
GroupPackagePermission,
|
||||
Package,
|
||||
MLRelativeReasoning,
|
||||
EnviFormer,
|
||||
Compound,
|
||||
@ -21,10 +21,12 @@ from .models import (
|
||||
ExternalDatabase,
|
||||
ExternalIdentifier,
|
||||
JobLog,
|
||||
License,
|
||||
)
|
||||
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
|
||||
class UserAdmin(admin.ModelAdmin):
|
||||
list_display = ["username", "email", "is_active"]
|
||||
|
||||
@ -63,10 +65,6 @@ class EnviFormerAdmin(EPAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class LicenseAdmin(admin.ModelAdmin):
|
||||
list_display = ["cc_string", "link", "image_link"]
|
||||
|
||||
|
||||
class CompoundAdmin(EPAdmin):
|
||||
pass
|
||||
|
||||
@ -123,7 +121,6 @@ admin.site.register(JobLog, JobLogAdmin)
|
||||
admin.site.register(Package, PackageAdmin)
|
||||
admin.site.register(MLRelativeReasoning, MLRelativeReasoningAdmin)
|
||||
admin.site.register(EnviFormer, EnviFormerAdmin)
|
||||
admin.site.register(License, LicenseAdmin)
|
||||
admin.site.register(Compound, CompoundAdmin)
|
||||
admin.site.register(CompoundStructure, CompoundStructureAdmin)
|
||||
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
"""
|
||||
Context processors for enviPy application.
|
||||
|
||||
Context processors automatically make variables available to all templates.
|
||||
"""
|
||||
|
||||
from .logic import PackageManager
|
||||
from .models import Package
|
||||
|
||||
|
||||
def package_context(request):
|
||||
"""
|
||||
Provides package data for the search modal which is included globally
|
||||
in framework_modern.html.
|
||||
|
||||
Returns:
|
||||
dict: Context dictionary with reviewed and unreviewed packages
|
||||
"""
|
||||
current_user = request.user
|
||||
|
||||
reviewed_package_qs = PackageManager.get_reviewed_packages()
|
||||
|
||||
unreviewed_package_qs = Package.objects.none()
|
||||
|
||||
# Only get user-specific packages if user is authenticated
|
||||
if current_user.is_authenticated:
|
||||
unreviewed_package_qs = PackageManager.get_all_readable_packages(current_user)
|
||||
|
||||
return {
|
||||
"reviewed_packages": reviewed_package_qs,
|
||||
"unreviewed_packages": unreviewed_package_qs,
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
from typing import List, Dict, Optional, Any
|
||||
|
||||
from django.conf import settings as s
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect
|
||||
@ -10,7 +11,6 @@ from .logic import PackageManager, UserManager, SettingManager
|
||||
from .models import (
|
||||
Compound,
|
||||
CompoundStructure,
|
||||
Package,
|
||||
User,
|
||||
UserPackagePermission,
|
||||
Rule,
|
||||
@ -23,6 +23,9 @@ from .models import (
|
||||
)
|
||||
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
|
||||
def _anonymous_or_real(request):
|
||||
if request.user.is_authenticated and not request.user.is_anonymous:
|
||||
return request.user
|
||||
|
||||
@ -4,7 +4,6 @@ import json
|
||||
from typing import Union, List, Optional, Set, Dict, Any
|
||||
from uuid import UUID
|
||||
|
||||
import nh3
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import transaction
|
||||
from django.conf import settings as s
|
||||
@ -12,7 +11,6 @@ from pydantic import ValidationError
|
||||
|
||||
from epdb.models import (
|
||||
User,
|
||||
Package,
|
||||
UserPackagePermission,
|
||||
GroupPackagePermission,
|
||||
Permission,
|
||||
@ -34,6 +32,8 @@ from utilities.misc import PackageImporter, PackageExporter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
|
||||
class EPDBURLParser:
|
||||
UUID_PATTERN = r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
|
||||
@ -186,12 +186,6 @@ class UserManager(object):
|
||||
def create_user(
|
||||
username, email, password, set_setting=True, add_to_group=True, *args, **kwargs
|
||||
):
|
||||
# Clean for potential XSS
|
||||
clean_username = nh3.clean(username).strip()
|
||||
clean_email = nh3.clean(email).strip()
|
||||
if clean_username != username or clean_email != email:
|
||||
# This will be caught by the try in view.py/register
|
||||
raise ValueError("Invalid username or password")
|
||||
# avoid circular import :S
|
||||
from .tasks import send_registration_mail
|
||||
|
||||
@ -269,9 +263,8 @@ class GroupManager(object):
|
||||
@staticmethod
|
||||
def create_group(current_user, name, description):
|
||||
g = Group()
|
||||
# Clean for potential XSS
|
||||
g.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
g.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
g.name = name
|
||||
g.description = description
|
||||
g.owner = current_user
|
||||
g.save()
|
||||
|
||||
@ -526,13 +519,8 @@ class PackageManager(object):
|
||||
@transaction.atomic
|
||||
def create_package(current_user, name: str, description: str = None):
|
||||
p = Package()
|
||||
|
||||
# Clean for potential XSS
|
||||
p.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
if description is not None and description.strip() != "":
|
||||
p.description = nh3.clean(description.strip(), tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
p.name = name
|
||||
p.description = description
|
||||
p.save()
|
||||
|
||||
up = UserPackagePermission()
|
||||
@ -1107,29 +1095,28 @@ class SettingManager(object):
|
||||
model: EPModel = None,
|
||||
model_threshold: float = None,
|
||||
):
|
||||
new_s = Setting()
|
||||
# Clean for potential XSS
|
||||
new_s.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
new_s.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
new_s.max_nodes = max_nodes
|
||||
new_s.max_depth = max_depth
|
||||
new_s.model = model
|
||||
new_s.model_threshold = model_threshold
|
||||
s = Setting()
|
||||
s.name = name
|
||||
s.description = description
|
||||
s.max_nodes = max_nodes
|
||||
s.max_depth = max_depth
|
||||
s.model = model
|
||||
s.model_threshold = model_threshold
|
||||
|
||||
new_s.save()
|
||||
s.save()
|
||||
|
||||
if rule_packages is not None:
|
||||
for r in rule_packages:
|
||||
new_s.rule_packages.add(r)
|
||||
new_s.save()
|
||||
s.rule_packages.add(r)
|
||||
s.save()
|
||||
|
||||
usp = UserSettingPermission()
|
||||
usp.user = user
|
||||
usp.setting = new_s
|
||||
usp.setting = s
|
||||
usp.permission = Permission.ALL[0]
|
||||
usp.save()
|
||||
|
||||
return new_s
|
||||
return s
|
||||
|
||||
@staticmethod
|
||||
def get_default_setting(user: User):
|
||||
@ -1558,7 +1545,7 @@ class SPathway(object):
|
||||
if self.prediction_setting.model.app_domain:
|
||||
app_domain_assessment = self.prediction_setting.model.app_domain.assess(
|
||||
sub.smiles
|
||||
)
|
||||
)[0]
|
||||
|
||||
if self.persist is not None:
|
||||
n = self.snode_persist_lookup[sub]
|
||||
@ -1591,7 +1578,9 @@ class SPathway(object):
|
||||
if self.prediction_setting.model:
|
||||
if self.prediction_setting.model.app_domain:
|
||||
app_domain_assessment = (
|
||||
self.prediction_setting.model.app_domain.assess(c)
|
||||
self.prediction_setting.model.app_domain.assess(c)[
|
||||
0
|
||||
]
|
||||
)
|
||||
|
||||
self.smiles_to_node[c] = SNode(
|
||||
|
||||
@ -12,16 +12,10 @@ from epdb.models import (
|
||||
Permission,
|
||||
User,
|
||||
ExternalDatabase,
|
||||
License,
|
||||
)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"-ol", "--only-licenses", action="store_true", help="Only create licenses."
|
||||
)
|
||||
|
||||
def create_users(self):
|
||||
# Anonymous User
|
||||
if not User.objects.filter(email="anon@envipath.com").exists():
|
||||
@ -89,17 +83,6 @@ class Command(BaseCommand):
|
||||
|
||||
return anon, admin, g, user0
|
||||
|
||||
def create_licenses(self):
|
||||
"""Create the six default licenses supported by enviPath"""
|
||||
cc_strings = ["by", "by-nc", "by-nc-nd", "by-nc-sa", "by-nd", "by-sa"]
|
||||
for cc_string in cc_strings:
|
||||
if not License.objects.filter(cc_string=cc_string).exists():
|
||||
new_license = License()
|
||||
new_license.cc_string = cc_string
|
||||
new_license.link = f"https://creativecommons.org/licenses/{cc_string}/4.0/"
|
||||
new_license.image_link = f"https://licensebuttons.net/l/{cc_string}/4.0/88x31.png"
|
||||
new_license.save()
|
||||
|
||||
def import_package(self, data, owner):
|
||||
return PackageManager.import_legacy_package(
|
||||
data, owner, keep_ids=True, add_import_timestamp=False, trust_reviewed=True
|
||||
@ -174,10 +157,6 @@ class Command(BaseCommand):
|
||||
|
||||
@transaction.atomic
|
||||
def handle(self, *args, **options):
|
||||
# Create licenses
|
||||
self.create_licenses()
|
||||
if options.get("only_licenses", False):
|
||||
return
|
||||
# Create users
|
||||
anon, admin, g, user0 = self.create_users()
|
||||
|
||||
|
||||
@ -2,7 +2,9 @@ from django.conf import settings as s
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from epdb.models import MLRelativeReasoning, EnviFormer, Package
|
||||
from epdb.models import EnviFormer, MLRelativeReasoning
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
@ -75,11 +77,13 @@ class Command(BaseCommand):
|
||||
return packages
|
||||
|
||||
# Iteratively create models in options["model_names"]
|
||||
print(f"Creating models: {options['model_names']}\n"
|
||||
f"Data packages: {options['data_packages']}\n"
|
||||
f"Rule Packages (only for MLRR): {options['rule_packages']}\n"
|
||||
f"Eval Packages: {options['eval_packages']}\n"
|
||||
f"Threshold: {options['threshold']:.2f}")
|
||||
print(
|
||||
f"Creating models: {options['model_names']}\n"
|
||||
f"Data packages: {options['data_packages']}\n"
|
||||
f"Rule Packages (only for MLRR): {options['rule_packages']}\n"
|
||||
f"Eval Packages: {options['eval_packages']}\n"
|
||||
f"Threshold: {options['threshold']:.2f}"
|
||||
)
|
||||
data_packages = decode_packages(options["data_packages"])
|
||||
eval_packages = decode_packages(options["eval_packages"])
|
||||
rule_packages = decode_packages(options["rule_packages"])
|
||||
@ -90,10 +94,10 @@ class Command(BaseCommand):
|
||||
pack,
|
||||
data_packages=data_packages,
|
||||
eval_packages=eval_packages,
|
||||
threshold=options['threshold'],
|
||||
threshold=options["threshold"],
|
||||
name=f"EnviFormer - {', '.join(options['data_packages'])} - T{options['threshold']:.2f}",
|
||||
description=f"EnviFormer transformer trained on {options['data_packages']} "
|
||||
f"evaluated on {options['eval_packages']}.",
|
||||
f"evaluated on {options['eval_packages']}.",
|
||||
)
|
||||
elif model_name == "mlrr":
|
||||
model = MLRelativeReasoning.create(
|
||||
@ -101,10 +105,10 @@ class Command(BaseCommand):
|
||||
rule_packages=rule_packages,
|
||||
data_packages=data_packages,
|
||||
eval_packages=eval_packages,
|
||||
threshold=options['threshold'],
|
||||
threshold=options["threshold"],
|
||||
name=f"ECC - {', '.join(options['data_packages'])} - T{options['threshold']:.2f}",
|
||||
description=f"ML Relative Reasoning trained on {options['data_packages']} with rules from "
|
||||
f"{options['rule_packages']} and evaluated on {options['eval_packages']}.",
|
||||
f"{options['rule_packages']} and evaluated on {options['eval_packages']}.",
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Cannot create model of type {model_name}, unknown model type")
|
||||
|
||||
@ -8,7 +8,9 @@ from django.conf import settings as s
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from epdb.models import EnviFormer, Package
|
||||
from epdb.models import EnviFormer
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
from django.apps import apps
|
||||
from django.conf import settings as s
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from django.db.models import F, Value, TextField, JSONField
|
||||
from django.db.models.functions import Replace, Cast
|
||||
from django.db.models import F, JSONField, TextField, Value
|
||||
from django.db.models.functions import Cast, Replace
|
||||
|
||||
from epdb.models import EnviPathModel
|
||||
|
||||
@ -23,10 +23,13 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
print("Localizing urls for Package")
|
||||
Package.objects.update(url=Replace(F("url"), Value(options["old"]), Value(options["new"])))
|
||||
|
||||
MODELS = [
|
||||
"User",
|
||||
"Group",
|
||||
"Package",
|
||||
"Compound",
|
||||
"CompoundStructure",
|
||||
"Pathway",
|
||||
|
||||
@ -0,0 +1,190 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-29 13:32
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("epdb", "0009_joblog"),
|
||||
("public", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="userpackagepermission",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Permission on",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="grouppackagepermission",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Permission on",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="epmodel",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Package",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="rule",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Package",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="compound",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Package",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="scenario",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Package",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="pathway",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Package",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="reaction",
|
||||
name="package",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="public.package",
|
||||
verbose_name="Package",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="default_package",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="public.package",
|
||||
verbose_name="Default Package",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="enviformer",
|
||||
name="data_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_data_packages",
|
||||
to="public.package",
|
||||
verbose_name="Data Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="enviformer",
|
||||
name="eval_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_eval_packages",
|
||||
to="public.package",
|
||||
verbose_name="Evaluation Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="enviformer",
|
||||
name="rule_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_rule_packages",
|
||||
to="public.package",
|
||||
verbose_name="Rule Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="mlrelativereasoning",
|
||||
name="data_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_data_packages",
|
||||
to="public.package",
|
||||
verbose_name="Data Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="mlrelativereasoning",
|
||||
name="eval_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_eval_packages",
|
||||
to="public.package",
|
||||
verbose_name="Evaluation Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="mlrelativereasoning",
|
||||
name="rule_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_rule_packages",
|
||||
to="public.package",
|
||||
verbose_name="Rule Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="rulebasedrelativereasoning",
|
||||
name="data_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_data_packages",
|
||||
to="public.package",
|
||||
verbose_name="Data Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="rulebasedrelativereasoning",
|
||||
name="eval_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_eval_packages",
|
||||
to="public.package",
|
||||
verbose_name="Evaluation Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="rulebasedrelativereasoning",
|
||||
name="rule_packages",
|
||||
field=models.ManyToManyField(
|
||||
related_name="%(app_label)s_%(class)s_rule_packages",
|
||||
to="public.package",
|
||||
verbose_name="Rule Packages",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="setting",
|
||||
name="rule_packages",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
related_name="setting_rule_packages",
|
||||
to="public.package",
|
||||
verbose_name="Setting Rule Packages",
|
||||
),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="Package",
|
||||
),
|
||||
]
|
||||
@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-11 14:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("epdb", "0009_joblog"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="license",
|
||||
name="cc_string",
|
||||
field=models.TextField(default="by-nc-sa", verbose_name="CC string"),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@ -1,59 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-11 14:13
|
||||
|
||||
import re
|
||||
|
||||
from django.contrib.postgres.aggregates import ArrayAgg
|
||||
from django.db import migrations
|
||||
from django.db.models import Min
|
||||
|
||||
|
||||
def set_cc(apps, schema_editor):
|
||||
License = apps.get_model("epdb", "License")
|
||||
|
||||
# For all existing licenses extract cc_string from link
|
||||
for license in License.objects.all():
|
||||
pattern = r"/licenses/([^/]+)/4\.0"
|
||||
match = re.search(pattern, license.link)
|
||||
if match:
|
||||
license.cc_string = match.group(1)
|
||||
license.save()
|
||||
else:
|
||||
raise ValueError(f"Could not find license for {license.link}")
|
||||
|
||||
# Ensure we have all licenses
|
||||
cc_strings = ["by", "by-nc", "by-nc-nd", "by-nc-sa", "by-nd", "by-sa"]
|
||||
for cc_string in cc_strings:
|
||||
if not License.objects.filter(cc_string=cc_string).exists():
|
||||
new_license = License()
|
||||
new_license.cc_string = cc_string
|
||||
new_license.link = f"https://creativecommons.org/licenses/{cc_string}/4.0/"
|
||||
new_license.image_link = f"https://licensebuttons.net/l/{cc_string}/4.0/88x31.png"
|
||||
new_license.save()
|
||||
|
||||
# As we might have existing Licenses representing the same License,
|
||||
# get min pk and all pks as a list
|
||||
license_lookup_qs = License.objects.values("cc_string").annotate(
|
||||
lowest_pk=Min("id"), all_pks=ArrayAgg("id", order_by=("id",))
|
||||
)
|
||||
|
||||
license_lookup = {
|
||||
row["cc_string"]: (row["lowest_pk"], row["all_pks"]) for row in license_lookup_qs
|
||||
}
|
||||
|
||||
Packages = apps.get_model("epdb", "Package")
|
||||
|
||||
for k, v in license_lookup.items():
|
||||
# Set min pk to all packages pointing to any of the duplicates
|
||||
Packages.objects.filter(pk__in=v[1]).update(license_id=v[0])
|
||||
# remove the min pk from "other" pks as we use them for deletion
|
||||
v[1].remove(v[0])
|
||||
# Delete redundant License objects
|
||||
License.objects.filter(pk__in=v[1]).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("epdb", "0010_license_cc_string"),
|
||||
]
|
||||
|
||||
operations = [migrations.RunPython(set_cc)]
|
||||
478
epdb/models.py
@ -7,11 +7,10 @@ import secrets
|
||||
from abc import abstractmethod
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
from typing import Union, List, Optional, Dict, Tuple, Set, Any
|
||||
from typing import Union, List, Optional, Dict, Tuple, Set, Any, TYPE_CHECKING
|
||||
from uuid import uuid4
|
||||
import math
|
||||
import joblib
|
||||
import nh3
|
||||
import numpy as np
|
||||
from django.conf import settings as s
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
@ -29,17 +28,12 @@ from sklearn.metrics import precision_score, recall_score, jaccard_score
|
||||
from sklearn.model_selection import ShuffleSplit
|
||||
|
||||
from utilities.chem import FormatConverter, ProductSet, PredictionResult, IndigoUtils
|
||||
from utilities.ml import (
|
||||
RuleBasedDataset,
|
||||
ApplicabilityDomainPCA,
|
||||
EnsembleClassifierChain,
|
||||
RelativeReasoning,
|
||||
EnviFormerDataset,
|
||||
Dataset,
|
||||
)
|
||||
from utilities.ml import Dataset, ApplicabilityDomainPCA, EnsembleClassifierChain, RelativeReasoning
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
##########################
|
||||
# User/Groups/Permission #
|
||||
@ -53,7 +47,10 @@ class User(AbstractUser):
|
||||
)
|
||||
url = models.TextField(blank=False, null=True, verbose_name="URL", unique=True)
|
||||
default_package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Default Package", null=True, on_delete=models.SET_NULL
|
||||
s.PACKAGE_IMPLEMENTATION,
|
||||
verbose_name="Default Package",
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
default_group = models.ForeignKey(
|
||||
"Group",
|
||||
@ -243,7 +240,7 @@ class UserPackagePermission(Permission):
|
||||
)
|
||||
user = models.ForeignKey("User", verbose_name="Permission to", on_delete=models.CASCADE)
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Permission on", on_delete=models.CASCADE
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Permission on", on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@ -259,7 +256,7 @@ class GroupPackagePermission(Permission):
|
||||
)
|
||||
group = models.ForeignKey("Group", verbose_name="Permission to", on_delete=models.CASCADE)
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Permission on", on_delete=models.CASCADE
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Permission on", on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@ -655,12 +652,11 @@ class ScenarioMixin(models.Model):
|
||||
|
||||
|
||||
class License(models.Model):
|
||||
cc_string = models.TextField(blank=False, null=False, verbose_name="CC string")
|
||||
link = models.URLField(blank=False, null=False, verbose_name="link")
|
||||
image_link = models.URLField(blank=False, null=False, verbose_name="Image link")
|
||||
|
||||
|
||||
class Package(EnviPathModel):
|
||||
class AbstractPackage(EnviPathModel):
|
||||
reviewed = models.BooleanField(verbose_name="Reviewstatus", default=False)
|
||||
license = models.ForeignKey(
|
||||
"epdb.License", on_delete=models.SET_NULL, blank=True, null=True, verbose_name="License"
|
||||
@ -728,10 +724,13 @@ class Package(EnviPathModel):
|
||||
rules = sorted(rules, key=lambda x: x.url)
|
||||
return rules
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin):
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
)
|
||||
default_structure = models.ForeignKey(
|
||||
"CompoundStructure",
|
||||
@ -781,7 +780,7 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def create(
|
||||
package: Package, smiles: str, name: str = None, description: str = None, *args, **kwargs
|
||||
package: "Package", smiles: str, name: str = None, description: str = None, *args, **kwargs
|
||||
) -> "Compound":
|
||||
if smiles is None or smiles.strip() == "":
|
||||
raise ValueError("SMILES is required")
|
||||
@ -811,16 +810,14 @@ class Compound(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdentifierMixin
|
||||
c = Compound()
|
||||
c.package = package
|
||||
|
||||
if name is not None:
|
||||
# Clean for potential XSS
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
if name is None or name == "":
|
||||
if name is None or name.strip() == "":
|
||||
name = f"Compound {Compound.objects.filter(package=package).count() + 1}"
|
||||
|
||||
c.name = name
|
||||
|
||||
# We have a default here only set the value if it carries some payload
|
||||
if description is not None and description.strip() != "":
|
||||
c.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
c.description = description.strip()
|
||||
|
||||
c.save()
|
||||
|
||||
@ -992,11 +989,11 @@ class CompoundStructure(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdenti
|
||||
raise ValueError("Unpersisted Compound! Persist compound first!")
|
||||
|
||||
cs = CompoundStructure()
|
||||
# Clean for potential XSS
|
||||
if name is not None:
|
||||
cs.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
cs.name = name
|
||||
|
||||
if description is not None:
|
||||
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
cs.description = description
|
||||
|
||||
cs.smiles = smiles
|
||||
cs.compound = compound
|
||||
@ -1061,7 +1058,7 @@ class EnzymeLink(EnviPathModel, KEGGIdentifierMixin):
|
||||
|
||||
class Rule(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
)
|
||||
|
||||
# # https://github.com/django-polymorphic/django-polymorphic/issues/229
|
||||
@ -1167,7 +1164,7 @@ class SimpleAmbitRule(SimpleRule):
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def create(
|
||||
package: Package,
|
||||
package: "Package",
|
||||
name: str = None,
|
||||
description: str = None,
|
||||
smirks: str = None,
|
||||
@ -1198,29 +1195,21 @@ class SimpleAmbitRule(SimpleRule):
|
||||
r = SimpleAmbitRule()
|
||||
r.package = package
|
||||
|
||||
if name is not None:
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
if name is None or name == "":
|
||||
if name is None or name.strip() == "":
|
||||
name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
|
||||
|
||||
r.name = name
|
||||
|
||||
if description is not None and description.strip() != "":
|
||||
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
r.description = description
|
||||
|
||||
r.smirks = smirks
|
||||
|
||||
if reactant_filter_smarts is not None and reactant_filter_smarts.strip() != "":
|
||||
if not FormatConverter.is_valid_smarts(reactant_filter_smarts.strip()):
|
||||
raise ValueError(f'Reactant Filter SMARTS "{reactant_filter_smarts}" is invalid!')
|
||||
else:
|
||||
r.reactant_filter_smarts = reactant_filter_smarts.strip()
|
||||
r.reactant_filter_smarts = reactant_filter_smarts
|
||||
|
||||
if product_filter_smarts is not None and product_filter_smarts.strip() != "":
|
||||
if not FormatConverter.is_valid_smarts(product_filter_smarts.strip()):
|
||||
raise ValueError(f'Product Filter SMARTS "{product_filter_smarts}" is invalid!')
|
||||
else:
|
||||
r.product_filter_smarts = product_filter_smarts.strip()
|
||||
r.product_filter_smarts = product_filter_smarts
|
||||
|
||||
r.save()
|
||||
return r
|
||||
@ -1241,6 +1230,7 @@ class SimpleAmbitRule(SimpleRule):
|
||||
|
||||
@property
|
||||
def related_reactions(self):
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
qs = Package.objects.filter(reviewed=True)
|
||||
return self.reaction_rule.filter(package__in=qs).order_by("name")
|
||||
|
||||
@ -1333,7 +1323,7 @@ class SequentialRuleOrdering(models.Model):
|
||||
|
||||
class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin):
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
)
|
||||
educts = models.ManyToManyField(
|
||||
"epdb.CompoundStructure", verbose_name="Educts", related_name="reaction_educts"
|
||||
@ -1355,7 +1345,7 @@ class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def create(
|
||||
package: Package,
|
||||
package: "Package",
|
||||
name: str = None,
|
||||
description: str = None,
|
||||
educts: Union[List[str], List[CompoundStructure]] = None,
|
||||
@ -1421,11 +1411,12 @@ class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin
|
||||
|
||||
r = Reaction()
|
||||
r.package = package
|
||||
# Clean for potential XSS
|
||||
|
||||
if name is not None and name.strip() != "":
|
||||
r.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
r.name = name
|
||||
|
||||
if description is not None and name.strip() != "":
|
||||
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
r.description = description
|
||||
|
||||
r.multi_step = multi_step
|
||||
|
||||
@ -1514,7 +1505,7 @@ class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin
|
||||
|
||||
class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
)
|
||||
setting = models.ForeignKey(
|
||||
"epdb.Setting", verbose_name="Setting", on_delete=models.CASCADE, null=True, blank=True
|
||||
@ -1733,15 +1724,14 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
):
|
||||
pw = Pathway()
|
||||
pw.package = package
|
||||
if name is not None:
|
||||
# Clean for potential XSS
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
if name is None or name == "":
|
||||
|
||||
if name is None or name.strip() == "":
|
||||
name = f"Pathway {Pathway.objects.filter(package=package).count() + 1}"
|
||||
|
||||
pw.name = name
|
||||
|
||||
if description is not None and description.strip() != "":
|
||||
pw.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
pw.description = description
|
||||
|
||||
pw.save()
|
||||
try:
|
||||
@ -2036,16 +2026,11 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
for node in end_nodes:
|
||||
e.end_nodes.add(node)
|
||||
|
||||
# Clean for potential XSS
|
||||
# Cleaning technically not needed as it is also done in Reaction.create, including it here for consistency
|
||||
if name is not None:
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
if name is None or name == "":
|
||||
if name is None:
|
||||
name = f"Reaction {pathway.package.reactions.count() + 1}"
|
||||
|
||||
if description is None:
|
||||
description = s.DEFAULT_VALUES["description"]
|
||||
description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
r = Reaction.create(
|
||||
pathway.package,
|
||||
@ -2076,7 +2061,7 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
|
||||
class EPModel(PolymorphicModel, EnviPathModel):
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
)
|
||||
|
||||
def _url(self):
|
||||
@ -2085,17 +2070,17 @@ class EPModel(PolymorphicModel, EnviPathModel):
|
||||
|
||||
class PackageBasedModel(EPModel):
|
||||
rule_packages = models.ManyToManyField(
|
||||
"Package",
|
||||
s.PACKAGE_IMPLEMENTATION,
|
||||
verbose_name="Rule Packages",
|
||||
related_name="%(app_label)s_%(class)s_rule_packages",
|
||||
)
|
||||
data_packages = models.ManyToManyField(
|
||||
"Package",
|
||||
s.PACKAGE_IMPLEMENTATION,
|
||||
verbose_name="Data Packages",
|
||||
related_name="%(app_label)s_%(class)s_data_packages",
|
||||
)
|
||||
eval_packages = models.ManyToManyField(
|
||||
"Package",
|
||||
s.PACKAGE_IMPLEMENTATION,
|
||||
verbose_name="Evaluation Packages",
|
||||
related_name="%(app_label)s_%(class)s_eval_packages",
|
||||
)
|
||||
@ -2199,7 +2184,7 @@ class PackageBasedModel(EPModel):
|
||||
|
||||
applicable_rules = self.applicable_rules
|
||||
reactions = list(self._get_reactions())
|
||||
ds = RuleBasedDataset.generate_dataset(reactions, applicable_rules, educts_only=True)
|
||||
ds = Dataset.generate_dataset(reactions, applicable_rules, educts_only=True)
|
||||
|
||||
end = datetime.now()
|
||||
logger.debug(f"build_dataset took {(end - start).total_seconds()} seconds")
|
||||
@ -2208,7 +2193,7 @@ class PackageBasedModel(EPModel):
|
||||
ds.save(f)
|
||||
return ds
|
||||
|
||||
def load_dataset(self) -> "Dataset | RuleBasedDataset | EnviFormerDataset":
|
||||
def load_dataset(self) -> "Dataset":
|
||||
ds_path = os.path.join(s.MODEL_DIR, f"{self.uuid}_ds.pkl")
|
||||
return Dataset.load(ds_path)
|
||||
|
||||
@ -2249,7 +2234,7 @@ class PackageBasedModel(EPModel):
|
||||
self.model_status = self.BUILT_NOT_EVALUATED
|
||||
self.save()
|
||||
|
||||
def evaluate_model(self, multigen: bool, eval_packages: List["Package"] = None, **kwargs):
|
||||
def evaluate_model(self, multigen: bool, eval_packages: List["Package"] = None):
|
||||
if self.model_status != self.BUILT_NOT_EVALUATED:
|
||||
raise ValueError(f"Can't evaluate a model in state {self.model_status}!")
|
||||
|
||||
@ -2367,39 +2352,37 @@ class PackageBasedModel(EPModel):
|
||||
eval_reactions = list(
|
||||
Reaction.objects.filter(package__in=self.eval_packages.all()).distinct()
|
||||
)
|
||||
ds = RuleBasedDataset.generate_dataset(
|
||||
eval_reactions, self.applicable_rules, educts_only=True
|
||||
)
|
||||
ds = Dataset.generate_dataset(eval_reactions, self.applicable_rules, educts_only=True)
|
||||
if isinstance(self, RuleBasedRelativeReasoning):
|
||||
X = ds.X(exclude_id_col=False, na_replacement=None).to_numpy()
|
||||
y = ds.y(na_replacement=np.nan).to_numpy()
|
||||
X = np.array(ds.X(exclude_id_col=False, na_replacement=None))
|
||||
y = np.array(ds.y(na_replacement=np.nan))
|
||||
else:
|
||||
X = ds.X(na_replacement=np.nan).to_numpy()
|
||||
y = ds.y(na_replacement=np.nan).to_numpy()
|
||||
X = np.array(ds.X(na_replacement=np.nan))
|
||||
y = np.array(ds.y(na_replacement=np.nan))
|
||||
single_gen_result = evaluate_sg(self.model, X, y, np.arange(len(X)), self.threshold)
|
||||
self.eval_results = self.compute_averages([single_gen_result])
|
||||
else:
|
||||
ds = self.load_dataset()
|
||||
|
||||
if isinstance(self, RuleBasedRelativeReasoning):
|
||||
X = ds.X(exclude_id_col=False, na_replacement=None).to_numpy()
|
||||
y = ds.y(na_replacement=np.nan).to_numpy()
|
||||
X = np.array(ds.X(exclude_id_col=False, na_replacement=None))
|
||||
y = np.array(ds.y(na_replacement=np.nan))
|
||||
else:
|
||||
X = ds.X(na_replacement=np.nan).to_numpy()
|
||||
y = ds.y(na_replacement=np.nan).to_numpy()
|
||||
X = np.array(ds.X(na_replacement=np.nan))
|
||||
y = np.array(ds.y(na_replacement=np.nan))
|
||||
|
||||
n_splits = kwargs.get("n_splits", 20)
|
||||
n_splits = 20
|
||||
|
||||
shuff = ShuffleSplit(n_splits=n_splits, test_size=0.25, random_state=42)
|
||||
splits = list(shuff.split(X))
|
||||
|
||||
from joblib import Parallel, delayed
|
||||
|
||||
models = Parallel(n_jobs=min(10, len(splits)))(
|
||||
models = Parallel(n_jobs=10)(
|
||||
delayed(train_func)(X, y, train_index, self._model_args())
|
||||
for train_index, _ in splits
|
||||
)
|
||||
evaluations = Parallel(n_jobs=min(10, len(splits)))(
|
||||
evaluations = Parallel(n_jobs=10)(
|
||||
delayed(evaluate_sg)(model, X, y, test_index, self.threshold)
|
||||
for model, (_, test_index) in zip(models, splits)
|
||||
)
|
||||
@ -2567,15 +2550,14 @@ class RuleBasedRelativeReasoning(PackageBasedModel):
|
||||
):
|
||||
rbrr = RuleBasedRelativeReasoning()
|
||||
rbrr.package = package
|
||||
if name is not None:
|
||||
# Clean for potential XSS
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
if name is None or name == "":
|
||||
|
||||
if name is None or name.strip() == "":
|
||||
name = f"RuleBasedRelativeReasoning {RuleBasedRelativeReasoning.objects.filter(package=package).count() + 1}"
|
||||
|
||||
rbrr.name = name
|
||||
|
||||
if description is not None and description.strip() != "":
|
||||
rbrr.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
rbrr.description = description
|
||||
|
||||
if threshold is None or (threshold <= 0 or 1 <= threshold):
|
||||
raise ValueError("Threshold must be a float between 0 and 1.")
|
||||
@ -2612,11 +2594,11 @@ class RuleBasedRelativeReasoning(PackageBasedModel):
|
||||
|
||||
return rbrr
|
||||
|
||||
def _fit_model(self, ds: RuleBasedDataset):
|
||||
def _fit_model(self, ds: Dataset):
|
||||
X, y = ds.X(exclude_id_col=False, na_replacement=None), ds.y(na_replacement=None)
|
||||
model = RelativeReasoning(
|
||||
start_index=ds.triggered()[0],
|
||||
end_index=ds.triggered()[-1],
|
||||
end_index=ds.triggered()[1],
|
||||
)
|
||||
model.fit(X, y)
|
||||
return model
|
||||
@ -2626,7 +2608,7 @@ class RuleBasedRelativeReasoning(PackageBasedModel):
|
||||
return {
|
||||
"clz": "RuleBaseRelativeReasoning",
|
||||
"start_index": ds.triggered()[0],
|
||||
"end_index": ds.triggered()[-1],
|
||||
"end_index": ds.triggered()[1],
|
||||
}
|
||||
|
||||
def _save_model(self, model):
|
||||
@ -2672,15 +2654,14 @@ class MLRelativeReasoning(PackageBasedModel):
|
||||
):
|
||||
mlrr = MLRelativeReasoning()
|
||||
mlrr.package = package
|
||||
if name is not None:
|
||||
# Clean for potential XSS
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
if name is None or name == "":
|
||||
|
||||
if name is None or name.strip() == "":
|
||||
name = f"MLRelativeReasoning {MLRelativeReasoning.objects.filter(package=package).count() + 1}"
|
||||
|
||||
mlrr.name = name
|
||||
|
||||
if description is not None and description.strip() != "":
|
||||
mlrr.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
mlrr.description = description
|
||||
|
||||
if threshold is None or (threshold <= 0 or 1 <= threshold):
|
||||
raise ValueError("Threshold must be a float between 0 and 1.")
|
||||
@ -2715,11 +2696,11 @@ class MLRelativeReasoning(PackageBasedModel):
|
||||
|
||||
return mlrr
|
||||
|
||||
def _fit_model(self, ds: RuleBasedDataset):
|
||||
def _fit_model(self, ds: Dataset):
|
||||
X, y = ds.X(na_replacement=np.nan), ds.y(na_replacement=np.nan)
|
||||
|
||||
model = EnsembleClassifierChain(**s.DEFAULT_MODEL_PARAMS)
|
||||
model.fit(X.to_numpy(), y.to_numpy())
|
||||
model.fit(X, y)
|
||||
return model
|
||||
|
||||
def _model_args(self):
|
||||
@ -2742,7 +2723,7 @@ class MLRelativeReasoning(PackageBasedModel):
|
||||
start = datetime.now()
|
||||
ds = self.load_dataset()
|
||||
classify_ds, classify_prods = ds.classification_dataset([smiles], self.applicable_rules)
|
||||
pred = self.model.predict_proba(classify_ds.X().to_numpy())
|
||||
pred = self.model.predict_proba(classify_ds.X())
|
||||
|
||||
res = MLRelativeReasoning.combine_products_and_probs(
|
||||
self.applicable_rules, pred[0], classify_prods[0]
|
||||
@ -2787,9 +2768,7 @@ class ApplicabilityDomain(EnviPathModel):
|
||||
|
||||
@cached_property
|
||||
def training_set_probs(self):
|
||||
ds = self.model.load_dataset()
|
||||
col_ids = ds.block_indices("prob")
|
||||
return ds[:, col_ids]
|
||||
return joblib.load(os.path.join(s.MODEL_DIR, f"{self.model.uuid}_train_probs.pkl"))
|
||||
|
||||
def build(self):
|
||||
ds = self.model.load_dataset()
|
||||
@ -2797,9 +2776,9 @@ class ApplicabilityDomain(EnviPathModel):
|
||||
start = datetime.now()
|
||||
|
||||
# Get Trainingset probs and dump them as they're required when using the app domain
|
||||
probs = self.model.model.predict_proba(ds.X().to_numpy())
|
||||
ds.add_probs(probs)
|
||||
ds.save(os.path.join(s.MODEL_DIR, f"{self.model.uuid}_ds.pkl"))
|
||||
probs = self.model.model.predict_proba(ds.X())
|
||||
f = os.path.join(s.MODEL_DIR, f"{self.model.uuid}_train_probs.pkl")
|
||||
joblib.dump(probs, f)
|
||||
|
||||
ad = ApplicabilityDomainPCA(num_neighbours=self.num_neighbours)
|
||||
ad.build(ds)
|
||||
@ -2822,20 +2801,15 @@ class ApplicabilityDomain(EnviPathModel):
|
||||
joblib.dump(ad, f)
|
||||
|
||||
def assess(self, structure: Union[str, "CompoundStructure"]):
|
||||
return self.assess_batch([structure])[0]
|
||||
|
||||
def assess_batch(self, structures: List["CompoundStructure | str"]):
|
||||
ds = self.model.load_dataset()
|
||||
|
||||
smiles = []
|
||||
for struct in structures:
|
||||
if isinstance(struct, CompoundStructure):
|
||||
smiles.append(structures.smiles)
|
||||
else:
|
||||
smiles.append(structures)
|
||||
if isinstance(structure, CompoundStructure):
|
||||
smiles = structure.smiles
|
||||
else:
|
||||
smiles = structure
|
||||
|
||||
assessment_ds, assessment_prods = ds.classification_dataset(
|
||||
structures, self.model.applicable_rules
|
||||
[structure], self.model.applicable_rules
|
||||
)
|
||||
|
||||
# qualified_neighbours_per_rule is a nested dictionary structured as:
|
||||
@ -2849,61 +2823,82 @@ class ApplicabilityDomain(EnviPathModel):
|
||||
# it identifies all training structures that have the same trigger reaction activated (i.e., value 1).
|
||||
# This is used to find "qualified neighbours" — training examples that share the same triggered feature
|
||||
# with a given assessment structure under a particular rule.
|
||||
qualified_neighbours_per_rule: Dict = {}
|
||||
qualified_neighbours_per_rule: Dict[int, Dict[int, List[int]]] = defaultdict(
|
||||
lambda: defaultdict(list)
|
||||
)
|
||||
|
||||
import polars as pl
|
||||
for rule_idx, feature_index in enumerate(range(*assessment_ds.triggered())):
|
||||
feature = ds.columns[feature_index]
|
||||
if feature.startswith("trig_"):
|
||||
# TODO unroll loop
|
||||
for i, cx in enumerate(assessment_ds.X(exclude_id_col=False)):
|
||||
if int(cx[feature_index]) == 1:
|
||||
for j, tx in enumerate(ds.X(exclude_id_col=False)):
|
||||
if int(tx[feature_index]) == 1:
|
||||
qualified_neighbours_per_rule[i][rule_idx].append(j)
|
||||
|
||||
# Select only the triggered columns
|
||||
for i, row in enumerate(assessment_ds[:, assessment_ds.triggered()].iter_rows(named=True)):
|
||||
# Find the rules the structure triggers. For each rule, filter the training dataset to rows that also
|
||||
# trigger that rule.
|
||||
train_trig = {
|
||||
trig_uuid.split("_")[-1]: ds.filter(pl.col(trig_uuid).eq(1))
|
||||
for trig_uuid, value in row.items()
|
||||
if value == 1
|
||||
}
|
||||
qualified_neighbours_per_rule[i] = train_trig
|
||||
rule_to_i = {str(r.uuid): i for i, r in enumerate(self.model.applicable_rules)}
|
||||
probs = self.training_set_probs
|
||||
# preds = self.model.model.predict_proba(assessment_ds.X())
|
||||
preds = self.model.combine_products_and_probs(
|
||||
self.model.applicable_rules,
|
||||
self.model.model.predict_proba(assessment_ds.X().to_numpy())[0],
|
||||
self.model.model.predict_proba(assessment_ds.X())[0],
|
||||
assessment_prods[0],
|
||||
)
|
||||
|
||||
assessments = list()
|
||||
|
||||
# loop through our assessment dataset
|
||||
for i, instance in enumerate(assessment_ds[:, assessment_ds.struct_features()]):
|
||||
for i, instance in enumerate(assessment_ds):
|
||||
rule_reliabilities = dict()
|
||||
local_compatibilities = dict()
|
||||
neighbours_per_rule = dict()
|
||||
neighbor_probs_per_rule = dict()
|
||||
|
||||
# loop through rule indices together with the collected neighbours indices from train dataset
|
||||
for rule_uuid, train_instances in qualified_neighbours_per_rule[i].items():
|
||||
# compute tanimoto distance for all neighbours and add to dataset
|
||||
for rule_idx, vals in qualified_neighbours_per_rule[i].items():
|
||||
# collect the train dataset instances and store it along with the index (a.k.a. row number) of the
|
||||
# train dataset
|
||||
train_instances = []
|
||||
for v in vals:
|
||||
train_instances.append((v, ds.at(v)))
|
||||
|
||||
# sf is a tuple with start/end index of the features
|
||||
sf = ds.struct_features()
|
||||
|
||||
# compute tanimoto distance for all neighbours
|
||||
# result ist a list of tuples with train index and computed distance
|
||||
dists = self._compute_distances(
|
||||
assessment_ds[i, assessment_ds.struct_features()].to_numpy()[0],
|
||||
train_instances[:, train_instances.struct_features()].to_numpy(),
|
||||
instance.X()[0][sf[0] : sf[1]],
|
||||
[ti[1].X()[0][sf[0] : sf[1]] for ti in train_instances],
|
||||
)
|
||||
train_instances = train_instances.with_columns(dist=pl.Series(dists))
|
||||
|
||||
dists_with_index = list()
|
||||
for ti, dist in zip(train_instances, dists):
|
||||
dists_with_index.append((ti[0], dist[1]))
|
||||
|
||||
# sort them in a descending way and take at most `self.num_neighbours`
|
||||
# TODO: Should this be descending? If we want the most similar then we want values close to zero (ascending)
|
||||
train_instances = train_instances.sort("dist", descending=True)[
|
||||
: self.num_neighbours
|
||||
]
|
||||
dists_with_index = sorted(dists_with_index, key=lambda x: x[1], reverse=True)
|
||||
dists_with_index = dists_with_index[: self.num_neighbours]
|
||||
|
||||
# compute average distance
|
||||
rule_reliabilities[rule_uuid] = (
|
||||
train_instances.select(pl.mean("dist")).fill_nan(0.0).item()
|
||||
rule_reliabilities[rule_idx] = (
|
||||
sum([d[1] for d in dists_with_index]) / len(dists_with_index)
|
||||
if len(dists_with_index) > 0
|
||||
else 0.0
|
||||
)
|
||||
|
||||
# for local_compatibility we'll need the datasets for the indices having the highest similarity
|
||||
local_compatibilities[rule_uuid] = self._compute_compatibility(
|
||||
rule_uuid, train_instances
|
||||
neighbour_datasets = [(d[0], ds.at(d[0])) for d in dists_with_index]
|
||||
local_compatibilities[rule_idx] = self._compute_compatibility(
|
||||
rule_idx, probs, neighbour_datasets
|
||||
)
|
||||
neighbours_per_rule[rule_uuid] = list(
|
||||
CompoundStructure.objects.filter(uuid__in=train_instances["structure_id"])
|
||||
)
|
||||
neighbor_probs_per_rule[rule_uuid] = train_instances[f"prob_{rule_uuid}"].to_list()
|
||||
neighbours_per_rule[rule_idx] = [
|
||||
CompoundStructure.objects.get(uuid=ds[1].structure_id())
|
||||
for ds in neighbour_datasets
|
||||
]
|
||||
neighbor_probs_per_rule[rule_idx] = [
|
||||
probs[d[0]][rule_idx] for d in dists_with_index
|
||||
]
|
||||
|
||||
ad_res = {
|
||||
"ad_params": {
|
||||
@ -2914,21 +2909,23 @@ class ApplicabilityDomain(EnviPathModel):
|
||||
"local_compatibility_threshold": self.local_compatibilty_threshold,
|
||||
},
|
||||
"assessment": {
|
||||
"smiles": smiles[i],
|
||||
"inside_app_domain": self.pca.is_applicable(assessment_ds[i])[0],
|
||||
"smiles": smiles,
|
||||
"inside_app_domain": self.pca.is_applicable(instance)[0],
|
||||
},
|
||||
}
|
||||
|
||||
transformations = list()
|
||||
for rule_uuid in rule_reliabilities.keys():
|
||||
rule = Rule.objects.get(uuid=rule_uuid)
|
||||
for rule_idx in rule_reliabilities.keys():
|
||||
rule = Rule.objects.get(
|
||||
uuid=instance.columns[instance.observed()[0] + rule_idx].replace("obs_", "")
|
||||
)
|
||||
|
||||
rule_data = rule.simple_json()
|
||||
rule_data["image"] = f"{rule.url}?image=svg"
|
||||
|
||||
neighbors = []
|
||||
for n, n_prob in zip(
|
||||
neighbours_per_rule[rule_uuid], neighbor_probs_per_rule[rule_uuid]
|
||||
neighbours_per_rule[rule_idx], neighbor_probs_per_rule[rule_idx]
|
||||
):
|
||||
neighbor = n.simple_json()
|
||||
neighbor["image"] = f"{n.url}?image=svg"
|
||||
@ -2945,14 +2942,14 @@ class ApplicabilityDomain(EnviPathModel):
|
||||
|
||||
transformation = {
|
||||
"rule": rule_data,
|
||||
"reliability": rule_reliabilities[rule_uuid],
|
||||
"reliability": rule_reliabilities[rule_idx],
|
||||
# We're setting it here to False, as we don't know whether "assess" is called during pathway
|
||||
# prediction or from Model Page. For persisted Nodes this field will be overwritten at runtime
|
||||
"is_predicted": False,
|
||||
"local_compatibility": local_compatibilities[rule_uuid],
|
||||
"probability": preds[rule_to_i[rule_uuid]].probability,
|
||||
"local_compatibility": local_compatibilities[rule_idx],
|
||||
"probability": preds[rule_idx].probability,
|
||||
"transformation_products": [
|
||||
x.product_set for x in preds[rule_to_i[rule_uuid]].product_sets
|
||||
x.product_set for x in preds[rule_idx].product_sets
|
||||
],
|
||||
"times_triggered": ds.times_triggered(str(rule.uuid)),
|
||||
"neighbors": neighbors,
|
||||
@ -2970,24 +2967,32 @@ class ApplicabilityDomain(EnviPathModel):
|
||||
def _compute_distances(classify_instance: List[int], train_instances: List[List[int]]):
|
||||
from utilities.ml import tanimoto_distance
|
||||
|
||||
distances = [tanimoto_distance(classify_instance, train) for train in train_instances]
|
||||
distances = [
|
||||
(i, tanimoto_distance(classify_instance, train))
|
||||
for i, train in enumerate(train_instances)
|
||||
]
|
||||
return distances
|
||||
|
||||
def _compute_compatibility(self, rule_idx: int, neighbours: "RuleBasedDataset"):
|
||||
@staticmethod
|
||||
def _compute_compatibility(rule_idx: int, preds, neighbours: List[Tuple[int, "Dataset"]]):
|
||||
tp, tn, fp, fn = 0.0, 0.0, 0.0, 0.0
|
||||
accuracy = 0.0
|
||||
import polars as pl
|
||||
|
||||
obs_pred = neighbours.select(
|
||||
obs=pl.col(f"obs_{rule_idx}").cast(pl.Boolean),
|
||||
pred=pl.col(f"prob_{rule_idx}") >= self.model.threshold,
|
||||
)
|
||||
# Compute tp, tn, fp, fn using polars expressions
|
||||
tp = obs_pred.filter((pl.col("obs")) & (pl.col("pred"))).height
|
||||
tn = obs_pred.filter((~pl.col("obs")) & (~pl.col("pred"))).height
|
||||
fp = obs_pred.filter((~pl.col("obs")) & (pl.col("pred"))).height
|
||||
fn = obs_pred.filter((pl.col("obs")) & (~pl.col("pred"))).height
|
||||
if tp + tn > 0.0:
|
||||
accuracy = (tp + tn) / (tp + tn + fp + fn)
|
||||
for n in neighbours:
|
||||
obs = n[1].y()[0][rule_idx]
|
||||
pred = preds[n[0]][rule_idx]
|
||||
if obs and pred:
|
||||
tp += 1
|
||||
elif not obs and pred:
|
||||
fp += 1
|
||||
elif obs and not pred:
|
||||
fn += 1
|
||||
else:
|
||||
tn += 1
|
||||
# Jaccard Index
|
||||
if tp + tn > 0.0:
|
||||
accuracy = (tp + tn) / (tp + tn + fp + fn)
|
||||
|
||||
return accuracy
|
||||
|
||||
|
||||
@ -3007,15 +3012,14 @@ class EnviFormer(PackageBasedModel):
|
||||
):
|
||||
mod = EnviFormer()
|
||||
mod.package = package
|
||||
if name is not None:
|
||||
# Clean for potential XSS
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
if name is None or name == "":
|
||||
|
||||
if name is None or name.strip() == "":
|
||||
name = f"EnviFormer {EnviFormer.objects.filter(package=package).count() + 1}"
|
||||
|
||||
mod.name = name
|
||||
|
||||
if description is not None and description.strip() != "":
|
||||
mod.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
mod.description = description
|
||||
|
||||
if threshold is None or (threshold <= 0 or 1 <= threshold):
|
||||
raise ValueError("Threshold must be a float between 0 and 1.")
|
||||
@ -3089,24 +3093,44 @@ class EnviFormer(PackageBasedModel):
|
||||
self.save()
|
||||
|
||||
start = datetime.now()
|
||||
ds = EnviFormerDataset.generate_dataset(self._get_reactions())
|
||||
# Standardise reactions for the training data, EnviFormer ignores stereochemistry currently
|
||||
co2 = {"C(=O)=O", "O=C=O"}
|
||||
ds = []
|
||||
for reaction in self._get_reactions():
|
||||
educts = ".".join(
|
||||
[
|
||||
FormatConverter.standardize(smile.smiles, remove_stereo=True)
|
||||
for smile in reaction.educts.all()
|
||||
]
|
||||
)
|
||||
products = ".".join(
|
||||
[
|
||||
FormatConverter.standardize(smile.smiles, remove_stereo=True)
|
||||
for smile in reaction.products.all()
|
||||
]
|
||||
)
|
||||
if products not in co2:
|
||||
ds.append(f"{educts}>>{products}")
|
||||
|
||||
end = datetime.now()
|
||||
logger.debug(f"build_dataset took {(end - start).total_seconds()} seconds")
|
||||
f = os.path.join(s.MODEL_DIR, f"{self.uuid}_ds.json")
|
||||
ds.save(f)
|
||||
with open(f, "w") as d_file:
|
||||
json.dump(ds, d_file)
|
||||
return ds
|
||||
|
||||
def load_dataset(self):
|
||||
def load_dataset(self) -> "Dataset":
|
||||
ds_path = os.path.join(s.MODEL_DIR, f"{self.uuid}_ds.json")
|
||||
return EnviFormerDataset.load(ds_path)
|
||||
with open(ds_path) as d_file:
|
||||
ds = json.load(d_file)
|
||||
return ds
|
||||
|
||||
def _fit_model(self, ds):
|
||||
# Call to enviFormer's fine_tune function and return the model
|
||||
from enviformer.finetune import fine_tune
|
||||
|
||||
start = datetime.now()
|
||||
model = fine_tune(ds.X(), ds.y(), s.MODEL_DIR, str(self.uuid), device=s.ENVIFORMER_DEVICE)
|
||||
model = fine_tune(ds, s.MODEL_DIR, str(self.uuid), device=s.ENVIFORMER_DEVICE)
|
||||
end = datetime.now()
|
||||
logger.debug(f"EnviFormer finetuning took {(end - start).total_seconds():.2f} seconds")
|
||||
return model
|
||||
@ -3122,7 +3146,7 @@ class EnviFormer(PackageBasedModel):
|
||||
args = {"clz": "EnviFormer"}
|
||||
return args
|
||||
|
||||
def evaluate_model(self, multigen: bool, eval_packages: List["Package"] = None, **kwargs):
|
||||
def evaluate_model(self, multigen: bool, eval_packages: List["Package"] = None):
|
||||
if self.model_status != self.BUILT_NOT_EVALUATED:
|
||||
raise ValueError(f"Can't evaluate a model in state {self.model_status}!")
|
||||
|
||||
@ -3137,20 +3161,21 @@ class EnviFormer(PackageBasedModel):
|
||||
self.model_status = self.EVALUATING
|
||||
self.save()
|
||||
|
||||
def evaluate_sg(test_ds, predictions, model_thresh):
|
||||
def evaluate_sg(test_reactions, predictions, model_thresh):
|
||||
# Group the true products of reactions with the same reactant together
|
||||
assert len(test_ds) == len(predictions)
|
||||
true_dict = {}
|
||||
for r in test_ds:
|
||||
reactant, true_product_set = r
|
||||
for r in test_reactions:
|
||||
reactant, true_product_set = r.split(">>")
|
||||
true_product_set = {p for p in true_product_set.split(".")}
|
||||
true_dict[reactant] = true_dict.setdefault(reactant, []) + [true_product_set]
|
||||
assert len(test_reactions) == len(predictions)
|
||||
assert sum(len(v) for v in true_dict.values()) == len(test_reactions)
|
||||
|
||||
# Group the predicted products of reactions with the same reactant together
|
||||
pred_dict = {}
|
||||
for k, pred in enumerate(predictions):
|
||||
pred_smiles, pred_proba = zip(*pred.items())
|
||||
reactant, _ = test_ds[k, "educts"], test_ds[k, "products"]
|
||||
reactant, true_product = test_reactions[k].split(">>")
|
||||
pred_dict.setdefault(reactant, {"predict": [], "scores": []})
|
||||
for smiles, proba in zip(pred_smiles, pred_proba):
|
||||
smiles = set(smiles.split("."))
|
||||
@ -3185,7 +3210,7 @@ class EnviFormer(PackageBasedModel):
|
||||
break
|
||||
|
||||
# Recall is TP (correct) / TP + FN (len(test_reactions))
|
||||
rec = {f"{k:.2f}": v / len(test_ds) for k, v in correct.items()}
|
||||
rec = {f"{k:.2f}": v / len(test_reactions) for k, v in correct.items()}
|
||||
# Precision is TP (correct) / TP + FP (predicted)
|
||||
prec = {
|
||||
f"{k:.2f}": v / predicted[k] if predicted[k] > 0 else 0 for k, v in correct.items()
|
||||
@ -3264,35 +3289,47 @@ class EnviFormer(PackageBasedModel):
|
||||
|
||||
# If there are eval packages perform single generation evaluation on them instead of random splits
|
||||
if self.eval_packages.count() > 0:
|
||||
ds = EnviFormerDataset.generate_dataset(
|
||||
Reaction.objects.filter(package__in=self.eval_packages.all()).distinct()
|
||||
)
|
||||
test_result = self.model.predict_batch(ds.X())
|
||||
ds = []
|
||||
for reaction in Reaction.objects.filter(
|
||||
package__in=self.eval_packages.all()
|
||||
).distinct():
|
||||
educts = ".".join(
|
||||
[
|
||||
FormatConverter.standardize(smile.smiles, remove_stereo=True)
|
||||
for smile in reaction.educts.all()
|
||||
]
|
||||
)
|
||||
products = ".".join(
|
||||
[
|
||||
FormatConverter.standardize(smile.smiles, remove_stereo=True)
|
||||
for smile in reaction.products.all()
|
||||
]
|
||||
)
|
||||
ds.append(f"{educts}>>{products}")
|
||||
test_result = self.model.predict_batch([smirk.split(">>")[0] for smirk in ds])
|
||||
single_gen_result = evaluate_sg(ds, test_result, self.threshold)
|
||||
self.eval_results = self.compute_averages([single_gen_result])
|
||||
else:
|
||||
from enviformer.finetune import fine_tune
|
||||
|
||||
ds = self.load_dataset()
|
||||
n_splits = kwargs.get("n_splits", 20)
|
||||
n_splits = 20
|
||||
shuff = ShuffleSplit(n_splits=n_splits, test_size=0.1, random_state=42)
|
||||
|
||||
# Single gen eval is done in one loop of train then evaluate rather than storing all n_splits trained models
|
||||
# this helps reduce the memory footprint.
|
||||
single_gen_results = []
|
||||
for split_id, (train_index, test_index) in enumerate(shuff.split(ds)):
|
||||
train = ds[train_index]
|
||||
test = ds[test_index]
|
||||
train = [ds[i] for i in train_index]
|
||||
test = [ds[i] for i in test_index]
|
||||
start = datetime.now()
|
||||
model = fine_tune(
|
||||
train.X(), train.y(), s.MODEL_DIR, str(split_id), device=s.ENVIFORMER_DEVICE
|
||||
)
|
||||
model = fine_tune(train, s.MODEL_DIR, str(split_id), device=s.ENVIFORMER_DEVICE)
|
||||
end = datetime.now()
|
||||
logger.debug(
|
||||
f"EnviFormer finetuning took {(end - start).total_seconds():.2f} seconds"
|
||||
)
|
||||
model.to(s.ENVIFORMER_DEVICE)
|
||||
test_result = model.predict_batch(test.X())
|
||||
test_result = model.predict_batch([smirk.split(">>")[0] for smirk in test])
|
||||
single_gen_results.append(evaluate_sg(test, test_result, self.threshold))
|
||||
|
||||
self.eval_results = self.compute_averages(single_gen_results)
|
||||
@ -3371,12 +3408,23 @@ class EnviFormer(PackageBasedModel):
|
||||
):
|
||||
overlap += 1
|
||||
continue
|
||||
train_reactions.append(reaction)
|
||||
train_ds = EnviFormerDataset.generate_dataset(train_reactions)
|
||||
educts = ".".join(
|
||||
[
|
||||
FormatConverter.standardize(smile.smiles, remove_stereo=True)
|
||||
for smile in reaction.educts.all()
|
||||
]
|
||||
)
|
||||
products = ".".join(
|
||||
[
|
||||
FormatConverter.standardize(smile.smiles, remove_stereo=True)
|
||||
for smile in reaction.products.all()
|
||||
]
|
||||
)
|
||||
train_reactions.append(f"{educts}>>{products}")
|
||||
logging.debug(
|
||||
f"{overlap} compounds had to be removed from multigen split due to overlap within pathways"
|
||||
)
|
||||
model = fine_tune(train_ds.X(), train_ds.y(), s.MODEL_DIR, f"mg_{split_id}")
|
||||
model = fine_tune(train_reactions, s.MODEL_DIR, f"mg_{split_id}")
|
||||
multi_gen_results.append(evaluate_mg(model, test_pathways, self.threshold))
|
||||
|
||||
self.eval_results.update(
|
||||
@ -3400,7 +3448,7 @@ class PluginModel(EPModel):
|
||||
|
||||
class Scenario(EnviPathModel):
|
||||
package = models.ForeignKey(
|
||||
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
s.PACKAGE_IMPLEMENTATION, verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||
)
|
||||
scenario_date = models.CharField(max_length=256, null=False, blank=False, default="No date")
|
||||
scenario_type = models.CharField(
|
||||
@ -3425,44 +3473,41 @@ class Scenario(EnviPathModel):
|
||||
scenario_type: str,
|
||||
additional_information: List["EnviPyModel"],
|
||||
):
|
||||
new_s = Scenario()
|
||||
new_s.package = package
|
||||
if name is not None:
|
||||
# Clean for potential XSS
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
if name is None or name == "":
|
||||
s = Scenario()
|
||||
s.package = package
|
||||
|
||||
if name is None or name.strip() == "":
|
||||
name = f"Scenario {Scenario.objects.filter(package=package).count() + 1}"
|
||||
new_s.name = name
|
||||
|
||||
s.name = name
|
||||
|
||||
if description is not None and description.strip() != "":
|
||||
new_s.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
s.description = description
|
||||
|
||||
if scenario_date is not None and scenario_date.strip() != "":
|
||||
new_s.scenario_date = nh3.clean(scenario_date).strip()
|
||||
s.scenario_date = scenario_date
|
||||
|
||||
if scenario_type is not None and scenario_type.strip() != "":
|
||||
new_s.scenario_type = scenario_type
|
||||
s.scenario_type = scenario_type
|
||||
|
||||
add_inf = defaultdict(list)
|
||||
|
||||
for info in additional_information:
|
||||
cls_name = info.__class__.__name__
|
||||
# Clean for potential XSS hidden in the additional information fields.
|
||||
ai_data = json.loads(nh3.clean(info.model_dump_json()).strip())
|
||||
ai_data = json.loads(info.model_dump_json())
|
||||
ai_data["uuid"] = f"{uuid4()}"
|
||||
add_inf[cls_name].append(ai_data)
|
||||
|
||||
new_s.additional_information = add_inf
|
||||
s.additional_information = add_inf
|
||||
|
||||
new_s.save()
|
||||
s.save()
|
||||
|
||||
return new_s
|
||||
return s
|
||||
|
||||
@transaction.atomic
|
||||
def add_additional_information(self, data: "EnviPyModel"):
|
||||
cls_name = data.__class__.__name__
|
||||
# Clean for potential XSS hidden in the additional information fields.
|
||||
ai_data = json.loads(nh3.clean(data.model_dump_json()).strip())
|
||||
ai_data = json.loads(data.model_dump_json())
|
||||
ai_data["uuid"] = f"{uuid4()}"
|
||||
|
||||
if cls_name not in self.additional_information:
|
||||
@ -3497,8 +3542,7 @@ class Scenario(EnviPathModel):
|
||||
new_ais = defaultdict(list)
|
||||
for k, vals in data.items():
|
||||
for v in vals:
|
||||
# Clean for potential XSS hidden in the additional information fields.
|
||||
ai_data = json.loads(nh3.clean(v.model_dump_json()).strip())
|
||||
ai_data = json.loads(v.model_dump_json())
|
||||
if hasattr(v, "uuid"):
|
||||
ai_data["uuid"] = str(v.uuid)
|
||||
else:
|
||||
@ -3555,7 +3599,7 @@ class Setting(EnviPathModel):
|
||||
)
|
||||
|
||||
rule_packages = models.ManyToManyField(
|
||||
"Package",
|
||||
s.PACKAGE_IMPLEMENTATION,
|
||||
verbose_name="Setting Rule Packages",
|
||||
related_name="setting_rule_packages",
|
||||
blank=True,
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import csv
|
||||
import io
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable, List, Optional
|
||||
from uuid import uuid4
|
||||
|
||||
from celery import shared_task
|
||||
from celery.utils.functional import LRUCache
|
||||
from django.utils import timezone
|
||||
from django.conf import settings as s
|
||||
|
||||
from epdb.logic import SPathway
|
||||
from epdb.models import Edge, EPModel, JobLog, Node, Package, Pathway, Rule, Setting, User
|
||||
from epdb.models import Edge, EPModel, JobLog, Node, Pathway, Rule, Setting, User
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
ML_CACHE = LRUCache(3) # Cache the three most recent ML models to reduce load times.
|
||||
@ -29,7 +32,7 @@ def dispatch_eager(user: "User", job: Callable, *args, **kwargs):
|
||||
log.task_id = uuid4()
|
||||
log.job_name = job.__name__
|
||||
log.status = "SUCCESS"
|
||||
log.done_at = timezone.now()
|
||||
log.done_at = datetime.now()
|
||||
log.task_result = str(x) if x else None
|
||||
log.save()
|
||||
|
||||
|
||||
15
epdb/urls.py
@ -48,7 +48,6 @@ urlpatterns = [
|
||||
re_path(r"^user$", v.users, name="users"),
|
||||
re_path(r"^group$", v.groups, name="groups"),
|
||||
re_path(r"^search$", v.search, name="search"),
|
||||
re_path(r"^predict$", v.predict_pathway, name="predict_pathway"),
|
||||
# User Detail
|
||||
re_path(rf"^user/(?P<user_uuid>{UUID})", v.user, name="user"),
|
||||
# Group Detail
|
||||
@ -142,11 +141,6 @@ urlpatterns = [
|
||||
v.package_pathway,
|
||||
name="package pathway detail",
|
||||
),
|
||||
re_path(
|
||||
rf"^package/(?P<package_uuid>{UUID})/predict$",
|
||||
v.package_predict_pathway,
|
||||
name="package predict pathway",
|
||||
),
|
||||
# Pathway Nodes
|
||||
re_path(
|
||||
rf"^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/node$",
|
||||
@ -199,13 +193,4 @@ urlpatterns = [
|
||||
re_path(r"^jobs", v.jobs, name="jobs"),
|
||||
# OAuth Stuff
|
||||
path("o/userinfo/", v.userinfo, name="oauth_userinfo"),
|
||||
# Static Pages
|
||||
re_path(r"^terms$", v.static_terms_of_use, name="terms_of_use"),
|
||||
re_path(r"^privacy$", v.static_privacy_policy, name="privacy_policy"),
|
||||
re_path(r"^cookie-policy$", v.static_cookie_policy, name="cookie_policy"),
|
||||
re_path(r"^about$", v.static_about_us, name="about_us"),
|
||||
re_path(r"^contact$", v.static_contact_support, name="contact_support"),
|
||||
re_path(r"^careers$", v.static_careers, name="careers"),
|
||||
re_path(r"^cite$", v.static_cite, name="cite"),
|
||||
re_path(r"^legal$", v.static_legal, name="legal"),
|
||||
]
|
||||
|
||||
295
epdb/views.py
@ -1,56 +1,56 @@
|
||||
import json
|
||||
import logging
|
||||
from typing import List, Dict, Any
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from django.conf import settings as s
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.http import JsonResponse, HttpResponse, HttpResponseNotAllowed, HttpResponseBadRequest
|
||||
from django.shortcuts import render, redirect
|
||||
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed, JsonResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from envipy_additional_information import NAME_MAPPING
|
||||
from oauth2_provider.decorators import protected_resource
|
||||
import nh3
|
||||
|
||||
from utilities.chem import FormatConverter, IndigoUtils
|
||||
from utilities.decorators import package_permission_required
|
||||
from utilities.misc import HTMLGenerator
|
||||
|
||||
from .logic import (
|
||||
EPDBURLParser,
|
||||
GroupManager,
|
||||
PackageManager,
|
||||
UserManager,
|
||||
SettingManager,
|
||||
SearchManager,
|
||||
EPDBURLParser,
|
||||
SettingManager,
|
||||
UserManager,
|
||||
)
|
||||
from .models import (
|
||||
Package,
|
||||
GroupPackagePermission,
|
||||
Group,
|
||||
CompoundStructure,
|
||||
APIToken,
|
||||
Compound,
|
||||
CompoundStructure,
|
||||
Edge,
|
||||
EnviFormer,
|
||||
EnzymeLink,
|
||||
EPModel,
|
||||
ExternalDatabase,
|
||||
ExternalIdentifier,
|
||||
Group,
|
||||
GroupPackagePermission,
|
||||
JobLog,
|
||||
License,
|
||||
MLRelativeReasoning,
|
||||
Node,
|
||||
Pathway,
|
||||
Permission,
|
||||
Reaction,
|
||||
Rule,
|
||||
Pathway,
|
||||
Node,
|
||||
EPModel,
|
||||
EnviFormer,
|
||||
MLRelativeReasoning,
|
||||
RuleBasedRelativeReasoning,
|
||||
Scenario,
|
||||
SimpleAmbitRule,
|
||||
APIToken,
|
||||
UserPackagePermission,
|
||||
Permission,
|
||||
License,
|
||||
User,
|
||||
Edge,
|
||||
ExternalDatabase,
|
||||
ExternalIdentifier,
|
||||
EnzymeLink,
|
||||
JobLog,
|
||||
UserPackagePermission,
|
||||
)
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -83,14 +83,9 @@ def login(request):
|
||||
return render(request, "static/login.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
from django.contrib.auth import authenticate
|
||||
from django.contrib.auth import login
|
||||
|
||||
username = request.POST.get("username").strip()
|
||||
if username != request.POST.get("username"):
|
||||
context["message"] = "Login failed!"
|
||||
return render(request, "static/login.html", context)
|
||||
from django.contrib.auth import authenticate, login
|
||||
|
||||
username = request.POST.get("username")
|
||||
password = request.POST.get("password")
|
||||
|
||||
# Get email for username and check if the account is active
|
||||
@ -105,7 +100,6 @@ def login(request):
|
||||
except get_user_model().DoesNotExist:
|
||||
context["message"] = "Login failed!"
|
||||
return render(request, "static/login.html", context)
|
||||
|
||||
try:
|
||||
user = authenticate(username=email, password=password)
|
||||
except Exception:
|
||||
@ -143,14 +137,9 @@ def register(request):
|
||||
context = get_base_context(request)
|
||||
|
||||
if request.method == "GET":
|
||||
# Redirect to unified login page with signup tab
|
||||
next_url = request.GET.get("next", "")
|
||||
redirect_url = reverse("login") + "#signup"
|
||||
|
||||
if next_url:
|
||||
redirect_url += f"?next={next_url}"
|
||||
|
||||
return redirect(redirect_url)
|
||||
context["title"] = "enviPath"
|
||||
context["next"] = request.GET.get("next", "")
|
||||
return render(request, "static/register.html", context)
|
||||
elif request.method == "POST":
|
||||
context["title"] = "enviPath"
|
||||
if next := request.POST.get("next"):
|
||||
@ -163,18 +152,18 @@ def register(request):
|
||||
|
||||
if not (username and email and password):
|
||||
context["message"] = "Invalid username/email/password"
|
||||
return render(request, "static/login.html", context)
|
||||
return render(request, "static/register.html", context)
|
||||
|
||||
if password != rpassword or password == "":
|
||||
context["message"] = "Registration failed, provided passwords differ!"
|
||||
return render(request, "static/login.html", context)
|
||||
return render(request, "static/register.html", context)
|
||||
|
||||
try:
|
||||
u = UserManager.create_user(username, email, password)
|
||||
logger.info(f"Created user {u.username} ({u.pk})")
|
||||
except Exception:
|
||||
context["message"] = "Registration failed! Couldn't create User Account."
|
||||
return render(request, "static/login.html", context)
|
||||
return render(request, "static/register.html", context)
|
||||
|
||||
if s.ADMIN_APPROVAL_REQUIRED:
|
||||
context["success_message"] = (
|
||||
@ -248,7 +237,6 @@ def get_base_context(request, for_user=None) -> Dict[str, Any]:
|
||||
"enabled_features": s.FLAGS,
|
||||
"debug": s.DEBUG,
|
||||
"external_databases": ExternalDatabase.get_databases(),
|
||||
"site_id": s.MATOMO_SITE_ID,
|
||||
},
|
||||
}
|
||||
|
||||
@ -362,34 +350,6 @@ def index(request):
|
||||
return render(request, "index/index.html", context)
|
||||
|
||||
|
||||
def predict_pathway(request):
|
||||
"""Top-level predict pathway view using user's default package."""
|
||||
if request.method != "GET":
|
||||
return HttpResponseNotAllowed(["GET"])
|
||||
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Predict Pathway"
|
||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||
|
||||
return render(request, "predict_pathway.html", context)
|
||||
|
||||
|
||||
@package_permission_required()
|
||||
def package_predict_pathway(request, package_uuid):
|
||||
"""Package-specific predict pathway view."""
|
||||
if request.method != "GET":
|
||||
return HttpResponseNotAllowed(["GET"])
|
||||
|
||||
current_user = _anonymous_or_real(request)
|
||||
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
|
||||
|
||||
context = get_base_context(request)
|
||||
context["title"] = f"enviPath - {current_package.name} - Predict Pathway"
|
||||
context["meta"]["current_package"] = current_package
|
||||
|
||||
return render(request, "predict_pathway.html", context)
|
||||
|
||||
|
||||
def packages(request):
|
||||
current_user = _anonymous_or_real(request)
|
||||
|
||||
@ -709,7 +669,7 @@ def search(request):
|
||||
|
||||
if request.method == "GET":
|
||||
package_urls = request.GET.getlist("packages")
|
||||
searchterm = request.GET.get("search", "").strip()
|
||||
searchterm = request.GET.get("search")
|
||||
mode = request.GET.get("mode")
|
||||
|
||||
# add HTTP_ACCEPT check to differentiate between index and ajax call
|
||||
@ -872,7 +832,7 @@ def package_models(request, package_uuid):
|
||||
request, "Invalid model type.", f'Model type "{model_type}" is not supported."'
|
||||
)
|
||||
|
||||
from .tasks import dispatch, build_model
|
||||
from .tasks import build_model, dispatch
|
||||
|
||||
dispatch(current_user, build_model, mod.pk)
|
||||
|
||||
@ -931,7 +891,7 @@ def package_model(request, package_uuid, model_uuid):
|
||||
return JsonResponse(res, safe=False)
|
||||
|
||||
else:
|
||||
app_domain_assessment = current_model.app_domain.assess(stand_smiles)
|
||||
app_domain_assessment = current_model.app_domain.assess(stand_smiles)[0]
|
||||
return JsonResponse(app_domain_assessment, safe=False)
|
||||
|
||||
context = get_base_context(request)
|
||||
@ -971,24 +931,12 @@ def package_model(request, package_uuid, model_uuid):
|
||||
]
|
||||
dispatch(current_user, evaluate_model, current_model.pk, multigen, eval_package_ids)
|
||||
|
||||
return redirect(current_model.url)
|
||||
elif hidden == "retrain":
|
||||
from .tasks import dispatch, retrain
|
||||
|
||||
dispatch(current_user, retrain, current_model.pk)
|
||||
|
||||
return redirect(current_model.url)
|
||||
else:
|
||||
return HttpResponseBadRequest()
|
||||
else:
|
||||
# TODO: Move cleaning to property updater
|
||||
name = request.POST.get("model-name")
|
||||
if name is not None:
|
||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
description = request.POST.get("model-description")
|
||||
if description is not None:
|
||||
description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
name = request.POST.get("model-name", "").strip()
|
||||
description = request.POST.get("model-description", "").strip()
|
||||
|
||||
if any([name, description]):
|
||||
if name:
|
||||
@ -1090,23 +1038,17 @@ def package(request, package_uuid):
|
||||
else:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
# TODO: Move cleaning to property updater
|
||||
new_package_name = request.POST.get("package-name")
|
||||
if new_package_name is not None:
|
||||
new_package_name = nh3.clean(new_package_name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
new_package_description = request.POST.get("package-description")
|
||||
if new_package_description is not None:
|
||||
new_package_description = nh3.clean(
|
||||
new_package_description, tags=s.ALLOWED_HTML_TAGS
|
||||
).strip()
|
||||
|
||||
grantee_url = request.POST.get("grantee")
|
||||
read = request.POST.get("read") == "on"
|
||||
write = request.POST.get("write") == "on"
|
||||
owner = request.POST.get("owner") == "on"
|
||||
|
||||
cc_string = request.POST.get("license")
|
||||
license = request.POST.get("license")
|
||||
license_link = request.POST.get("license-link")
|
||||
license_image_link = request.POST.get("license-image-link")
|
||||
|
||||
if new_package_name:
|
||||
current_package.name = new_package_name
|
||||
@ -1134,15 +1076,24 @@ def package(request, package_uuid):
|
||||
|
||||
PackageManager.update_permissions(current_user, current_package, grantee, max_perm)
|
||||
return redirect(current_package.url)
|
||||
elif license is not None:
|
||||
if license == "no-license":
|
||||
if current_package.license is not None:
|
||||
current_package.license.delete()
|
||||
|
||||
elif cc_string is not None:
|
||||
cc_string = cc_string.strip()
|
||||
if cc_string == "no-license": # Reset the package's license
|
||||
current_package.license = None
|
||||
current_package.save()
|
||||
return redirect(current_package.url)
|
||||
else: # Get the license and assign it to the package
|
||||
current_package.license = License.objects.get(cc_string=cc_string)
|
||||
else:
|
||||
if current_package.license is not None:
|
||||
current_package.license.delete()
|
||||
|
||||
license = License()
|
||||
license.link = license_link
|
||||
license.image_link = license_image_link
|
||||
license.save()
|
||||
|
||||
current_package.license = license
|
||||
current_package.save()
|
||||
|
||||
return redirect(current_package.url)
|
||||
@ -1250,16 +1201,8 @@ def package_compound(request, package_uuid, compound_uuid):
|
||||
|
||||
return JsonResponse({"success": current_compound.url})
|
||||
|
||||
# TODO: Move cleaning to property updater
|
||||
new_compound_name = request.POST.get("compound-name")
|
||||
if new_compound_name is not None:
|
||||
new_compound_name = nh3.clean(new_compound_name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
new_compound_description = request.POST.get("compound-description")
|
||||
if new_compound_description is not None:
|
||||
new_compound_description = nh3.clean(
|
||||
new_compound_description, tags=s.ALLOWED_HTML_TAGS
|
||||
).strip()
|
||||
new_compound_name = request.POST.get("compound-name", "").strip()
|
||||
new_compound_description = request.POST.get("compound-description", "").strip()
|
||||
|
||||
if new_compound_name:
|
||||
current_compound.name = new_compound_name
|
||||
@ -1395,16 +1338,8 @@ def package_compound_structure(request, package_uuid, compound_uuid, structure_u
|
||||
else:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
# TODO: Move cleaning to property updater
|
||||
new_structure_name = request.POST.get("compound-structure-name")
|
||||
if new_structure_name is not None:
|
||||
new_structure_name = nh3.clean(new_structure_name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
new_structure_description = request.POST.get("compound-structure-description")
|
||||
if new_structure_description is not None:
|
||||
new_structure_description = nh3.clean(
|
||||
new_structure_description, tags=s.ALLOWED_HTML_TAGS
|
||||
).strip()
|
||||
new_structure_name = request.POST.get("compound-structure-name", "").strip()
|
||||
new_structure_description = request.POST.get("compound-structure-description", "").strip()
|
||||
|
||||
if new_structure_name:
|
||||
current_structure.name = new_structure_name
|
||||
@ -1611,14 +1546,8 @@ def package_rule(request, package_uuid, rule_uuid):
|
||||
|
||||
return JsonResponse({"success": current_rule.url})
|
||||
|
||||
# TODO: Move cleaning to property updater
|
||||
rule_name = request.POST.get("rule-name")
|
||||
if rule_name is not None:
|
||||
rule_name = nh3.clean(rule_name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
rule_description = request.POST.get("rule-description")
|
||||
if rule_description is not None:
|
||||
rule_description = nh3.clean(rule_description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
rule_name = request.POST.get("rule-name", "").strip()
|
||||
rule_description = request.POST.get("rule-description", "").strip()
|
||||
|
||||
if rule_name:
|
||||
current_rule.name = rule_name
|
||||
@ -1708,6 +1637,7 @@ def package_reactions(request, package_uuid):
|
||||
reaction_name = request.POST.get("reaction-name")
|
||||
reaction_description = request.POST.get("reaction-description")
|
||||
reactions_smirks = request.POST.get("reaction-smirks")
|
||||
|
||||
educts = reactions_smirks.split(">>")[0].split(".")
|
||||
products = reactions_smirks.split(">>")[1].split(".")
|
||||
|
||||
@ -1768,16 +1698,8 @@ def package_reaction(request, package_uuid, reaction_uuid):
|
||||
|
||||
return JsonResponse({"success": current_reaction.url})
|
||||
|
||||
# TODO: Move cleaning to property updater
|
||||
new_reaction_name = request.POST.get("reaction-name")
|
||||
if new_reaction_name is not None:
|
||||
new_reaction_name = nh3.clean(new_reaction_name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
new_reaction_description = request.POST.get("reaction-description")
|
||||
if new_reaction_description is not None:
|
||||
new_reaction_description = nh3.clean(
|
||||
new_reaction_description, tags=s.ALLOWED_HTML_TAGS
|
||||
).strip()
|
||||
new_reaction_name = request.POST.get("reaction-name", "").strip()
|
||||
new_reaction_description = request.POST.get("reaction-description", "").strip()
|
||||
|
||||
if new_reaction_name:
|
||||
current_reaction.name = new_reaction_name
|
||||
@ -1854,9 +1776,8 @@ def package_pathways(request, package_uuid):
|
||||
|
||||
name = request.POST.get("name")
|
||||
description = request.POST.get("description")
|
||||
|
||||
smiles = request.POST.get("smiles", "").strip()
|
||||
pw_mode = request.POST.get("predict", "predict").strip()
|
||||
smiles = request.POST.get("smiles", "").strip()
|
||||
|
||||
if "smiles" in request.POST and smiles == "":
|
||||
return error(
|
||||
@ -1865,6 +1786,8 @@ def package_pathways(request, package_uuid):
|
||||
"Pathway prediction failed due to missing or empty SMILES",
|
||||
)
|
||||
|
||||
smiles = smiles.strip()
|
||||
|
||||
try:
|
||||
stand_smiles = FormatConverter.standardize(smiles)
|
||||
except ValueError:
|
||||
@ -2023,14 +1946,8 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
||||
|
||||
return JsonResponse({"success": current_pathway.url})
|
||||
|
||||
# TODO: Move cleaning to property updater
|
||||
pathway_name = request.POST.get("pathway-name")
|
||||
if pathway_name is not None:
|
||||
pathway_name = nh3.clean(pathway_name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
pathway_description = request.POST.get("pathway-description")
|
||||
if pathway_description is not None:
|
||||
pathway_description = nh3.clean(pathway_description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
if any([pathway_name, pathway_description]):
|
||||
if pathway_name is not None and pathway_name.strip() != "":
|
||||
@ -2118,8 +2035,8 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
|
||||
elif request.method == "POST":
|
||||
node_name = request.POST.get("node-name")
|
||||
node_description = request.POST.get("node-description")
|
||||
node_smiles = request.POST.get("node-smiles")
|
||||
|
||||
node_smiles = request.POST.get("node-smiles").strip()
|
||||
current_pathway.add_node(node_smiles, name=node_name, description=node_description)
|
||||
|
||||
return redirect(current_pathway.url)
|
||||
@ -2284,7 +2201,6 @@ def package_pathway_edges(request, package_uuid, pathway_uuid):
|
||||
|
||||
edge_name = request.POST.get("edge-name")
|
||||
edge_description = request.POST.get("edge-description")
|
||||
|
||||
edge_substrates = request.POST.getlist("edge-substrates")
|
||||
edge_products = request.POST.getlist("edge-products")
|
||||
|
||||
@ -2371,7 +2287,7 @@ def package_scenarios(request, package_uuid):
|
||||
"all", False
|
||||
):
|
||||
scens = Scenario.objects.filter(package=current_package).order_by("name")
|
||||
res = [{"name": s_.name, "url": s_.url, "uuid": s_.uuid} for s_ in scens]
|
||||
res = [{"name": s.name, "url": s.url, "uuid": s.uuid} for s in scens]
|
||||
return JsonResponse(res, safe=False)
|
||||
|
||||
context = get_base_context(request)
|
||||
@ -2409,9 +2325,9 @@ def package_scenarios(request, package_uuid):
|
||||
context["unreviewed_objects"] = unreviewed_scenario_qs
|
||||
|
||||
from envipy_additional_information import (
|
||||
SEDIMENT_ADDITIONAL_INFORMATION,
|
||||
SLUDGE_ADDITIONAL_INFORMATION,
|
||||
SOIL_ADDITIONAL_INFORMATION,
|
||||
SEDIMENT_ADDITIONAL_INFORMATION,
|
||||
)
|
||||
|
||||
context["scenario_types"] = {
|
||||
@ -2419,21 +2335,21 @@ def package_scenarios(request, package_uuid):
|
||||
"name": "soil",
|
||||
"widgets": [
|
||||
HTMLGenerator.generate_html(ai, prefix=f"soil_{0}")
|
||||
for ai in [x for sv in SOIL_ADDITIONAL_INFORMATION.values() for x in sv]
|
||||
for ai in [x for s in SOIL_ADDITIONAL_INFORMATION.values() for x in s]
|
||||
],
|
||||
},
|
||||
"Sludge Data": {
|
||||
"name": "sludge",
|
||||
"widgets": [
|
||||
HTMLGenerator.generate_html(ai, prefix=f"sludge_{0}")
|
||||
for ai in [x for sv in SLUDGE_ADDITIONAL_INFORMATION.values() for x in sv]
|
||||
for ai in [x for s in SLUDGE_ADDITIONAL_INFORMATION.values() for x in s]
|
||||
],
|
||||
},
|
||||
"Water-Sediment System Data": {
|
||||
"name": "sediment",
|
||||
"widgets": [
|
||||
HTMLGenerator.generate_html(ai, prefix=f"sediment_{0}")
|
||||
for ai in [x for sv in SEDIMENT_ADDITIONAL_INFORMATION.values() for x in sv]
|
||||
for ai in [x for s in SEDIMENT_ADDITIONAL_INFORMATION.values() for x in s]
|
||||
],
|
||||
},
|
||||
}
|
||||
@ -2448,7 +2364,6 @@ def package_scenarios(request, package_uuid):
|
||||
|
||||
scenario_name = request.POST.get("scenario-name")
|
||||
scenario_description = request.POST.get("scenario-description")
|
||||
|
||||
scenario_date_year = request.POST.get("scenario-date-year")
|
||||
scenario_date_month = request.POST.get("scenario-date-month")
|
||||
scenario_date_day = request.POST.get("scenario-date-day")
|
||||
@ -2462,9 +2377,9 @@ def package_scenarios(request, package_uuid):
|
||||
scenario_type = request.POST.get("scenario-type")
|
||||
|
||||
additional_information = HTMLGenerator.build_models(request.POST.dict())
|
||||
additional_information = [x for sv in additional_information.values() for x in sv]
|
||||
additional_information = [x for s in additional_information.values() for x in s]
|
||||
|
||||
new_scen = Scenario.create(
|
||||
s = Scenario.create(
|
||||
current_package,
|
||||
name=scenario_name,
|
||||
description=scenario_description,
|
||||
@ -2473,7 +2388,7 @@ def package_scenarios(request, package_uuid):
|
||||
additional_information=additional_information,
|
||||
)
|
||||
|
||||
return redirect(new_scen.url)
|
||||
return redirect(s.url)
|
||||
else:
|
||||
return HttpResponseNotAllowed(
|
||||
[
|
||||
@ -2773,7 +2688,6 @@ def settings(request):
|
||||
|
||||
name = request.POST.get("prediction-setting-name")
|
||||
description = request.POST.get("prediction-setting-description")
|
||||
|
||||
new_default = request.POST.get("prediction-setting-new-default", "off") == "on"
|
||||
|
||||
max_nodes = min(
|
||||
@ -2924,60 +2838,3 @@ def userinfo(request):
|
||||
"email_verified": user.is_active,
|
||||
}
|
||||
return JsonResponse(res)
|
||||
|
||||
|
||||
# Static Pages
|
||||
def static_terms_of_use(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Terms of Use"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/terms_of_use.html", context)
|
||||
|
||||
|
||||
def static_privacy_policy(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Privacy Policy"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/privacy_policy.html", context)
|
||||
|
||||
|
||||
def static_cookie_policy(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Cookie Policy"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/cookie_policy.html", context)
|
||||
|
||||
|
||||
def static_about_us(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - About Us"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/about_us.html", context)
|
||||
|
||||
|
||||
def static_contact_support(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Contact & Support"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/contact.html", context)
|
||||
|
||||
|
||||
def static_careers(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Careers"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/careers.html", context)
|
||||
|
||||
|
||||
def static_cite(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - How to Cite"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/cite.html", context)
|
||||
|
||||
|
||||
def static_legal(request):
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Legal Information"
|
||||
context["public_mode"] = True
|
||||
return render(request, "static/legal.html", context)
|
||||
|
||||
@ -1,22 +1,19 @@
|
||||
import gzip
|
||||
import json
|
||||
import logging
|
||||
import os.path
|
||||
from datetime import datetime
|
||||
|
||||
from django.conf import settings as s
|
||||
from django.http import HttpResponseNotAllowed
|
||||
from django.shortcuts import render
|
||||
|
||||
from epdb.logic import PackageManager
|
||||
from epdb.models import Rule, SimpleAmbitRule, Package, CompoundStructure
|
||||
from epdb.views import get_base_context, _anonymous_or_real
|
||||
from utilities.chem import FormatConverter
|
||||
|
||||
|
||||
from rdkit import Chem
|
||||
from rdkit.Chem.MolStandardize import rdMolStandardize
|
||||
|
||||
from epdb.models import CompoundStructure, Rule, SimpleAmbitRule
|
||||
from epdb.views import get_base_context
|
||||
from utilities.chem import FormatConverter
|
||||
|
||||
Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -59,9 +56,7 @@ def run_both_engines(SMILES, SMIRKS):
|
||||
set(
|
||||
[
|
||||
normalize_smiles(str(x))
|
||||
for x in FormatConverter.sanitize_smiles(
|
||||
[str(s) for s in all_rdkit_prods]
|
||||
)[0]
|
||||
for x in FormatConverter.sanitize_smiles([str(s) for s in all_rdkit_prods])[0]
|
||||
]
|
||||
)
|
||||
)
|
||||
@ -85,8 +80,7 @@ def migration(request):
|
||||
url="http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1"
|
||||
)
|
||||
ALL_SMILES = [
|
||||
cs.smiles
|
||||
for cs in CompoundStructure.objects.filter(compound__package=BBD)
|
||||
cs.smiles for cs in CompoundStructure.objects.filter(compound__package=BBD)
|
||||
]
|
||||
RULES = SimpleAmbitRule.objects.filter(package=BBD)
|
||||
|
||||
@ -142,9 +136,7 @@ def migration(request):
|
||||
)
|
||||
|
||||
for r in migration_status["results"]:
|
||||
r["detail_url"] = r["detail_url"].replace(
|
||||
"http://localhost:8000", s.SERVER_URL
|
||||
)
|
||||
r["detail_url"] = r["detail_url"].replace("http://localhost:8000", s.SERVER_URL)
|
||||
|
||||
context.update(**migration_status)
|
||||
|
||||
@ -152,8 +144,6 @@ def migration(request):
|
||||
|
||||
|
||||
def migration_detail(request, package_uuid, rule_uuid):
|
||||
current_user = _anonymous_or_real(request)
|
||||
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
|
||||
@ -235,9 +225,7 @@ def compare(request):
|
||||
context["smirks"] = (
|
||||
"[#1,#6:6][#7;X3;!$(NC1CC1)!$([N][C]=O)!$([!#8]CNC=O):1]([#1,#6:7])[#6;A;X4:2][H:3]>>[#1,#6:6][#7;X3:1]([#1,#6:7])[H:3].[#6;A:2]=O"
|
||||
)
|
||||
context["smiles"] = (
|
||||
"C(CC(=O)N[C@@H](CS[Se-])C(=O)NCC(=O)[O-])[C@@H](C(=O)[O-])N"
|
||||
)
|
||||
context["smiles"] = "C(CC(=O)N[C@@H](CS[Se-])C(=O)NCC(=O)[O-])[C@@H](C(=O)[O-])N"
|
||||
return render(request, "compare.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
|
||||
25
package.json
@ -1,25 +0,0 @@
|
||||
{
|
||||
"name": "envipy",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"description": "enviPath UI - Tailwind CSS + DaisyUI",
|
||||
"scripts": {
|
||||
"dev": "tailwindcss -i static/css/input.css -o static/css/output.css --watch=always",
|
||||
"build": "tailwindcss -i static/css/input.css -o static/css/output.css --minify"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/cli": "^4.1.16",
|
||||
"@tailwindcss/postcss": "^4.1.16",
|
||||
"daisyui": "^5.4.3",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-jinja-template": "^2.1.0",
|
||||
"prettier-plugin-tailwindcss": "^0.7.1",
|
||||
"tailwindcss": "^4.1.16"
|
||||
},
|
||||
"keywords": [
|
||||
"django",
|
||||
"tailwindcss",
|
||||
"daisyui"
|
||||
]
|
||||
}
|
||||
740
pnpm-lock.yaml
generated
@ -1,740 +0,0 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
devDependencies:
|
||||
'@tailwindcss/cli':
|
||||
specifier: ^4.1.16
|
||||
version: 4.1.16
|
||||
'@tailwindcss/postcss':
|
||||
specifier: ^4.1.16
|
||||
version: 4.1.16
|
||||
daisyui:
|
||||
specifier: ^5.4.3
|
||||
version: 5.4.3
|
||||
postcss:
|
||||
specifier: ^8.5.6
|
||||
version: 8.5.6
|
||||
prettier:
|
||||
specifier: ^3.6.2
|
||||
version: 3.6.2
|
||||
prettier-plugin-jinja-template:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(prettier@3.6.2)
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1(prettier@3.6.2)
|
||||
tailwindcss:
|
||||
specifier: ^4.1.16
|
||||
version: 4.1.16
|
||||
|
||||
packages:
|
||||
|
||||
'@alloc/quick-lru@5.2.0':
|
||||
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||
|
||||
'@jridgewell/remapping@2.3.5':
|
||||
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2':
|
||||
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.1':
|
||||
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@parcel/watcher-darwin-arm64@2.5.1':
|
||||
resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@parcel/watcher-darwin-x64@2.5.1':
|
||||
resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@parcel/watcher-freebsd-x64@2.5.1':
|
||||
resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@parcel/watcher-linux-arm-glibc@2.5.1':
|
||||
resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.1':
|
||||
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
||||
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
||||
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
||||
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-linux-x64-musl@2.5.1':
|
||||
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@parcel/watcher-win32-arm64@2.5.1':
|
||||
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@parcel/watcher-win32-ia32@2.5.1':
|
||||
resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@parcel/watcher-win32-x64@2.5.1':
|
||||
resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@parcel/watcher@2.5.1':
|
||||
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
'@tailwindcss/cli@4.1.16':
|
||||
resolution: {integrity: sha512-dsnANPrh2ZooHyZ/8uJhc9ecpcYtufToc21NY09NS9vF16rxPCjJ8dP7TUAtPqlUJTHSmRkN2hCdoYQIlgh4fw==}
|
||||
hasBin: true
|
||||
|
||||
'@tailwindcss/node@4.1.16':
|
||||
resolution: {integrity: sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==}
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.1.16':
|
||||
resolution: {integrity: sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.1.16':
|
||||
resolution: {integrity: sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.1.16':
|
||||
resolution: {integrity: sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.1.16':
|
||||
resolution: {integrity: sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16':
|
||||
resolution: {integrity: sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.1.16':
|
||||
resolution: {integrity: sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.16':
|
||||
resolution: {integrity: sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.16':
|
||||
resolution: {integrity: sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.16':
|
||||
resolution: {integrity: sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.16':
|
||||
resolution: {integrity: sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
bundledDependencies:
|
||||
- '@napi-rs/wasm-runtime'
|
||||
- '@emnapi/core'
|
||||
- '@emnapi/runtime'
|
||||
- '@tybys/wasm-util'
|
||||
- '@emnapi/wasi-threads'
|
||||
- tslib
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.1.16':
|
||||
resolution: {integrity: sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.1.16':
|
||||
resolution: {integrity: sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide@4.1.16':
|
||||
resolution: {integrity: sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@tailwindcss/postcss@4.1.16':
|
||||
resolution: {integrity: sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A==}
|
||||
|
||||
braces@3.0.3:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
daisyui@5.4.3:
|
||||
resolution: {integrity: sha512-dfDCJnN4utErGoWfElgdEE252FtfHV9Mxj5Dq1+JzUq3nVkluWdF3JYykP0Xy/y/yArnPXYztO1tLNCow3kjmg==}
|
||||
|
||||
detect-libc@1.0.3:
|
||||
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
|
||||
engines: {node: '>=0.10'}
|
||||
hasBin: true
|
||||
|
||||
detect-libc@2.1.2:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
enhanced-resolve@5.18.3:
|
||||
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
fill-range@7.1.1:
|
||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
graceful-fs@4.2.11:
|
||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||
|
||||
is-extglob@2.1.1:
|
||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-number@7.0.0:
|
||||
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
||||
jiti@2.6.1:
|
||||
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
|
||||
hasBin: true
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
lightningcss-darwin-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-darwin-x64@1.30.2:
|
||||
resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
lightningcss-freebsd-x64@1.30.2:
|
||||
resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||
resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss-win32-x64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
lightningcss@1.30.2:
|
||||
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
micromatch@4.0.8:
|
||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
mri@1.2.0:
|
||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
nanoid@3.3.11:
|
||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
node-addon-api@7.1.1:
|
||||
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
picomatch@2.3.1:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
prettier-plugin-jinja-template@2.1.0:
|
||||
resolution: {integrity: sha512-mzoCp2Oy9BDSug80fw3B3J4n4KQj1hRvoQOL1akqcDKBb5nvYxrik9zUEDs4AEJ6nK7QDTGoH0y9rx7AlnQ78Q==}
|
||||
peerDependencies:
|
||||
prettier: ^3.0.0
|
||||
|
||||
prettier-plugin-tailwindcss@0.7.1:
|
||||
resolution: {integrity: sha512-Bzv1LZcuiR1Sk02iJTS1QzlFNp/o5l2p3xkopwOrbPmtMeh3fK9rVW5M3neBQzHq+kGKj/4LGQMTNcTH4NGPtQ==}
|
||||
engines: {node: '>=20.19'}
|
||||
peerDependencies:
|
||||
'@ianvs/prettier-plugin-sort-imports': '*'
|
||||
'@prettier/plugin-hermes': '*'
|
||||
'@prettier/plugin-oxc': '*'
|
||||
'@prettier/plugin-pug': '*'
|
||||
'@shopify/prettier-plugin-liquid': '*'
|
||||
'@trivago/prettier-plugin-sort-imports': '*'
|
||||
'@zackad/prettier-plugin-twig': '*'
|
||||
prettier: ^3.0
|
||||
prettier-plugin-astro: '*'
|
||||
prettier-plugin-css-order: '*'
|
||||
prettier-plugin-jsdoc: '*'
|
||||
prettier-plugin-marko: '*'
|
||||
prettier-plugin-multiline-arrays: '*'
|
||||
prettier-plugin-organize-attributes: '*'
|
||||
prettier-plugin-organize-imports: '*'
|
||||
prettier-plugin-sort-imports: '*'
|
||||
prettier-plugin-svelte: '*'
|
||||
peerDependenciesMeta:
|
||||
'@ianvs/prettier-plugin-sort-imports':
|
||||
optional: true
|
||||
'@prettier/plugin-hermes':
|
||||
optional: true
|
||||
'@prettier/plugin-oxc':
|
||||
optional: true
|
||||
'@prettier/plugin-pug':
|
||||
optional: true
|
||||
'@shopify/prettier-plugin-liquid':
|
||||
optional: true
|
||||
'@trivago/prettier-plugin-sort-imports':
|
||||
optional: true
|
||||
'@zackad/prettier-plugin-twig':
|
||||
optional: true
|
||||
prettier-plugin-astro:
|
||||
optional: true
|
||||
prettier-plugin-css-order:
|
||||
optional: true
|
||||
prettier-plugin-jsdoc:
|
||||
optional: true
|
||||
prettier-plugin-marko:
|
||||
optional: true
|
||||
prettier-plugin-multiline-arrays:
|
||||
optional: true
|
||||
prettier-plugin-organize-attributes:
|
||||
optional: true
|
||||
prettier-plugin-organize-imports:
|
||||
optional: true
|
||||
prettier-plugin-sort-imports:
|
||||
optional: true
|
||||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
|
||||
prettier@3.6.2:
|
||||
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
tailwindcss@4.1.16:
|
||||
resolution: {integrity: sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==}
|
||||
|
||||
tapable@2.3.0:
|
||||
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@alloc/quick-lru@5.2.0': {}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
|
||||
'@jridgewell/remapping@2.3.5':
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.13
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2': {}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.31':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-darwin-arm64@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-darwin-x64@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-freebsd-x64@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm-glibc@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-x64-musl@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-win32-arm64@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-win32-ia32@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-win32-x64@2.5.1':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher@2.5.1':
|
||||
dependencies:
|
||||
detect-libc: 1.0.3
|
||||
is-glob: 4.0.3
|
||||
micromatch: 4.0.8
|
||||
node-addon-api: 7.1.1
|
||||
optionalDependencies:
|
||||
'@parcel/watcher-android-arm64': 2.5.1
|
||||
'@parcel/watcher-darwin-arm64': 2.5.1
|
||||
'@parcel/watcher-darwin-x64': 2.5.1
|
||||
'@parcel/watcher-freebsd-x64': 2.5.1
|
||||
'@parcel/watcher-linux-arm-glibc': 2.5.1
|
||||
'@parcel/watcher-linux-arm-musl': 2.5.1
|
||||
'@parcel/watcher-linux-arm64-glibc': 2.5.1
|
||||
'@parcel/watcher-linux-arm64-musl': 2.5.1
|
||||
'@parcel/watcher-linux-x64-glibc': 2.5.1
|
||||
'@parcel/watcher-linux-x64-musl': 2.5.1
|
||||
'@parcel/watcher-win32-arm64': 2.5.1
|
||||
'@parcel/watcher-win32-ia32': 2.5.1
|
||||
'@parcel/watcher-win32-x64': 2.5.1
|
||||
|
||||
'@tailwindcss/cli@4.1.16':
|
||||
dependencies:
|
||||
'@parcel/watcher': 2.5.1
|
||||
'@tailwindcss/node': 4.1.16
|
||||
'@tailwindcss/oxide': 4.1.16
|
||||
enhanced-resolve: 5.18.3
|
||||
mri: 1.2.0
|
||||
picocolors: 1.1.1
|
||||
tailwindcss: 4.1.16
|
||||
|
||||
'@tailwindcss/node@4.1.16':
|
||||
dependencies:
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
enhanced-resolve: 5.18.3
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.30.2
|
||||
magic-string: 0.30.21
|
||||
source-map-js: 1.2.1
|
||||
tailwindcss: 4.1.16
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.1.16':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide@4.1.16':
|
||||
optionalDependencies:
|
||||
'@tailwindcss/oxide-android-arm64': 4.1.16
|
||||
'@tailwindcss/oxide-darwin-arm64': 4.1.16
|
||||
'@tailwindcss/oxide-darwin-x64': 4.1.16
|
||||
'@tailwindcss/oxide-freebsd-x64': 4.1.16
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.16
|
||||
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.16
|
||||
'@tailwindcss/oxide-linux-arm64-musl': 4.1.16
|
||||
'@tailwindcss/oxide-linux-x64-gnu': 4.1.16
|
||||
'@tailwindcss/oxide-linux-x64-musl': 4.1.16
|
||||
'@tailwindcss/oxide-wasm32-wasi': 4.1.16
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.16
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.1.16
|
||||
|
||||
'@tailwindcss/postcss@4.1.16':
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
'@tailwindcss/node': 4.1.16
|
||||
'@tailwindcss/oxide': 4.1.16
|
||||
postcss: 8.5.6
|
||||
tailwindcss: 4.1.16
|
||||
|
||||
braces@3.0.3:
|
||||
dependencies:
|
||||
fill-range: 7.1.1
|
||||
|
||||
daisyui@5.4.3: {}
|
||||
|
||||
detect-libc@1.0.3: {}
|
||||
|
||||
detect-libc@2.1.2: {}
|
||||
|
||||
enhanced-resolve@5.18.3:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
tapable: 2.3.0
|
||||
|
||||
fill-range@7.1.1:
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
is-extglob@2.1.1: {}
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
|
||||
is-number@7.0.0: {}
|
||||
|
||||
jiti@2.6.1: {}
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-arm64@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-darwin-x64@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-freebsd-x64@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss-win32-x64-msvc@1.30.2:
|
||||
optional: true
|
||||
|
||||
lightningcss@1.30.2:
|
||||
dependencies:
|
||||
detect-libc: 2.1.2
|
||||
optionalDependencies:
|
||||
lightningcss-android-arm64: 1.30.2
|
||||
lightningcss-darwin-arm64: 1.30.2
|
||||
lightningcss-darwin-x64: 1.30.2
|
||||
lightningcss-freebsd-x64: 1.30.2
|
||||
lightningcss-linux-arm-gnueabihf: 1.30.2
|
||||
lightningcss-linux-arm64-gnu: 1.30.2
|
||||
lightningcss-linux-arm64-musl: 1.30.2
|
||||
lightningcss-linux-x64-gnu: 1.30.2
|
||||
lightningcss-linux-x64-musl: 1.30.2
|
||||
lightningcss-win32-arm64-msvc: 1.30.2
|
||||
lightningcss-win32-x64-msvc: 1.30.2
|
||||
|
||||
magic-string@0.30.21:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
micromatch@4.0.8:
|
||||
dependencies:
|
||||
braces: 3.0.3
|
||||
picomatch: 2.3.1
|
||||
|
||||
mri@1.2.0: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
node-addon-api@7.1.1: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
postcss@8.5.6:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
prettier-plugin-jinja-template@2.1.0(prettier@3.6.2):
|
||||
dependencies:
|
||||
prettier: 3.6.2
|
||||
|
||||
prettier-plugin-tailwindcss@0.7.1(prettier@3.6.2):
|
||||
dependencies:
|
||||
prettier: 3.6.2
|
||||
|
||||
prettier@3.6.2: {}
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
tailwindcss@4.1.16: {}
|
||||
|
||||
tapable@2.3.0: {}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
0
public/__init__.py
Normal file
1
public/admin.py
Normal file
@ -0,0 +1 @@
|
||||
# Register your models here.
|
||||
6
public/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PublicConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "public"
|
||||
56
public/migrations/0001_initial.py
Normal file
@ -0,0 +1,56 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-29 13:32
|
||||
|
||||
import django.utils.timezone
|
||||
import model_utils.fields
|
||||
import uuid
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Package",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
model_utils.fields.AutoCreatedField(
|
||||
default=django.utils.timezone.now, editable=False, verbose_name="created"
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
model_utils.fields.AutoLastModifiedField(
|
||||
default=django.utils.timezone.now, editable=False, verbose_name="modified"
|
||||
),
|
||||
),
|
||||
(
|
||||
"uuid",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4, unique=True, verbose_name="UUID of this object"
|
||||
),
|
||||
),
|
||||
("name", models.TextField(default="no name", verbose_name="Name")),
|
||||
(
|
||||
"description",
|
||||
models.TextField(default="no description", verbose_name="Descriptions"),
|
||||
),
|
||||
("url", models.TextField(null=True, unique=True, verbose_name="URL")),
|
||||
("kv", models.JSONField(blank=True, default=dict, null=True)),
|
||||
("reviewed", models.BooleanField(default=False, verbose_name="Reviewstatus")),
|
||||
],
|
||||
options={
|
||||
"db_table": "epdb_package",
|
||||
"managed": False,
|
||||
},
|
||||
),
|
||||
]
|
||||
16
public/migrations/0002_alter_package_options.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-29 18:39
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("public", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="package",
|
||||
options={},
|
||||
),
|
||||
]
|
||||
25
public/migrations/0003_package_license.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-29 18:40
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("epdb", "0010_alter_userpackagepermission_package_and_more"),
|
||||
("public", "0002_alter_package_options"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="package",
|
||||
name="license",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="epdb.license",
|
||||
verbose_name="License",
|
||||
),
|
||||
),
|
||||
]
|
||||
0
public/migrations/__init__.py
Normal file
6
public/models.py
Normal file
@ -0,0 +1,6 @@
|
||||
from epdb.models import AbstractPackage
|
||||
|
||||
|
||||
class Package(AbstractPackage):
|
||||
class Meta:
|
||||
db_table = "epdb_package"
|
||||
1
public/tests.py
Normal file
@ -0,0 +1 @@
|
||||
# Create your tests here.
|
||||
1
public/views.py
Normal file
@ -0,0 +1 @@
|
||||
# Create your views here.
|
||||
@ -27,12 +27,10 @@ dependencies = [
|
||||
"scikit-learn>=1.6.1",
|
||||
"sentry-sdk[django]>=2.32.0",
|
||||
"setuptools>=80.8.0",
|
||||
"nh3==0.3.2",
|
||||
"polars==1.35.1",
|
||||
]
|
||||
|
||||
[tool.uv.sources]
|
||||
enviformer = { git = "ssh://git@git.envipath.com/enviPath/enviformer.git", rev = "v0.1.4" }
|
||||
enviformer = { git = "ssh://git@git.envipath.com/enviPath/enviformer.git", rev = "v0.1.2" }
|
||||
envipy-plugins = { git = "ssh://git@git.envipath.com/enviPath/enviPy-plugins.git", rev = "v0.1.0" }
|
||||
envipy-additional-information = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git", rev = "v0.1.7"}
|
||||
envipy-ambit = { git = "ssh://git@git.envipath.com/enviPath/enviPy-ambit.git" }
|
||||
@ -67,54 +65,22 @@ docstring-code-format = true
|
||||
[tool.poe.tasks]
|
||||
# Main tasks
|
||||
setup = { sequence = ["db-up", "migrate", "bootstrap"], help = "Complete setup: start database, run migrations, and bootstrap data" }
|
||||
dev = { shell = """
|
||||
# Start pnpm CSS watcher in background
|
||||
pnpm run dev &
|
||||
PNPM_PID=$!
|
||||
echo "Started CSS watcher (PID: $PNPM_PID)"
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
echo "\nShutting down..."
|
||||
if kill -0 $PNPM_PID 2>/dev/null; then
|
||||
kill $PNPM_PID
|
||||
echo "✓ CSS watcher stopped"
|
||||
fi
|
||||
if [ ! -z "${DJ_PID:-}" ] && kill -0 $DJ_PID 2>/dev/null; then
|
||||
kill $DJ_PID
|
||||
echo "✓ Django server stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
# Set trap for cleanup
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Start Django dev server in background
|
||||
uv run python manage.py runserver &
|
||||
DJ_PID=$!
|
||||
|
||||
# Wait for Django to finish
|
||||
wait $DJ_PID
|
||||
""", help = "Start the development server with CSS watcher", deps = ["db-up", "js-deps"] }
|
||||
build = { sequence = ["build-frontend", "collectstatic"], help = "Build frontend assets and collect static files" }
|
||||
dev = { cmd = "python manage.py runserver", help = "Start the development server", deps = ["db-up"] }
|
||||
|
||||
# Database tasks
|
||||
db-up = { cmd = "docker compose -f docker-compose.dev.yml up -d", help = "Start PostgreSQL database using Docker Compose" }
|
||||
db-down = { cmd = "docker compose -f docker-compose.dev.yml down", help = "Stop PostgreSQL database" }
|
||||
|
||||
# Frontend tasks
|
||||
js-deps = { cmd = "pnpm install", help = "Install frontend dependencies" }
|
||||
|
||||
# Full cleanup tasks
|
||||
clean = { sequence = ["clean-db"], help = "Remove model files and database volumes (WARNING: destroys all data!)" }
|
||||
clean-db = { cmd = "docker compose -f docker-compose.dev.yml down -v", help = "Removes the database container and volume." }
|
||||
|
||||
# Django tasks
|
||||
migrate = { cmd = "uv run python manage.py migrate", help = "Run database migrations" }
|
||||
migrate = { cmd = "python manage.py migrate", help = "Run database migrations" }
|
||||
bootstrap = { shell = """
|
||||
echo "Bootstrapping initial data..."
|
||||
echo "This will take a bit ⏱️. Get yourself some coffee..."
|
||||
uv run python manage.py bootstrap
|
||||
python manage.py bootstrap
|
||||
echo "✓ Bootstrap complete"
|
||||
echo ""
|
||||
echo "Default admin credentials:"
|
||||
@ -122,8 +88,4 @@ echo " Username: admin"
|
||||
echo " Email: admin@envipath.com"
|
||||
echo " Password: SuperSafe"
|
||||
""", help = "Bootstrap initial data (anonymous user, packages, models)" }
|
||||
shell = { cmd = "uv run python manage.py shell", help = "Open Django shell" }
|
||||
|
||||
# Build tasks
|
||||
build-frontend = { cmd = "pnpm run build", help = "Build frontend assets using pnpm", deps = ["js-deps"] }
|
||||
collectstatic = { cmd = "uv run python manage.py collectstatic --noinput", help = "Collect static files for production", deps = ["build-frontend"] }
|
||||
shell = { cmd = "python manage.py shell", help = "Open Django shell" }
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
/**
|
||||
* DaisyUI Themes - Generated by Style Dictionary
|
||||
* Theme mappings defined in tokens/daisyui-themes.json
|
||||
*/
|
||||
|
||||
/* Light theme (default) */
|
||||
@plugin "daisyui/theme" {
|
||||
name: "envipath";
|
||||
default: true;
|
||||
color-scheme: light;
|
||||
|
||||
--color-base-100: var(--color-neutral-50);
|
||||
--color-base-200: var(--color-neutral-100);
|
||||
--color-base-300: var(--color-neutral-200);
|
||||
--color-base-content: var(--color-neutral-900);
|
||||
--color-primary: var(--color-primary-500);
|
||||
--color-primary-content: var(--color-primary-50);
|
||||
--color-secondary: var(--color-secondary-500);
|
||||
--color-secondary-content: var(--color-secondary-50);
|
||||
--color-accent: var(--color-accent-500);
|
||||
--color-accent-content: var(--color-accent-50);
|
||||
--color-neutral: var(--color-neutral-950);
|
||||
--color-neutral-content: var(--color-neutral-100);
|
||||
--color-info: var(--color-info-500);
|
||||
--color-info-content: var(--color-info-950);
|
||||
--color-success: var(--color-success-500);
|
||||
--color-success-content: var(--color-success-950);
|
||||
--color-warning: var(--color-warning-500);
|
||||
--color-warning-content: var(--color-warning-950);
|
||||
--color-error: var(--color-error-500);
|
||||
--color-error-content: var(--color-error-950);
|
||||
|
||||
/* border radius */
|
||||
--radius-selector: 1rem;
|
||||
--radius-field: 0.25rem;
|
||||
--radius-box: 0.5rem;
|
||||
|
||||
/* base sizes */
|
||||
--size-selector: 0.25rem;
|
||||
--size-field: 0.25rem;
|
||||
|
||||
/* border size */
|
||||
--border: 1px;
|
||||
|
||||
/* effects */
|
||||
--depth: 1;
|
||||
--noise: 0;
|
||||
}
|
||||
|
||||
/* Dark theme (prefers-color-scheme: dark) */
|
||||
@plugin "daisyui/theme" {
|
||||
name: "envipath-dark";
|
||||
prefersdark: true;
|
||||
color-scheme: dark;
|
||||
|
||||
--color-primary: var(--color-primary-400);
|
||||
--color-primary-content: var(--color-neutral-950);
|
||||
--color-secondary: var(--color-secondary-400);
|
||||
--color-secondary-content: var(--color-neutral-950);
|
||||
--color-accent: var(--color-primary-500);
|
||||
--color-accent-content: var(--color-neutral-950);
|
||||
--color-neutral: var(--color-neutral-300);
|
||||
--color-neutral-content: var(--color-neutral-900);
|
||||
--color-base-100: var(--color-neutral-900);
|
||||
--color-base-200: var(--color-neutral-800);
|
||||
--color-base-300: var(--color-neutral-700);
|
||||
--color-base-content: var(--color-neutral-50);
|
||||
--color-info: var(--color-primary-400);
|
||||
--color-info-content: var(--color-neutral-950);
|
||||
--color-success: var(--color-success-400);
|
||||
--color-success-content: var(--color-neutral-950);
|
||||
--color-warning: var(--color-warning-400);
|
||||
--color-warning-content: var(--color-neutral-950);
|
||||
--color-error: var(--color-error-400);
|
||||
--color-error-content: var(--color-neutral-950);
|
||||
--radius-selector: 1rem;
|
||||
--radius-field: 0.25rem;
|
||||
--radius-box: 0.5rem;
|
||||
--size-selector: 0.25rem;
|
||||
--size-field: 0.25rem;
|
||||
--border: 1px;
|
||||
--depth: 1;
|
||||
--noise: 0;
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/* fira-code-latin-wght-normal */
|
||||
@font-face {
|
||||
font-family: 'Fira Code Variable';
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-weight: 300 700;
|
||||
src: url(https://cdn.jsdelivr.net/fontsource/fonts/fira-code:vf@latest/latin-wght-normal.woff2) format('woff2-variations');
|
||||
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||
}
|
||||
|
||||
/* inter-latin-wght-normal */
|
||||
@font-face {
|
||||
font-family: 'Inter Variable';
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-weight: 100 900;
|
||||
src: url(https://cdn.jsdelivr.net/fontsource/fonts/inter:vf@latest/latin-wght-normal.woff2) format('woff2-variations');
|
||||
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||
}
|
||||
|
||||
|
||||
/* Tell Tailwind where to find Django templates and Python files */
|
||||
@source "../../templates";
|
||||
|
||||
/* Custom theme configuration - must come before plugins */
|
||||
@import "./theme.css";
|
||||
|
||||
/* Import DaisyUI plugin */
|
||||
@plugin "daisyui" {
|
||||
logs: true;
|
||||
exclude: rootscrollgutter;
|
||||
}
|
||||
|
||||
@import "./daisyui-theme.css";
|
||||
@ -1,111 +0,0 @@
|
||||
/**
|
||||
* Tailwind v4 Theme - Generated by Style Dictionary
|
||||
* This creates Tailwind utility classes from design tokens
|
||||
*/
|
||||
|
||||
@theme {
|
||||
/* Colors */
|
||||
--color-primary-50: oklch(0.98 0.02 201);
|
||||
--color-primary-100: oklch(0.96 0.04 203);
|
||||
--color-primary-200: oklch(0.92 0.08 205);
|
||||
--color-primary-300: oklch(0.87 0.12 207);
|
||||
--color-primary-400: oklch(0.80 0.13 212);
|
||||
--color-primary-500: oklch(0.71 0.13 215);
|
||||
--color-primary-600: oklch(0.61 0.11 222);
|
||||
--color-primary-700: oklch(0.52 0.09 223);
|
||||
--color-primary-800: oklch(0.45 0.08 224);
|
||||
--color-primary-900: oklch(0.40 0.07 227);
|
||||
--color-primary-950: oklch(0.30 0.05 230);
|
||||
--color-secondary-50: oklch(0.98 0.02 166);
|
||||
--color-secondary-100: oklch(0.95 0.05 163);
|
||||
--color-secondary-200: oklch(0.90 0.09 164);
|
||||
--color-secondary-300: oklch(0.85 0.13 165);
|
||||
--color-secondary-400: oklch(0.77 0.15 163);
|
||||
--color-secondary-500: oklch(0.70 0.15 162);
|
||||
--color-secondary-600: oklch(0.60 0.13 163);
|
||||
--color-secondary-700: oklch(0.51 0.10 166);
|
||||
--color-secondary-800: oklch(0.43 0.09 167);
|
||||
--color-secondary-900: oklch(0.38 0.07 169);
|
||||
--color-secondary-950: oklch(0.26 0.05 173);
|
||||
--color-success-50: oklch(0.98 0.02 156);
|
||||
--color-success-100: oklch(0.96 0.04 157);
|
||||
--color-success-200: oklch(0.93 0.08 156);
|
||||
--color-success-300: oklch(0.87 0.14 154);
|
||||
--color-success-400: oklch(0.80 0.18 152);
|
||||
--color-success-500: oklch(0.72 0.19 150);
|
||||
--color-success-600: oklch(0.63 0.17 149);
|
||||
--color-success-700: oklch(0.53 0.14 150);
|
||||
--color-success-800: oklch(0.45 0.11 151);
|
||||
--color-success-900: oklch(0.39 0.09 153);
|
||||
--color-success-950: oklch(0.27 0.06 153);
|
||||
--color-warning-50: oklch(0.99 0.03 102);
|
||||
--color-warning-100: oklch(0.97 0.07 103);
|
||||
--color-warning-200: oklch(0.95 0.12 102);
|
||||
--color-warning-300: oklch(0.91 0.17 98);
|
||||
--color-warning-400: oklch(0.86 0.17 92);
|
||||
--color-warning-500: oklch(0.80 0.16 86);
|
||||
--color-warning-600: oklch(0.68 0.14 76);
|
||||
--color-warning-700: oklch(0.55 0.12 66);
|
||||
--color-warning-800: oklch(0.48 0.10 62);
|
||||
--color-warning-900: oklch(0.42 0.09 58);
|
||||
--color-warning-950: oklch(0.29 0.06 54);
|
||||
--color-error-50: oklch(0.97 0.01 17);
|
||||
--color-error-100: oklch(0.94 0.03 18);
|
||||
--color-error-200: oklch(0.88 0.06 18);
|
||||
--color-error-300: oklch(0.81 0.10 20);
|
||||
--color-error-400: oklch(0.71 0.17 22);
|
||||
--color-error-500: oklch(0.64 0.21 25);
|
||||
--color-error-600: oklch(0.58 0.22 27);
|
||||
--color-error-700: oklch(0.51 0.19 28);
|
||||
--color-error-800: oklch(0.44 0.16 27);
|
||||
--color-error-900: oklch(0.40 0.13 26);
|
||||
--color-error-950: oklch(0.26 0.09 26);
|
||||
--color-neutral-50: oklch(0.98 0.00 248);
|
||||
--color-neutral-100: oklch(0.97 0.01 248);
|
||||
--color-neutral-200: oklch(0.93 0.01 256);
|
||||
--color-neutral-300: oklch(0.87 0.02 253);
|
||||
--color-neutral-400: oklch(0.71 0.04 257);
|
||||
--color-neutral-500: oklch(0.55 0.04 257);
|
||||
--color-neutral-600: oklch(0.45 0.04 257);
|
||||
--color-neutral-700: oklch(0.37 0.04 257);
|
||||
--color-neutral-800: oklch(0.28 0.04 260);
|
||||
--color-neutral-900: oklch(0.28 0.04 260);
|
||||
--color-neutral-950: oklch(0.28 0.04 260);
|
||||
|
||||
/* Spacing */
|
||||
--spacing-0: 0;
|
||||
--spacing-1: 0.25rem;
|
||||
--spacing-2: 0.5rem;
|
||||
--spacing-3: 0.75rem;
|
||||
--spacing-4: 1rem;
|
||||
--spacing-5: 1.25rem;
|
||||
--spacing-6: 1.5rem;
|
||||
--spacing-7: 1.75rem;
|
||||
--spacing-8: 2rem;
|
||||
--spacing-10: 2.5rem;
|
||||
--spacing-12: 3rem;
|
||||
--spacing-16: 4rem;
|
||||
--spacing-20: 5rem;
|
||||
--spacing-24: 6rem;
|
||||
--spacing-32: 8rem;
|
||||
--spacing-40: 10rem;
|
||||
--spacing-48: 12rem;
|
||||
--spacing-56: 14rem;
|
||||
--spacing-64: 16rem;
|
||||
|
||||
/* Typography */
|
||||
--font-family-sans: 'Inter Variable', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-family-mono: 'Fira Code Variable', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace;
|
||||
--font-family-base: 'Inter Variable', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-size-xs: 0.75rem;
|
||||
--font-size-sm: 0.875rem;
|
||||
--font-size-base: 1rem;
|
||||
--font-size-lg: 1.125rem;
|
||||
--font-size-xl: 1.25rem;
|
||||
--font-size-2xl: 1.5rem;
|
||||
--font-size-3xl: 1.875rem;
|
||||
--font-size-4xl: 2.25rem;
|
||||
--font-size-5xl: 3rem;
|
||||
--font-size-6xl: 3.75rem;
|
||||
--font-size-7xl: 4.5rem;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 21 KiB |
225
static/images/logo-long.svg
Normal file
@ -0,0 +1,225 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="314.98749"
|
||||
height="28.8125"
|
||||
id="svg3004"
|
||||
xml:space="preserve"><metadata
|
||||
id="metadata3010"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3008" /><g
|
||||
transform="matrix(1.25,0,0,-1.25,0,28.8125)"
|
||||
id="g3012"><g
|
||||
transform="scale(0.1,0.1)"
|
||||
id="g3014"><path
|
||||
d="m 957.473,175.816 0,-4.296 -18.453,0 0,-48.614 -5.04,0 0,48.614 -18.378,0 0,4.296 41.871,0"
|
||||
id="path3016"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 969.695,175.816 0,-22.968 31.425,0 0,22.968 5.04,0 0,-52.91 -5.04,0 0,25.637 -31.425,0 0,-25.637 -5.039,0 0,52.91 5.039,0"
|
||||
id="path3018"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1055.58,175.816 0,-4.296 -31.49,0 0,-19.122 29.49,0 0,-4.293 -29.49,0 0,-20.898 31.87,0 0,-4.301 -36.91,0 0,52.91 36.53,0"
|
||||
id="path3020"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1124.58,175.816 0,-4.296 -31.5,0 0,-19.122 29.49,0 0,-4.293 -29.49,0 0,-20.898 31.87,0 0,-4.301 -36.91,0 0,52.91 36.54,0"
|
||||
id="path3022"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1139.76,175.816 30.83,-44.757 0.15,0 0,44.757 5.04,0 0,-52.91 -5.64,0 -30.82,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.63,0"
|
||||
id="path3024"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1188.15,175.816 17.19,-47.355 0.15,0 17.06,47.355 5.34,0 -19.65,-52.91 -5.86,0 -19.56,52.91 5.33,0"
|
||||
id="path3026"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1235.15,122.906 5.043,0 0,52.9102 -5.043,0 0,-52.9102 z"
|
||||
id="path3028"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1277.3,150.691 c 1.54,0 2.99,0.243 4.38,0.711 1.39,0.469 2.59,1.145 3.63,2.036 1.04,0.886 1.86,1.968 2.48,3.222 0.63,1.258 0.92,2.703 0.92,4.336 0,3.262 -0.94,5.824 -2.81,7.703 -1.88,1.875 -4.74,2.821 -8.6,2.821 l -18.82,0 0,-20.829 18.82,0 z m 0.38,25.125 c 2.16,0 4.23,-0.269 6.19,-0.816 1.95,-0.543 3.65,-1.367 5.1,-2.48 1.46,-1.118 2.62,-2.54 3.49,-4.297 0.86,-1.758 1.29,-3.821 1.29,-6.192 0,-3.359 -0.86,-6.273 -2.6,-8.742 -1.72,-2.473 -4.29,-4.055 -7.69,-4.746 l 0,-0.145 c 1.73,-0.25 3.16,-0.703 4.29,-1.367 1.14,-0.668 2.06,-1.527 2.78,-2.558 0.72,-1.035 1.23,-2.239 1.56,-3.594 0.31,-1.363 0.53,-2.832 0.62,-4.41 0.05,-0.887 0.1,-1.977 0.16,-3.262 0.05,-1.285 0.15,-2.582 0.29,-3.891 0.15,-1.312 0.38,-2.543 0.71,-3.711 0.32,-1.156 0.74,-2.054 1.3,-2.699 l -5.56,0 c -0.29,0.496 -0.54,1.098 -0.7,1.809 -0.18,0.723 -0.31,1.461 -0.37,2.234 -0.08,0.762 -0.14,1.512 -0.2,2.254 -0.05,0.742 -0.1,1.387 -0.14,1.926 -0.09,1.875 -0.26,3.742 -0.49,5.598 -0.22,1.851 -0.69,3.503 -1.4,4.961 -0.72,1.46 -1.76,2.632 -3.11,3.523 -1.36,0.887 -3.23,1.281 -5.6,1.191 l -19.12,0 0,-23.496 -5.03,0 0,52.91 24.23,0"
|
||||
id="path3030"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1308.46,140.879 c 0.77,-2.793 1.95,-5.289 3.56,-7.484 1.61,-2.2 3.66,-3.965 6.19,-5.301 2.52,-1.336 5.54,-2.004 9.04,-2.004 3.51,0 6.51,0.668 9,2.004 2.5,1.336 4.55,3.101 6.15,5.301 1.6,2.195 2.8,4.691 3.56,7.484 0.77,2.789 1.15,5.613 1.15,8.48 0,2.914 -0.38,5.758 -1.15,8.52 -0.76,2.769 -1.96,5.25 -3.56,7.449 -1.6,2.199 -3.65,3.969 -6.15,5.297 -2.49,1.336 -5.49,2.008 -9,2.008 -3.5,0 -6.52,-0.672 -9.04,-2.008 -2.53,-1.328 -4.58,-3.098 -6.19,-5.297 -1.61,-2.199 -2.79,-4.68 -3.56,-7.449 -0.75,-2.762 -1.15,-5.606 -1.15,-8.52 0,-2.867 0.4,-5.691 1.15,-8.48 z m -4.63,18.934 c 1.04,3.308 2.6,6.23 4.67,8.777 2.08,2.547 4.68,4.57 7.82,6.078 3.14,1.504 6.79,2.254 10.93,2.254 4.15,0 7.78,-0.75 10.89,-2.254 3.11,-1.508 5.71,-3.531 7.78,-6.078 2.08,-2.547 3.64,-5.469 4.67,-8.777 1.05,-3.313 1.56,-6.797 1.56,-10.454 0,-3.656 -0.51,-7.136 -1.56,-10.449 -1.03,-3.308 -2.59,-6.226 -4.67,-8.738 -2.07,-2.52 -4.67,-4.531 -7.78,-6.043 -3.11,-1.5 -6.74,-2.266 -10.89,-2.266 -4.14,0 -7.79,0.766 -10.93,2.266 -3.14,1.512 -5.74,3.523 -7.82,6.043 -2.07,2.512 -3.63,5.43 -4.67,8.738 -1.04,3.313 -1.54,6.793 -1.54,10.449 0,3.657 0.5,7.141 1.54,10.454"
|
||||
id="path3032"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1367.77,175.816 30.84,-44.757 0.15,0 0,44.757 5.05,0 0,-52.91 -5.64,0 -30.83,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.62,0"
|
||||
id="path3034"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1423.89,175.816 18.3,-46.386 18.22,46.386 7.41,0 0,-52.91 -5.03,0 0,45.723 -0.15,0 -18.09,-45.723 -4.74,0 -18.15,45.723 -0.15,0 0,-45.723 -5.04,0 0,52.91 7.42,0"
|
||||
id="path3036"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1517.1,175.816 0,-4.296 -31.48,0 0,-19.122 29.48,0 0,-4.293 -29.48,0 0,-20.898 31.86,0 0,-4.301 -36.9,0 0,52.91 36.52,0"
|
||||
id="path3038"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1532.29,175.816 30.82,-44.757 0.14,0 0,44.757 5.03,0 0,-52.91 -5.62,0 -30.81,44.754 -0.15,0 0,-44.754 -5.03,0 0,52.91 5.62,0"
|
||||
id="path3040"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1617.34,175.816 0,-4.296 -18.44,0 0,-48.614 -5.04,0 0,48.614 -18.38,0 0,4.296 41.86,0"
|
||||
id="path3042"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1647.8,143.656 -10.22,27.121 -10.6,-27.121 20.82,0 z m -7.18,32.16 20.74,-52.91 -5.4,0 -6.46,16.449 -24.07,0 -6.38,-16.449 -5.33,0 21.26,52.91 5.64,0"
|
||||
id="path3044"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1673.44,175.816 0,-48.609 29.65,0 0,-4.301 -34.68,0 0,52.91 5.03,0"
|
||||
id="path3046"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1769.74,165.254 c -1.02,1.605 -2.25,2.953 -3.71,4.043 -1.46,1.082 -3.06,1.914 -4.81,2.48 -1.76,0.567 -3.6,0.856 -5.52,0.856 -3.51,0 -6.53,-0.672 -9.05,-2.008 -2.52,-1.328 -4.58,-3.098 -6.18,-5.297 -1.61,-2.199 -2.8,-4.68 -3.56,-7.449 -0.77,-2.762 -1.15,-5.606 -1.15,-8.52 0,-2.867 0.38,-5.691 1.15,-8.48 0.76,-2.793 1.95,-5.289 3.56,-7.484 1.6,-2.2 3.66,-3.965 6.18,-5.301 2.52,-1.336 5.54,-2.004 9.05,-2.004 2.46,0 4.69,0.449 6.66,1.336 1.98,0.89 3.68,2.101 5.12,3.633 1.43,1.523 2.59,3.324 3.48,5.371 0.89,2.05 1.45,4.261 1.71,6.633 l 5.03,0 c -0.35,-3.258 -1.11,-6.204 -2.3,-8.821 -1.18,-2.617 -2.7,-4.84 -4.59,-6.664 -1.88,-1.824 -4.08,-3.238 -6.63,-4.223 -2.54,-0.992 -5.37,-1.492 -8.48,-1.492 -4.17,0 -7.81,0.766 -10.93,2.266 -3.15,1.512 -5.76,3.523 -7.83,6.043 -2.07,2.512 -3.62,5.43 -4.65,8.738 -1.04,3.313 -1.57,6.793 -1.57,10.449 0,3.657 0.53,7.141 1.57,10.454 1.03,3.308 2.58,6.23 4.65,8.777 2.07,2.547 4.68,4.57 7.83,6.078 3.12,1.504 6.76,2.254 10.93,2.254 2.52,0 4.97,-0.371 7.38,-1.106 2.39,-0.738 4.56,-1.843 6.51,-3.296 1.95,-1.461 3.58,-3.254 4.89,-5.372 1.3,-2.125 2.13,-4.574 2.47,-7.335 l -5.04,0 c -0.43,2.019 -1.16,3.839 -2.17,5.441"
|
||||
id="path3048"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1791.01,140.879 c 0.76,-2.793 1.95,-5.289 3.56,-7.484 1.6,-2.2 3.66,-3.965 6.18,-5.301 2.52,-1.336 5.53,-2.004 9.04,-2.004 3.51,0 6.5,0.668 9.01,2.004 2.49,1.336 4.54,3.101 6.14,5.301 1.61,2.195 2.79,4.691 3.57,7.484 0.75,2.789 1.14,5.613 1.14,8.48 0,2.914 -0.39,5.758 -1.14,8.52 -0.78,2.769 -1.96,5.25 -3.57,7.449 -1.6,2.199 -3.65,3.969 -6.14,5.297 -2.51,1.336 -5.5,2.008 -9.01,2.008 -3.51,0 -6.52,-0.672 -9.04,-2.008 -2.52,-1.328 -4.58,-3.098 -6.18,-5.297 -1.61,-2.199 -2.8,-4.68 -3.56,-7.449 -0.78,-2.762 -1.16,-5.606 -1.16,-8.52 0,-2.867 0.38,-5.691 1.16,-8.48 z m -4.64,18.934 c 1.04,3.308 2.6,6.23 4.67,8.777 2.08,2.547 4.68,4.57 7.82,6.078 3.13,1.504 6.77,2.254 10.93,2.254 4.15,0 7.78,-0.75 10.89,-2.254 3.11,-1.508 5.72,-3.531 7.79,-6.078 2.07,-2.547 3.62,-5.469 4.66,-8.777 1.04,-3.313 1.56,-6.797 1.56,-10.454 0,-3.656 -0.52,-7.136 -1.56,-10.449 -1.04,-3.308 -2.59,-6.226 -4.66,-8.738 -2.07,-2.52 -4.68,-4.531 -7.79,-6.043 -3.11,-1.5 -6.74,-2.266 -10.89,-2.266 -4.16,0 -7.8,0.766 -10.93,2.266 -3.14,1.512 -5.74,3.523 -7.82,6.043 -2.07,2.512 -3.63,5.43 -4.67,8.738 -1.04,3.313 -1.56,6.793 -1.56,10.449 0,3.657 0.52,7.141 1.56,10.454"
|
||||
id="path3050"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1850.33,175.816 30.82,-44.757 0.15,0 0,44.757 5.04,0 0,-52.91 -5.64,0 -30.82,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.64,0"
|
||||
id="path3052"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1935.39,175.816 0,-4.296 -18.45,0 0,-48.614 -5.04,0 0,48.614 -18.37,0 0,4.296 41.86,0"
|
||||
id="path3054"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1965.86,143.656 -10.23,27.121 -10.6,-27.121 20.83,0 z m -7.21,32.16 20.76,-52.91 -5.41,0 -6.44,16.449 -24.08,0 -6.38,-16.449 -5.33,0 21.26,52.91 5.62,0"
|
||||
id="path3056"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1993.71,175.816 18.3,-46.386 18.24,46.386 7.41,0 0,-52.91 -5.04,0 0,45.723 -0.15,0 -18.09,-45.723 -4.73,0 -18.16,45.723 -0.14,0 0,-45.723 -5.05,0 0,52.91 7.41,0"
|
||||
id="path3058"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2050.78,122.906 5.0273,0 0,52.9102 -5.0273,0 0,-52.9102 z"
|
||||
id="path3060"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2074.63,175.816 30.83,-44.757 0.15,0 0,44.757 5.04,0 0,-52.91 -5.63,0 -30.83,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.63,0"
|
||||
id="path3062"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2151.78,143.656 -10.24,27.121 -10.58,-27.121 20.82,0 z m -7.2,32.16 20.76,-52.91 -5.41,0 -6.45,16.449 -24.09,0 -6.36,-16.449 -5.34,0 21.27,52.91 5.62,0"
|
||||
id="path3064"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2177.93,175.816 30.82,-44.757 0.16,0 0,44.757 5.05,0 0,-52.91 -5.64,0 -30.84,44.754 -0.14,0 0,-44.754 -5.04,0 0,52.91 5.63,0"
|
||||
id="path3066"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2263.01,175.816 0,-4.296 -18.46,0 0,-48.614 -5.04,0 0,48.614 -18.38,0 0,4.296 41.88,0"
|
||||
id="path3068"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 945.785,32.6602 c 1.875,0 3.656,0.1562 5.336,0.4804 1.676,0.3164 3.16,0.8985 4.445,1.7383 1.286,0.8477 2.301,1.9649 3.043,3.375 0.739,1.4102 1.11,3.1719 1.11,5.2969 0,3.4101 -1.203,5.9648 -3.602,7.668 -2.387,1.7031 -5.836,2.5585 -10.332,2.5585 l -17.344,0 0,-21.1171 17.344,0 z m 0,25.414 c 2.028,0 3.778,0.2344 5.262,0.711 1.48,0.4609 2.719,1.1015 3.711,1.9218 0.98,0.8125 1.726,1.7696 2.215,2.8555 0.5,1.082 0.742,2.2422 0.742,3.4766 0,6.6211 -3.977,9.9375 -11.93,9.9375 l -17.344,0 0,-18.9024 17.344,0 z m 0,23.1953 c 2.223,0 4.36,-0.2109 6.41,-0.6289 2.051,-0.4218 3.852,-1.1328 5.41,-2.1484 1.559,-1.0156 2.805,-2.3438 3.743,-4 0.937,-1.6563 1.406,-3.7227 1.406,-6.1914 0,-1.3867 -0.219,-2.7305 -0.668,-4.0391 -0.445,-1.3086 -1.074,-2.4961 -1.887,-3.5547 -0.808,-1.0625 -1.781,-1.9687 -2.89,-2.7031 -1.114,-0.7422 -2.36,-1.2617 -3.739,-1.5586 l 0,-0.1523 c 3.403,-0.4453 6.121,-1.8321 8.145,-4.1797 2.031,-2.3477 3.043,-5.25 3.043,-8.711 0,-0.8398 -0.074,-1.7851 -0.227,-2.8515 -0.144,-1.0625 -0.437,-2.1524 -0.886,-3.2617 -0.446,-1.1133 -1.086,-2.2149 -1.93,-3.2969 -0.836,-1.0859 -1.957,-2.0391 -3.363,-2.8516 -1.414,-0.8203 -3.141,-1.4883 -5.192,-2.0039 -2.051,-0.5195 -4.508,-0.7812 -7.375,-0.7812 l -22.379,0 0,52.914 22.379,0"
|
||||
id="path3070"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 975.426,28.3555 5.04297,0 0,52.9141 -5.04297,0 0,-52.9141 z"
|
||||
id="path3072"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 997.105,46.3281 c 0.762,-2.789 1.95,-5.2812 3.555,-7.4804 1.6,-2.1993 3.67,-3.9688 6.18,-5.2969 2.53,-1.3399 5.54,-2.0039 9.04,-2.0039 3.51,0 6.52,0.664 9.01,2.0039 2.5,1.3281 4.54,3.0976 6.15,5.2969 1.61,2.1992 2.79,4.6914 3.55,7.4804 0.77,2.793 1.16,5.6211 1.16,8.4844 0,2.918 -0.39,5.7578 -1.16,8.5273 -0.76,2.7618 -1.94,5.2461 -3.55,7.4454 -1.61,2.2031 -3.65,3.9648 -6.15,5.3007 -2.49,1.3321 -5.5,2 -9.01,2 -3.5,0 -6.51,-0.6679 -9.04,-2 -2.51,-1.3359 -4.58,-3.0976 -6.18,-5.3007 -1.605,-2.1993 -2.793,-4.6836 -3.555,-7.4454 -0.773,-2.7695 -1.152,-5.6093 -1.152,-8.5273 0,-2.8633 0.379,-5.6914 1.152,-8.4844 z m -4.632,18.9336 c 1.035,3.3125 2.59,6.2383 4.668,8.7813 2.074,2.5429 4.679,4.5742 7.819,6.0781 3.13,1.5078 6.77,2.2578 10.92,2.2578 4.15,0 7.79,-0.75 10.9,-2.2578 3.11,-1.5039 5.71,-3.5352 7.78,-6.0781 2.08,-2.543 3.63,-5.4688 4.67,-8.7813 1.04,-3.3047 1.56,-6.789 1.56,-10.4492 0,-3.6602 -0.52,-7.1406 -1.56,-10.4414 -1.04,-3.3164 -2.59,-6.2305 -4.67,-8.7461 -2.07,-2.5195 -4.67,-4.5312 -7.78,-6.0391 -3.11,-1.5039 -6.75,-2.2656 -10.9,-2.2656 -4.15,0 -7.79,0.7617 -10.92,2.2656 -3.14,1.5079 -5.745,3.5196 -7.819,6.0391 -2.078,2.5156 -3.633,5.4297 -4.668,8.7461 -1.035,3.3008 -1.559,6.7812 -1.559,10.4414 0,3.6602 0.524,7.1445 1.559,10.4492"
|
||||
id="path3074"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1087.1,81.2695 0,-4.2929 -18.45,0 0,-48.6211 -5.04,0 0,48.6211 -18.38,0 0,4.2929 41.87,0"
|
||||
id="path3076"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1118.15,56.1484 c 1.53,0 2.99,0.2383 4.37,0.7071 1.39,0.4687 2.6,1.1484 3.63,2.0351 1.04,0.8907 1.86,1.9688 2.49,3.2227 0.61,1.2617 0.93,2.7109 0.93,4.332 0,3.2656 -0.95,5.836 -2.82,7.7031 -1.88,1.8829 -4.75,2.8282 -8.6,2.8282 l -18.82,0 0,-20.8282 18.82,0 z m 0.37,25.1211 c 2.17,0 4.23,-0.2695 6.19,-0.8203 1.95,-0.539 3.65,-1.3633 5.11,-2.4765 1.46,-1.1133 2.62,-2.543 3.49,-4.3008 0.86,-1.7578 1.29,-3.8125 1.29,-6.1875 0,-3.3594 -0.86,-6.2696 -2.59,-8.7461 -1.73,-2.4688 -4.3,-4.0469 -7.71,-4.7383 l 0,-0.1484 c 1.73,-0.25 3.16,-0.7032 4.3,-1.3672 1.14,-0.668 2.06,-1.5235 2.78,-2.5586 0.71,-1.0391 1.23,-2.2344 1.55,-3.5977 0.33,-1.3593 0.54,-2.8281 0.63,-4.4062 0.05,-0.8867 0.1,-1.9766 0.15,-3.2656 0.05,-1.2852 0.15,-2.5782 0.3,-3.8868 0.15,-1.3125 0.38,-2.5468 0.71,-3.707 0.31,-1.1562 0.74,-2.0586 1.29,-2.707 l -5.56,0 c -0.29,0.5 -0.53,1.1015 -0.7,1.8203 -0.17,0.7187 -0.3,1.4531 -0.37,2.2265 -0.07,0.7618 -0.14,1.5118 -0.19,2.25 -0.04,0.7461 -0.1,1.3946 -0.15,1.9297 -0.1,1.875 -0.26,3.7461 -0.48,5.6016 -0.22,1.8555 -0.69,3.5 -1.41,4.9609 -0.71,1.4532 -1.75,2.6289 -3.11,3.5235 -1.36,0.8906 -3.22,1.2812 -5.59,1.1875 l -19.12,0 0,-23.5 -5.04,0 0,52.914 24.23,0"
|
||||
id="path3078"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1174.25,49.1055 -10.23,27.125 -10.6,-27.125 20.83,0 z m -7.19,32.164 20.75,-52.914 -5.41,0 -6.45,16.457 -24.08,0 -6.38,-16.457 -5.33,0 21.27,52.914 5.63,0"
|
||||
id="path3080"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1200.41,81.2695 30.83,-44.7617 0.15,0 0,44.7617 5.04,0 0,-52.914 -5.63,0 -30.84,44.7578 -0.15,0 0,-44.7578 -5.04,0 0,52.914 5.64,0"
|
||||
id="path3082"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1252.87,38.9609 c 0.9,-1.8281 2.12,-3.289 3.67,-4.375 1.57,-1.0898 3.4,-1.8671 5.52,-2.3359 2.12,-0.4727 4.4,-0.7031 6.83,-0.7031 1.37,0 2.89,0.1914 4.52,0.5976 1.62,0.3907 3.14,1.0196 4.55,1.8828 1.42,0.8711 2.58,1.9727 3.52,3.336 0.94,1.3515 1.41,3.0039 1.41,4.9258 0,1.4843 -0.33,2.7695 -1.01,3.8593 -0.66,1.086 -1.53,1.9961 -2.58,2.7383 -1.07,0.7422 -2.24,1.3438 -3.53,1.8164 -1.28,0.4688 -2.55,0.8555 -3.78,1.1524 l -11.78,2.8789 c -1.54,0.4062 -3.02,0.8906 -4.49,1.4922 -1.44,0.5898 -2.72,1.375 -3.81,2.3672 -1.09,0.9843 -1.95,2.2031 -2.63,3.6289 -0.67,1.4336 -1,3.1875 -1,5.2617 0,1.289 0.25,2.7929 0.74,4.5234 0.49,1.7266 1.42,3.3594 2.79,4.8906 1.35,1.5274 3.21,2.8243 5.59,3.8907 2.37,1.0625 5.4,1.5898 9.1,1.5898 2.62,0 5.13,-0.3398 7.49,-1.0351 2.38,-0.6915 4.47,-1.7305 6.22,-3.1133 1.8,-1.3789 3.21,-3.0977 4.26,-5.1446 1.08,-2.0546 1.6,-4.4453 1.6,-7.1601 l -5.03,0 c -0.1,2.0351 -0.56,3.7969 -1.37,5.3047 -0.82,1.5039 -1.88,2.7617 -3.19,3.7773 -1.3,1.0117 -2.81,1.7852 -4.53,2.3008 -1.7,0.5195 -3.49,0.7773 -5.37,0.7773 -1.72,0 -3.39,-0.1914 -5,-0.5586 -1.61,-0.371 -3.01,-0.9609 -4.22,-1.7812 -1.21,-0.8164 -2.18,-1.8906 -2.93,-3.2227 -0.74,-1.332 -1.11,-2.9882 -1.11,-4.9648 0,-1.2305 0.22,-2.3086 0.64,-3.2227 0.42,-0.914 0.98,-1.6953 1.72,-2.332 0.75,-0.6484 1.61,-1.1601 2.56,-1.5547 0.98,-0.4023 1.99,-0.7226 3.08,-0.9687 l 12.9,-3.1875 c 1.88,-0.4883 3.64,-1.0938 5.3,-1.8164 1.65,-0.711 3.11,-1.6055 4.37,-2.6602 1.27,-1.0625 2.24,-2.3633 2.97,-3.8945 0.71,-1.5313 1.07,-3.3867 1.07,-5.5586 0,-0.5899 -0.07,-1.3828 -0.2,-2.3672 -0.11,-0.9922 -0.41,-2.0313 -0.87,-3.1523 -0.47,-1.1133 -1.14,-2.2344 -2,-3.3711 -0.87,-1.1368 -2.06,-2.1602 -3.56,-3.0782 -1.51,-0.9062 -3.37,-1.6562 -5.6,-2.2226 -2.22,-0.5586 -4.88,-0.8516 -8,-0.8516 -3.11,0 -6,0.3594 -8.68,1.0781 -2.65,0.7188 -4.94,1.8125 -6.81,3.2969 -1.88,1.4844 -3.32,3.3789 -4.34,5.707 -1,2.3204 -1.43,5.1055 -1.3,8.375 l 5.05,0 c -0.06,-2.7148 0.37,-4.9921 1.25,-6.8164"
|
||||
id="path3084"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1331.72,81.2695 0,-4.2929 -28.53,0 0,-19.1211 25.35,0 0,-4.3008 -25.35,0 0,-25.1992 -5.04,0 0,52.914 33.57,0"
|
||||
id="path3086"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1343.54,46.3281 c 0.78,-2.789 1.95,-5.2812 3.55,-7.4804 1.6,-2.1993 3.68,-3.9688 6.2,-5.2969 2.51,-1.3399 5.53,-2.0039 9.03,-2.0039 3.51,0 6.51,0.664 9.01,2.0039 2.5,1.3281 4.55,3.0976 6.15,5.2969 1.6,2.1992 2.78,4.6914 3.56,7.4804 0.76,2.793 1.15,5.6211 1.15,8.4844 0,2.918 -0.39,5.7578 -1.15,8.5273 -0.78,2.7618 -1.96,5.2461 -3.56,7.4454 -1.6,2.2031 -3.65,3.9648 -6.15,5.3007 -2.5,1.3321 -5.5,2 -9.01,2 -3.5,0 -6.52,-0.6679 -9.03,-2 -2.52,-1.3359 -4.6,-3.0976 -6.2,-5.3007 -1.6,-2.1993 -2.77,-4.6836 -3.55,-7.4454 -0.77,-2.7695 -1.14,-5.6093 -1.14,-8.5273 0,-2.8633 0.37,-5.6914 1.14,-8.4844 z m -4.63,18.9336 c 1.03,3.3125 2.59,6.2383 4.66,8.7813 2.09,2.5429 4.69,4.5742 7.82,6.0781 3.14,1.5078 6.79,2.2578 10.93,2.2578 4.15,0 7.8,-0.75 10.9,-2.2578 3.11,-1.5039 5.7,-3.5352 7.78,-6.0781 2.09,-2.543 3.63,-5.4688 4.66,-8.7813 1.04,-3.3047 1.57,-6.789 1.57,-10.4492 0,-3.6602 -0.53,-7.1406 -1.57,-10.4414 -1.03,-3.3164 -2.57,-6.2305 -4.66,-8.7461 -2.08,-2.5195 -4.67,-4.5312 -7.78,-6.0391 -3.1,-1.5039 -6.75,-2.2656 -10.9,-2.2656 -4.14,0 -7.79,0.7617 -10.93,2.2656 -3.13,1.5079 -5.73,3.5196 -7.82,6.0391 -2.07,2.5156 -3.63,5.4297 -4.66,8.7461 -1.04,3.3008 -1.56,6.7812 -1.56,10.4414 0,3.6602 0.52,7.1445 1.56,10.4492"
|
||||
id="path3088"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1421.16,56.1484 c 1.54,0 3,0.2383 4.39,0.7071 1.37,0.4687 2.58,1.1484 3.62,2.0351 1.04,0.8907 1.87,1.9688 2.49,3.2227 0.61,1.2617 0.91,2.7109 0.91,4.332 0,3.2656 -0.93,5.836 -2.81,7.7031 -1.88,1.8829 -4.73,2.8282 -8.6,2.8282 l -18.83,0 0,-20.8282 18.83,0 z m 0.37,25.1211 c 2.18,0 4.24,-0.2695 6.18,-0.8203 1.96,-0.539 3.67,-1.3633 5.12,-2.4765 1.47,-1.1133 2.63,-2.543 3.49,-4.3008 0.86,-1.7578 1.3,-3.8125 1.3,-6.1875 0,-3.3594 -0.87,-6.2696 -2.6,-8.7461 -1.72,-2.4688 -4.3,-4.0469 -7.71,-4.7383 l 0,-0.1484 c 1.74,-0.25 3.17,-0.7032 4.3,-1.3672 1.13,-0.668 2.06,-1.5235 2.78,-2.5586 0.72,-1.0391 1.24,-2.2344 1.56,-3.5977 0.32,-1.3593 0.52,-2.8281 0.63,-4.4062 0.05,-0.8867 0.1,-1.9766 0.15,-3.2656 0.05,-1.2852 0.15,-2.5782 0.29,-3.8868 0.16,-1.3125 0.38,-2.5468 0.7,-3.707 0.33,-1.1562 0.76,-2.0586 1.3,-2.707 l -5.55,0 c -0.31,0.5 -0.54,1.1015 -0.71,1.8203 -0.17,0.7187 -0.29,1.4531 -0.37,2.2265 -0.08,0.7618 -0.13,1.5118 -0.18,2.25 -0.05,0.7461 -0.1,1.3946 -0.15,1.9297 -0.1,1.875 -0.25,3.7461 -0.48,5.6016 -0.22,1.8555 -0.7,3.5 -1.41,4.9609 -0.73,1.4532 -1.76,2.6289 -3.12,3.5235 -1.36,0.8906 -3.21,1.2812 -5.59,1.1875 l -19.13,0 0,-23.5 -5.03,0 0,52.914 24.23,0"
|
||||
id="path3090"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1456.21,81.2695 18.3,-46.3906 18.24,46.3906 7.41,0 0,-52.914 -5.04,0 0,45.7265 -0.15,0 -18.08,-45.7265 -4.74,0 -18.17,45.7265 -0.13,0 0,-45.7265 -5.05,0 0,52.914 7.41,0"
|
||||
id="path3092"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1541.21,49.1055 -10.22,27.125 -10.6,-27.125 20.82,0 z m -7.19,32.164 20.74,-52.914 -5.42,0 -6.42,16.457 -24.08,0 -6.38,-16.457 -5.33,0 21.27,52.914 5.62,0"
|
||||
id="path3094"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1593,81.2695 0,-4.2929 -18.47,0 0,-48.6211 -5.04,0 0,48.6211 -18.37,0 0,4.2929 41.88,0"
|
||||
id="path3096"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1600.55,28.3555 5.0391,0 0,52.9141 -5.0391,0 0,-52.9141 z"
|
||||
id="path3098"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1622.23,46.3281 c 0.76,-2.789 1.94,-5.2812 3.55,-7.4804 1.6,-2.1993 3.67,-3.9688 6.19,-5.2969 2.52,-1.3399 5.53,-2.0039 9.04,-2.0039 3.5,0 6.5,0.664 9.01,2.0039 2.48,1.3281 4.54,3.0976 6.14,5.2969 1.61,2.1992 2.8,4.6914 3.56,7.4804 0.76,2.793 1.15,5.6211 1.15,8.4844 0,2.918 -0.39,5.7578 -1.15,8.5273 -0.76,2.7618 -1.95,5.2461 -3.56,7.4454 -1.6,2.2031 -3.66,3.9648 -6.14,5.3007 -2.51,1.3321 -5.51,2 -9.01,2 -3.51,0 -6.52,-0.6679 -9.04,-2 -2.52,-1.3359 -4.59,-3.0976 -6.19,-5.3007 -1.61,-2.1993 -2.79,-4.6836 -3.55,-7.4454 -0.77,-2.7695 -1.16,-5.6093 -1.16,-8.5273 0,-2.8633 0.39,-5.6914 1.16,-8.4844 z m -4.64,18.9336 c 1.03,3.3125 2.6,6.2383 4.68,8.7813 2.07,2.5429 4.67,4.5742 7.8,6.0781 3.14,1.5078 6.79,2.2578 10.94,2.2578 4.16,0 7.78,-0.75 10.88,-2.2578 3.13,-1.5039 5.72,-3.5352 7.8,-6.0781 2.07,-2.543 3.62,-5.4688 4.66,-8.7813 1.03,-3.3047 1.55,-6.789 1.55,-10.4492 0,-3.6602 -0.52,-7.1406 -1.55,-10.4414 -1.04,-3.3164 -2.59,-6.2305 -4.66,-8.7461 -2.08,-2.5195 -4.67,-4.5312 -7.8,-6.0391 -3.1,-1.5039 -6.72,-2.2656 -10.88,-2.2656 -4.15,0 -7.8,0.7617 -10.94,2.2656 -3.13,1.5079 -5.73,3.5196 -7.8,6.0391 -2.08,2.5156 -3.65,5.4297 -4.68,8.7461 -1.03,3.3008 -1.55,6.7812 -1.55,10.4414 0,3.6602 0.52,7.1445 1.55,10.4492"
|
||||
id="path3100"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1681.55,81.2695 30.82,-44.7617 0.15,0 0,44.7617 5.04,0 0,-52.914 -5.64,0 -30.82,44.7578 -0.15,0 0,-44.7578 -5.03,0 0,52.914 5.63,0"
|
||||
id="path3102"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1775.58,55.332 c 3.51,0 6.35,0.8946 8.52,2.6719 2.17,1.7774 3.26,4.4922 3.26,8.1484 0,3.6602 -1.09,6.3711 -3.26,8.1485 -2.17,1.7851 -5.01,2.6758 -8.52,2.6758 l -17.35,0 0,-21.6446 17.35,0 z m 1.12,25.9375 c 2.36,0 4.51,-0.3359 6.43,-0.9961 1.94,-0.6679 3.58,-1.6562 4.99,-2.9648 1.37,-1.3125 2.43,-2.9063 3.17,-4.7852 0.74,-1.875 1.11,-4.0039 1.11,-6.3711 0,-2.3671 -0.37,-4.4921 -1.11,-6.371 -0.74,-1.8829 -1.8,-3.4766 -3.17,-4.7852 -1.41,-1.3047 -3.05,-2.293 -4.99,-2.9609 -1.92,-0.6641 -4.07,-0.9961 -6.43,-0.9961 l -18.47,0 0,-22.6836 -5.04,0 0,52.914 23.51,0"
|
||||
id="path3104"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1824.93,49.1055 -10.22,27.125 -10.6,-27.125 20.82,0 z m -7.19,32.164 20.76,-52.914 -5.41,0 -6.45,16.457 -24.09,0 -6.38,-16.457 -5.33,0 21.28,52.914 5.62,0"
|
||||
id="path3106"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1876.73,81.2695 0,-4.2929 -18.45,0 0,-48.6211 -5.04,0 0,48.6211 -18.38,0 0,4.2929 41.87,0"
|
||||
id="path3108"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1888.96,81.2695 0,-22.9687 31.41,0 0,22.9687 5.04,0 0,-52.914 -5.04,0 0,25.6445 -31.41,0 0,-25.6445 -5.04,0 0,52.914 5.04,0"
|
||||
id="path3110"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1938.38,81.2695 12.01,-46.3125 0.15,0 12.9,46.3125 6.3,0 12.96,-46.3125 0.15,0 12.07,46.3125 5.04,0 -14.59,-52.914 -5.34,0 -13.42,47.3515 -0.14,0 -13.34,-47.3515 -5.48,0 -14.67,52.914 5.4,0"
|
||||
id="path3112"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2034.73,49.1055 -10.24,27.125 -10.59,-27.125 20.83,0 z m -7.2,32.164 20.75,-52.914 -5.41,0 -6.44,16.457 -24.09,0 -6.37,-16.457 -5.34,0 21.27,52.914 5.63,0"
|
||||
id="path3114"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2043.84,81.2695 5.93,0 17.41,-26.8281 17.33,26.8281 6.01,0 -20.9,-31.125 0,-21.789 -5.04,0 0,21.789 -20.74,31.125"
|
||||
id="path3116"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2144.01,56.1484 c 1.55,0 3,0.2383 4.38,0.7071 1.39,0.4687 2.6,1.1484 3.63,2.0351 1.05,0.8907 1.88,1.9688 2.48,3.2227 0.62,1.2617 0.93,2.7109 0.93,4.332 0,3.2656 -0.94,5.836 -2.81,7.7031 -1.89,1.8829 -4.75,2.8282 -8.61,2.8282 l -18.81,0 0,-20.8282 18.81,0 z m 0.38,25.1211 c 2.18,0 4.23,-0.2695 6.19,-0.8203 1.95,-0.539 3.66,-1.3633 5.1,-2.4765 1.47,-1.1133 2.63,-2.543 3.5,-4.3008 0.86,-1.7578 1.29,-3.8125 1.29,-6.1875 0,-3.3594 -0.86,-6.2696 -2.59,-8.7461 -1.73,-2.4688 -4.3,-4.0469 -7.7,-4.7383 l 0,-0.1484 c 1.72,-0.25 3.15,-0.7032 4.28,-1.3672 1.15,-0.668 2.07,-1.5235 2.79,-2.5586 0.72,-1.0391 1.24,-2.2344 1.55,-3.5977 0.32,-1.3593 0.54,-2.8281 0.63,-4.4062 0.05,-0.8867 0.1,-1.9766 0.15,-3.2656 0.05,-1.2852 0.15,-2.5782 0.29,-3.8868 0.15,-1.3125 0.39,-2.5468 0.71,-3.707 0.33,-1.1562 0.76,-2.0586 1.3,-2.707 l -5.55,0 c -0.3,0.5 -0.54,1.1015 -0.71,1.8203 -0.17,0.7187 -0.3,1.4531 -0.38,2.2265 -0.07,0.7618 -0.13,1.5118 -0.18,2.25 -0.04,0.7461 -0.1,1.3946 -0.15,1.9297 -0.1,1.875 -0.26,3.7461 -0.49,5.6016 -0.22,1.8555 -0.68,3.5 -1.39,4.9609 -0.73,1.4532 -1.76,2.6289 -3.13,3.5235 -1.35,0.8906 -3.21,1.2812 -5.59,1.1875 l -19.11,0 0,-23.5 -5.04,0 0,52.914 24.23,0"
|
||||
id="path3118"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2208.34,81.2695 0,-4.2929 -31.49,0 0,-19.1211 29.49,0 0,-4.3008 -29.49,0 0,-20.8945 31.87,0 0,-4.3047 -36.91,0 0,52.914 36.53,0"
|
||||
id="path3120"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2221.6,38.9609 c 0.9,-1.8281 2.13,-3.289 3.66,-4.375 1.58,-1.0898 3.4,-1.8671 5.53,-2.3359 2.12,-0.4727 4.41,-0.7031 6.82,-0.7031 1.38,0 2.9,0.1914 4.53,0.5976 1.62,0.3907 3.13,1.0196 4.55,1.8828 1.41,0.8711 2.58,1.9727 3.52,3.336 0.94,1.3515 1.4,3.0039 1.4,4.9258 0,1.4843 -0.32,2.7695 -0.99,3.8593 -0.66,1.086 -1.55,1.9961 -2.59,2.7383 -1.06,0.7422 -2.24,1.3438 -3.53,1.8164 -1.28,0.4688 -2.54,0.8555 -3.78,1.1524 l -11.77,2.8789 c -1.55,0.4062 -3.03,0.8906 -4.5,1.4922 -1.45,0.5898 -2.73,1.375 -3.82,2.3672 -1.08,0.9843 -1.95,2.2031 -2.62,3.6289 -0.66,1.4336 -1,3.1875 -1,5.2617 0,1.289 0.24,2.7929 0.74,4.5234 0.5,1.7266 1.42,3.3594 2.78,4.8906 1.36,1.5274 3.23,2.8243 5.59,3.8907 2.38,1.0625 5.41,1.5898 9.12,1.5898 2.61,0 5.11,-0.3398 7.48,-1.0351 2.37,-0.6915 4.46,-1.7305 6.24,-3.1133 1.77,-1.3789 3.19,-3.0977 4.24,-5.1446 1.08,-2.0546 1.6,-4.4453 1.6,-7.1601 l -5.03,0 c -0.1,2.0351 -0.55,3.7969 -1.38,5.3047 -0.81,1.5039 -1.87,2.7617 -3.18,3.7773 -1.31,1.0117 -2.82,1.7852 -4.53,2.3008 -1.71,0.5195 -3.48,0.7773 -5.37,0.7773 -1.73,0 -3.4,-0.1914 -5.01,-0.5586 -1.6,-0.371 -3,-0.9609 -4.21,-1.7812 -1.21,-0.8164 -2.19,-1.8906 -2.94,-3.2227 -0.74,-1.332 -1.1,-2.9882 -1.1,-4.9648 0,-1.2305 0.21,-2.3086 0.63,-3.2227 0.43,-0.914 0.99,-1.6953 1.73,-2.332 0.75,-0.6484 1.62,-1.1601 2.56,-1.5547 0.97,-0.4023 1.99,-0.7226 3.08,-0.9687 l 12.9,-3.1875 c 1.87,-0.4883 3.64,-1.0938 5.3,-1.8164 1.65,-0.711 3.11,-1.6055 4.37,-2.6602 1.26,-1.0625 2.24,-2.3633 2.97,-3.8945 0.71,-1.5313 1.07,-3.3867 1.07,-5.5586 0,-0.5899 -0.07,-1.3828 -0.2,-2.3672 -0.11,-0.9922 -0.41,-2.0313 -0.87,-3.1523 -0.48,-1.1133 -1.15,-2.2344 -2.01,-3.3711 -0.86,-1.1368 -2.05,-2.1602 -3.55,-3.0782 -1.5,-0.9062 -3.37,-1.6562 -5.6,-2.2226 -2.22,-0.5586 -4.89,-0.8516 -8.01,-0.8516 -3.11,0 -5.99,0.3594 -8.67,1.0781 -2.66,0.7188 -4.94,1.8125 -6.8,3.2969 -1.89,1.4844 -3.33,3.3789 -4.36,5.707 -0.99,2.3204 -1.43,5.1055 -1.29,8.375 l 5.04,0 c -0.05,-2.7148 0.38,-4.9921 1.26,-6.8164"
|
||||
id="path3122"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2270.24,46.3281 c 0.79,-2.789 1.96,-5.2812 3.57,-7.4804 1.6,-2.1993 3.67,-3.9688 6.18,-5.2969 2.52,-1.3399 5.54,-2.0039 9.04,-2.0039 3.51,0 6.52,0.664 9.02,2.0039 2.49,1.3281 4.54,3.0976 6.15,5.2969 1.6,2.1992 2.77,4.6914 3.55,7.4804 0.77,2.793 1.15,5.6211 1.15,8.4844 0,2.918 -0.38,5.7578 -1.15,8.5273 -0.78,2.7618 -1.95,5.2461 -3.55,7.4454 -1.61,2.2031 -3.66,3.9648 -6.15,5.3007 -2.5,1.3321 -5.51,2 -9.02,2 -3.5,0 -6.52,-0.6679 -9.04,-2 -2.51,-1.3359 -4.58,-3.0976 -6.18,-5.3007 -1.61,-2.1993 -2.78,-4.6836 -3.57,-7.4454 -0.75,-2.7695 -1.13,-5.6093 -1.13,-8.5273 0,-2.8633 0.38,-5.6914 1.13,-8.4844 z m -4.62,18.9336 c 1.04,3.3125 2.59,6.2383 4.66,8.7813 2.09,2.5429 4.68,4.5742 7.83,6.0781 3.14,1.5078 6.78,2.2578 10.92,2.2578 4.15,0 7.8,-0.75 10.9,-2.2578 3.11,-1.5039 5.7,-3.5352 7.79,-6.0781 2.07,-2.543 3.63,-5.4688 4.66,-8.7813 1.04,-3.3047 1.56,-6.789 1.56,-10.4492 0,-3.6602 -0.52,-7.1406 -1.56,-10.4414 -1.03,-3.3164 -2.59,-6.2305 -4.66,-8.7461 -2.09,-2.5195 -4.68,-4.5312 -7.79,-6.0391 -3.1,-1.5039 -6.75,-2.2656 -10.9,-2.2656 -4.14,0 -7.78,0.7617 -10.92,2.2656 -3.15,1.5079 -5.74,3.5196 -7.83,6.0391 -2.07,2.5156 -3.62,5.4297 -4.66,8.7461 -1.04,3.3008 -1.56,6.7812 -1.56,10.4414 0,3.6602 0.52,7.1445 1.56,10.4492"
|
||||
id="path3124"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2328.53,81.2695 0,-32.7539 c 0,-3.0625 0.35,-5.664 1.03,-7.8242 0.69,-2.1406 1.71,-3.8984 3.05,-5.2578 1.33,-1.3555 2.97,-2.3477 4.88,-2.9648 1.93,-0.6172 4.11,-0.9219 6.52,-0.9219 2.47,0 4.67,0.3047 6.61,0.9219 1.93,0.6171 3.55,1.6093 4.88,2.9648 1.34,1.3594 2.35,3.1172 3.04,5.2578 0.69,2.1602 1.04,4.7617 1.04,7.8242 l 0,32.7539 5.04,0 0,-33.8672 c 0,-2.7148 -0.38,-5.2968 -1.14,-7.7382 -0.77,-2.4493 -1.99,-4.5899 -3.65,-6.418 -1.66,-1.8242 -3.76,-3.2695 -6.36,-4.332 -2.6,-1.0586 -5.74,-1.5938 -9.46,-1.5938 -3.65,0 -6.77,0.5352 -9.37,1.5938 -2.59,1.0625 -4.71,2.5078 -6.37,4.332 -1.66,1.8281 -2.87,3.9687 -3.63,6.418 -0.77,2.4414 -1.13,5.0234 -1.13,7.7382 l 0,33.8672 5.02,0"
|
||||
id="path3126"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2400.87,56.1484 c 1.51,0 2.99,0.2383 4.36,0.7071 1.39,0.4687 2.59,1.1484 3.63,2.0351 1.03,0.8907 1.86,1.9688 2.49,3.2227 0.62,1.2617 0.92,2.7109 0.92,4.332 0,3.2656 -0.94,5.836 -2.82,7.7031 -1.86,1.8829 -4.73,2.8282 -8.58,2.8282 l -18.83,0 0,-20.8282 18.83,0 z m 0.36,25.1211 c 2.18,0 4.23,-0.2695 6.2,-0.8203 1.94,-0.539 3.64,-1.3633 5.11,-2.4765 1.45,-1.1133 2.61,-2.543 3.47,-4.3008 0.88,-1.7578 1.29,-3.8125 1.29,-6.1875 0,-3.3594 -0.85,-6.2696 -2.58,-8.7461 -1.73,-2.4688 -4.29,-4.0469 -7.71,-4.7383 l 0,-0.1484 c 1.73,-0.25 3.17,-0.7032 4.31,-1.3672 1.11,-0.668 2.05,-1.5235 2.77,-2.5586 0.71,-1.0391 1.23,-2.2344 1.55,-3.5977 0.32,-1.3593 0.52,-2.8281 0.63,-4.4062 0.05,-0.8867 0.11,-1.9766 0.16,-3.2656 0.04,-1.2852 0.15,-2.5782 0.29,-3.8868 0.14,-1.3125 0.38,-2.5468 0.7,-3.707 0.31,-1.1562 0.75,-2.0586 1.3,-2.707 l -5.56,0 c -0.29,0.5 -0.53,1.1015 -0.71,1.8203 -0.16,0.7187 -0.29,1.4531 -0.36,2.2265 -0.09,0.7618 -0.14,1.5118 -0.19,2.25 -0.05,0.7461 -0.1,1.3946 -0.15,1.9297 -0.09,1.875 -0.27,3.7461 -0.47,5.6016 -0.23,1.8555 -0.69,3.5 -1.42,4.9609 -0.71,1.4532 -1.75,2.6289 -3.1,3.5235 -1.37,0.8906 -3.23,1.2812 -5.6,1.1875 l -19.12,0 0,-23.5 -5.04,0 0,52.914 24.23,0"
|
||||
id="path3128"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2465.16,70.7109 c -1.02,1.6094 -2.27,2.9493 -3.71,4.0391 -1.47,1.0859 -3.08,1.9141 -4.82,2.4844 -1.75,0.5625 -3.59,0.8515 -5.53,0.8515 -3.5,0 -6.51,-0.6679 -9.03,-2 -2.52,-1.3359 -4.6,-3.0976 -6.18,-5.3007 -1.62,-2.1993 -2.8,-4.6836 -3.58,-7.4454 -0.76,-2.7695 -1.14,-5.6093 -1.14,-8.5273 0,-2.8633 0.38,-5.6914 1.14,-8.4844 0.78,-2.789 1.96,-5.2812 3.58,-7.4804 1.58,-2.1993 3.66,-3.9688 6.18,-5.2969 2.52,-1.3399 5.53,-2.0039 9.03,-2.0039 2.47,0 4.7,0.4453 6.66,1.332 2,0.8906 3.7,2.1016 5.13,3.6289 1.44,1.5274 2.6,3.3281 3.48,5.3711 0.9,2.0508 1.46,4.2695 1.71,6.6367 l 5.04,0 c -0.35,-3.2578 -1.13,-6.1953 -2.3,-8.8203 -1.19,-2.6172 -2.72,-4.8359 -4.59,-6.668 -1.88,-1.8281 -4.09,-3.2304 -6.63,-4.2226 -2.56,-0.9844 -5.37,-1.4844 -8.5,-1.4844 -4.15,0 -7.79,0.7617 -10.93,2.2656 -3.13,1.5079 -5.74,3.5196 -7.83,6.0391 -2.05,2.5156 -3.62,5.4297 -4.65,8.7461 -1.04,3.3008 -1.56,6.7812 -1.56,10.4414 0,3.6602 0.52,7.1445 1.56,10.4492 1.03,3.3125 2.6,6.2383 4.65,8.7813 2.09,2.5429 4.7,4.5742 7.83,6.0781 3.14,1.5078 6.78,2.2578 10.93,2.2578 2.52,0 4.97,-0.3711 7.38,-1.1094 2.39,-0.7382 4.57,-1.8398 6.52,-3.2968 1.95,-1.461 3.57,-3.25 4.89,-5.3711 1.31,-2.1289 2.14,-4.5703 2.48,-7.3399 l -5.04,0 c -0.45,2.0274 -1.17,3.8399 -2.17,5.4492"
|
||||
id="path3130"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2519.59,81.2695 0,-4.2929 -31.5,0 0,-19.1211 29.5,0 0,-4.3008 -29.5,0 0,-20.8945 31.86,0 0,-4.3047 -36.9,0 0,52.914 36.54,0"
|
||||
id="path3132"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 109.109,130.879 c -2.171,6.246 -5.242,11.781 -9.2145,16.601 -3.9765,4.825 -8.8007,8.7 -14.4765,11.637 -5.6758,2.938 -12.1133,4.395 -19.2969,4.395 -7.375,0 -13.9023,-1.457 -19.5781,-4.395 -5.6797,-2.937 -10.5039,-6.812 -14.4766,-11.637 -3.9726,-4.82 -7.1406,-10.41 -9.5078,-16.75 -2.3633,-6.332 -3.9258,-12.816 -4.6758,-19.433 l 94.7732,0 c -0.179,6.812 -1.371,13.348 -3.547,19.582 z M 20.5703,76.2539 c 1.8008,-6.9141 4.6875,-13.1055 8.6563,-18.5937 3.9765,-5.4883 8.9922,-10.0235 15.0429,-13.6133 6.0547,-3.6016 13.336,-5.3985 21.8516,-5.3985 13.0586,0 23.2734,3.4102 30.6484,10.2188 7.3755,6.8008 12.4885,15.8867 15.3205,27.2344 l 17.883,0 C 126.184,59.457 119.234,46.5898 109.109,37.5195 98.9922,28.4258 84.6602,23.8906 66.1211,23.8906 c -11.5352,0 -21.5234,2.043 -29.9336,6.1133 C 27.7578,34.0664 20.9023,39.6445 15.6094,46.7422 10.3125,53.8281 6.39063,62.0586 3.83203,71.4336 1.28125,80.7891 0,90.6719 0,101.086 c 0,9.641 1.28125,19.098 3.83203,28.371 2.5586,9.27 6.48047,17.551 11.77737,24.828 5.2929,7.285 12.1484,13.153 20.5781,17.606 8.4102,4.437 18.3984,6.664 29.9336,6.664 11.7266,0 21.7539,-2.375 30.0859,-7.102 8.32,-4.719 15.078,-10.922 20.285,-18.578 5.196,-7.66 8.938,-16.461 11.203,-26.395 2.278,-9.937 3.219,-20 2.84,-30.2222 l -112.6522,0 c 0,-6.4336 0.8867,-13.1055 2.6875,-20.0039"
|
||||
id="path3134"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 157.859,174.297 0,-25.258 0.571,0 c 3.41,8.895 9.457,16.039 18.164,21.426 8.695,5.398 18.254,8.09 28.66,8.09 10.219,0 18.777,-1.325 25.68,-3.977 6.91,-2.648 12.441,-6.379 16.601,-11.203 4.16,-4.824 7.098,-10.738 8.797,-17.734 1.699,-7.008 2.555,-14.864 2.555,-23.555 l 0,-94.2188 -17.875,0 0,91.3708 c 0,6.246 -0.567,12.059 -1.703,17.461 -1.141,5.387 -3.121,10.067 -5.957,14.047 -2.844,3.969 -6.676,7.09 -11.5,9.359 -4.821,2.274 -10.829,3.407 -18.02,3.407 -7.191,0 -13.578,-1.278 -19.152,-3.828 -5.578,-2.555 -10.309,-6.055 -14.192,-10.5 -3.879,-4.442 -6.91,-9.743 -9.082,-15.895 -2.172,-6.156 -3.355,-12.82 -3.547,-20.004 l 0,-85.4178 -17.871,0 0,146.4298 17.871,0"
|
||||
id="path3136"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 274.938,174.297 45.976,-128.5509 0.566,0 45.407,128.5509 18.449,0 -54.77,-146.4298 -19.019,0 -56.465,146.4298 19.856,0"
|
||||
id="path3138"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 409.707,174.297 0,-146.4298 -17.875,0 0,146.4298 17.875,0 z m 0,56.187 0,-28.664 -17.875,0 0,28.664 17.875,0"
|
||||
id="path3140"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 487.02,104.863 c 3.683,0 7.222,0.27 10.632,0.809 3.407,0.547 6.403,1.601 8.993,3.172 2.589,1.566 4.668,3.785 6.238,6.648 1.558,2.852 2.347,6.613 2.347,11.235 0,4.636 -0.789,8.39 -2.347,11.25 -1.57,2.859 -3.649,5.074 -6.238,6.64 -2.59,1.571 -5.586,2.629 -8.993,3.172 -3.41,0.547 -6.949,0.813 -10.632,0.813 l -24.934,0 0,-43.739 24.934,0 z m 8.793,68.68 c 9.128,0 16.898,-1.32 23.304,-3.988 6.406,-2.66 11.613,-6.16 15.633,-10.524 4.023,-4.359 6.961,-9.34 8.797,-14.922 1.84,-5.589 2.758,-11.379 2.758,-17.382 0,-5.852 -0.918,-11.614 -2.758,-17.27 -1.836,-5.652 -4.774,-10.664 -8.797,-15.0273 -4.02,-4.3633 -9.227,-7.8672 -15.633,-10.5234 -6.406,-2.6602 -14.176,-3.9844 -23.304,-3.9844 l -33.727,0 0,-52.336 -32.102,0 0,145.9571 65.829,0"
|
||||
id="path3142"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 614.273,76.7539 c -1.835,-0.6211 -3.812,-1.1289 -5.929,-1.5351 -2.114,-0.4102 -4.324,-0.75 -6.641,-1.0196 -2.316,-0.2773 -4.637,-0.6211 -6.953,-1.0273 -2.176,-0.4102 -4.328,-0.9571 -6.437,-1.6328 -2.114,-0.6836 -3.958,-1.6016 -5.52,-2.7618 -1.566,-1.1562 -2.832,-2.625 -3.777,-4.3945 -0.957,-1.7773 -1.438,-4.0234 -1.438,-6.7461 0,-2.5937 0.481,-4.7695 1.438,-6.5429 0.945,-1.7696 2.246,-3.168 3.879,-4.1915 1.636,-1.0234 3.543,-1.7382 5.726,-2.1484 2.176,-0.4101 4.426,-0.6094 6.746,-0.6094 5.723,0 10.145,0.9532 13.285,2.8672 3.133,1.9024 5.45,4.1875 6.953,6.8438 1.497,2.6562 2.418,5.3476 2.758,8.0742 0.336,2.7226 0.516,4.9101 0.516,6.543 l 0,10.8398 c -1.234,-1.1055 -2.766,-1.9492 -4.606,-2.5586 z m -57.339,40.9841 c 3,4.496 6.812,8.106 11.449,10.832 4.637,2.723 9.844,4.672 15.637,5.828 5.789,1.157 11.617,1.735 17.48,1.735 5.316,0 10.691,-0.375 16.145,-1.125 5.457,-0.75 10.425,-2.211 14.921,-4.395 4.504,-2.175 8.18,-5.207 11.043,-9.093 2.86,-3.883 4.297,-9.032 4.297,-15.434 l 0,-54.9922 c 0,-4.7774 0.27,-9.336 0.817,-13.6954 0.539,-4.3632 1.496,-7.6328 2.859,-9.8125 l -29.437,0 c -0.543,1.6329 -0.989,3.3008 -1.329,5.0118 -0.343,1.6992 -0.582,3.4414 -0.718,5.2109 -4.633,-4.7734 -10.082,-8.1133 -16.348,-10.0156 -6.273,-1.9063 -12.676,-2.8672 -19.219,-2.8672 -5.043,0 -9.746,0.6172 -14.105,1.8398 -4.367,1.2266 -8.18,3.1367 -11.449,5.7305 -3.27,2.5859 -5.825,5.8594 -7.668,9.8125 -1.84,3.9492 -2.758,8.6523 -2.758,14.1016 0,5.9961 1.058,10.9375 3.168,14.8242 2.109,3.8789 4.836,6.9726 8.179,9.2969 3.34,2.3164 7.157,4.0585 11.446,5.2148 4.297,1.1562 8.617,2.0742 12.98,2.7539 4.364,0.6836 8.656,1.2266 12.879,1.6367 4.227,0.4102 7.973,1.0235 11.25,1.8438 3.266,0.8125 5.856,2.0117 7.762,3.582 1.91,1.5664 2.793,3.8477 2.664,6.8435 0,3.137 -0.516,5.617 -1.535,7.461 -1.028,1.844 -2.395,3.266 -4.09,4.293 -1.707,1.02 -3.68,1.699 -5.93,2.039 -2.25,0.344 -4.672,0.516 -7.258,0.516 -5.718,0 -10.222,-1.223 -13.488,-3.68 -3.277,-2.453 -5.183,-6.543 -5.726,-12.265 l -29.032,0 c 0.41,6.816 2.118,12.46 5.114,16.968"
|
||||
id="path3144"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 720.172,133.277 0,-19.422 -21.254,0 0,-52.3355 c 0,-4.9023 0.812,-8.1718 2.449,-9.8047 1.637,-1.6406 4.903,-2.4609 9.817,-2.4609 1.632,0 3.195,0.0703 4.699,0.2031 1.496,0.1328 2.926,0.3438 4.289,0.6172 l 0,-22.4883 c -2.453,-0.414 -5.176,-0.6836 -8.176,-0.8203 -2.996,-0.1289 -5.926,-0.1992 -8.789,-0.1992 -4.5,0 -8.754,0.3047 -12.773,0.918 -4.024,0.6094 -7.563,1.8086 -10.629,3.5781 -3.071,1.7695 -5.489,4.293 -7.254,7.5586 -1.781,3.2773 -2.664,7.5703 -2.664,12.8828 l 0,62.3511 -17.578,0 0,19.422 17.578,0 0,31.684 29.031,0 0,-31.684 21.254,0"
|
||||
id="path3146"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 755.918,173.543 0,-54.984 0.613,0 c 3.684,6.125 8.387,10.586 14.11,13.379 5.722,2.796 11.312,4.195 16.761,4.195 7.77,0 14.137,-1.059 19.114,-3.164 4.972,-2.114 8.894,-5.043 11.754,-8.793 2.863,-3.75 4.871,-8.317 6.031,-13.699 1.152,-5.383 1.734,-11.3481 1.734,-17.8832 l 0,-65.0079 -29.027,0 0,59.6954 c 0,8.7148 -1.363,15.2227 -4.086,19.5157 -2.731,4.293 -7.567,6.433 -14.516,6.433 -7.902,0 -13.633,-2.343 -17.172,-7.039 -3.543,-4.703 -5.316,-12.441 -5.316,-23.2144 l 0,-55.3907 -29.023,0 0,145.9571 29.023,0"
|
||||
id="path3148"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 863.082,0 21.875,0 0,190.547 -21.875,0 0,-190.547 z"
|
||||
id="path3150"
|
||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 22 KiB |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104 26" role="img" fill="currentColor">
|
||||
<path id="ep-logo-name" d="M13.638 12.451a6.613 6.613 0 0 0-1.152-2.075 5.687 5.687 0 0 0-1.81-1.455c-.708-.369-1.513-.55-2.411-.55-.922 0-1.739.181-2.447.55a5.702 5.702 0 0 0-1.81 1.455 7.21 7.21 0 0 0-1.188 2.092 10.28 10.28 0 0 0-.586 2.43h11.848a8.013 8.013 0 0 0-.444-2.447zM2.571 19.277a6.885 6.885 0 0 0 1.082 2.324 6.187 6.187 0 0 0 1.88 1.702c.757.452 1.667.676 2.732.676 1.633 0 2.91-.427 3.83-1.277.923-.852 1.563-1.987 1.917-3.405h2.234c-.474 2.08-1.342 3.689-2.608 4.824-1.264 1.135-3.056 1.702-5.373 1.702-1.442 0-2.69-.254-3.742-.765-1.053-.507-1.91-1.203-2.572-2.092C1.29 22.082.8 21.052.48 19.88A13.991 13.991 0 0 1 0 16.174c0-1.206.16-2.388.479-3.547a9.56 9.56 0 0 1 1.472-3.103c.662-.91 1.519-1.643 2.572-2.2 1.051-.554 2.3-.833 3.742-.833 1.466 0 2.72.296 3.76.887A7.487 7.487 0 0 1 14.562 9.7c.65.959 1.118 2.058 1.401 3.3.284 1.243.402 2.5.354 3.777H2.234c0 .806.113 1.638.337 2.5M19.732 7.024v3.156h.07c.428-1.113 1.184-2.004 2.271-2.678a6.654 6.654 0 0 1 3.584-1.01c1.277 0 2.346.163 3.21.495.862.332 1.555.799 2.075 1.402.52.603.887 1.342 1.1 2.216.212.877.32 1.858.32 2.945v11.777h-2.235v-11.42c0-.782-.071-1.51-.214-2.184-.142-.673-.39-1.26-.745-1.757a3.61 3.61 0 0 0-1.436-1.17c-.603-.283-1.354-.425-2.253-.425-.898 0-1.697.16-2.395.479a5.221 5.221 0 0 0-1.772 1.31 6.034 6.034 0 0 0-1.136 1.988 8.128 8.128 0 0 0-.444 2.5v10.679h-2.234V7.024h2.234M34.367 7.024l5.747 16.067h.071L45.86 7.024h2.307l-6.846 18.303h-2.378L31.885 7.024h2.482M51.214 7.024v18.303h-2.235V7.024h2.235zm0-7.024V3.58h-2.235V0h2.235M61.037 15.703c.46 0 .902-.034 1.33-.103.424-.068.799-.2 1.122-.395.325-.195.584-.474.78-.833.196-.356.294-.825.294-1.404 0-.578-.098-1.047-.294-1.406a2.162 2.162 0 0 0-.78-.83 3.104 3.104 0 0 0-1.123-.395 8.39 8.39 0 0 0-1.329-.103H57.92v5.469h3.117zm1.099-8.587c1.14 0 2.112.166 2.913.498.801.335 1.452.772 1.953 1.316.503.545.871 1.167 1.1 1.866a6.89 6.89 0 0 1 .346 2.172c0 .733-.115 1.453-.346 2.159a5.043 5.043 0 0 1-1.1 1.88c-.501.544-1.152.984-1.953 1.316-.8.332-1.772.498-2.913.498H57.92v6.54h-4.013V7.116h8.229M76.944 19.216a5.26 5.26 0 0 1-.742.19c-.264.052-.54.096-.83.13-.29.034-.579.076-.87.127-.27.051-.54.12-.804.205-.263.085-.494.2-.69.344-.195.144-.354.33-.472.55-.12.222-.18.502-.18.844 0 .323.06.596.18.818.118.22.28.396.485.523.205.129.443.217.716.268.272.051.553.076.844.076.715 0 1.267-.117 1.66-.357.392-.239.68-.525.869-.857.187-.332.303-.668.344-1.008a6.93 6.93 0 0 0 .065-.818v-1.355a1.615 1.615 0 0 1-.575.32zm-7.168-5.124a4.345 4.345 0 0 1 1.43-1.353 6.257 6.257 0 0 1 1.956-.73 11.148 11.148 0 0 1 2.185-.215c.664 0 1.336.047 2.018.14a6.193 6.193 0 0 1 1.866.549 3.69 3.69 0 0 1 1.38 1.137c.356.486.537 1.128.537 1.93v6.874c0 .596.033 1.167.102 1.712.066.544.186.954.357 1.225h-3.68a5.23 5.23 0 0 1-.256-1.277 4.735 4.735 0 0 1-2.043 1.253 8.261 8.261 0 0 1-2.402.356c-.63 0-1.219-.076-1.763-.23a4.016 4.016 0 0 1-1.432-.715 3.34 3.34 0 0 1-.958-1.228c-.23-.493-.344-1.081-.344-1.762 0-.75.131-1.368.395-1.853a3.324 3.324 0 0 1 1.023-1.163 4.648 4.648 0 0 1 1.43-.651 15.515 15.515 0 0 1 1.623-.345 27.623 27.623 0 0 1 1.61-.202c.527-.052.996-.13 1.406-.232.408-.1.732-.252.97-.447.239-.195.349-.48.333-.857 0-.39-.065-.7-.192-.933a1.406 1.406 0 0 0-.511-.534 2.014 2.014 0 0 0-.741-.257 6.208 6.208 0 0 0-.907-.063c-.715 0-1.278.151-1.686.459-.41.308-.648.818-.716 1.533h-3.63c.052-.852.265-1.557.64-2.121M90.181 12.15v2.427h-2.657v6.543c0 .613.101 1.02.306 1.226.205.205.613.308 1.227.308.204 0 .399-.01.587-.027.188-.015.366-.042.537-.076v2.81a8.619 8.619 0 0 1-1.023.103c-.373.017-.74.024-1.098.024a10.41 10.41 0 0 1-1.597-.115 3.728 3.728 0 0 1-1.328-.446 2.356 2.356 0 0 1-.907-.945c-.222-.41-.333-.945-.333-1.61v-7.795h-2.198v-2.426h2.198V8.19h3.629v3.96h2.657M94.703 7.116v6.873h.075c.462-.764 1.05-1.323 1.764-1.672.716-.35 1.415-.523 2.096-.523.97 0 1.767.132 2.388.396.622.263 1.113.63 1.47 1.098.358.47.609 1.04.754 1.712.144.674.217 1.418.217 2.236v8.125h-3.629v-7.46c0-1.09-.17-1.905-.511-2.44-.34-.537-.945-.805-1.814-.805-.988 0-1.704.293-2.146.88-.443.587-.664 1.556-.664 2.901v6.924h-3.628V7.116h3.628" class="logo-main"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
@ -1,3 +0,0 @@
|
||||
<svg fill="currentColor" id="ep-logo-square" role="img" viewBox="0 0 65 65" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M26.538 25.283c-.532-1.519-1.274-2.861-2.24-4.037a11.163 11.163 0 0 0-3.522-2.828c-1.381-.712-2.948-1.07-4.697-1.07-1.791 0-3.379.358-4.76 1.07a11.11 11.11 0 0 0-3.522 2.828c-.966 1.176-1.737 2.533-2.308 4.07a19.839 19.839 0 0 0-1.139 4.728h23.047a15.559 15.559 0 0 0-.86-4.76zM5 38.57c.44 1.685 1.143 3.189 2.11 4.527.966 1.333 2.187 2.436 3.656 3.31 1.475.875 3.243 1.308 5.313 1.308 3.178 0 5.665-.83 7.456-2.485 1.793-1.65 3.037-3.867 3.726-6.626h4.35c-.922 4.054-2.613 7.179-5.073 9.39-2.46 2.208-5.947 3.315-10.46 3.315-2.802 0-5.233-.502-7.274-1.489-2.056-.986-3.721-2.348-5.01-4.072-1.284-1.724-2.241-3.725-2.861-6.005C.313 37.465 0 35.058 0 32.529c0-2.343.313-4.649.933-6.9.62-2.254 1.577-4.267 2.861-6.04 1.289-1.772 2.954-3.197 5.01-4.281 2.041-1.08 4.472-1.616 7.275-1.616 2.856 0 5.293.571 7.32 1.724 2.026 1.147 3.666 2.66 4.931 4.521 1.265 1.86 2.177 3.999 2.725 6.416a27.9 27.9 0 0 1 .692 7.348H4.35c0 1.567.215 3.188.65 4.868M49.301 31.456c.914 0 1.793-.07 2.638-.202.845-.136 1.586-.4 2.23-.78.641-.391 1.159-.942 1.548-1.656.387-.702.582-1.64.582-2.782 0-1.148-.195-2.08-.582-2.79-.39-.707-.907-1.26-1.547-1.65-.645-.386-1.386-.65-2.231-.78a16.554 16.554 0 0 0-2.638-.206h-6.176v10.846h6.176zm2.184-17.032c2.26 0 4.189.331 5.776.995 1.592.66 2.88 1.524 3.877 2.608a10.007 10.007 0 0 1 2.177 3.696c.46 1.393.684 2.828.684 4.313 0 1.455-.224 2.88-.684 4.28a9.955 9.955 0 0 1-2.177 3.727c-.997 1.079-2.285 1.953-3.877 2.607-1.587.664-3.516.992-5.776.992h-8.36v12.974h-7.964V14.424h16.324" class="logo-main"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 17 KiB |
BIN
static/images/uoa.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
@ -1,170 +0,0 @@
|
||||
/**
|
||||
* Discourse API Integration for enviPath Community
|
||||
* Handles fetching topics from the Discourse forum API
|
||||
*/
|
||||
|
||||
class DiscourseAPI {
|
||||
constructor() {
|
||||
this.baseUrl = 'https://community.envipath.org';
|
||||
this.categoryId = 10; // Announcements category
|
||||
this.limit = 3; // Number of topics to fetch
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch topics from Discourse API
|
||||
* @param {number} limit - Number of topics to fetch
|
||||
* @returns {Promise<Array>} Array of topic objects
|
||||
*/
|
||||
async fetchTopics(limit = this.limit) {
|
||||
try {
|
||||
const url = `${this.baseUrl}/c/announcements/${this.categoryId}.json`;
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return this.processTopics(data.topic_list.topics, limit);
|
||||
} catch (error) {
|
||||
console.error('Error fetching Discourse topics:', error);
|
||||
return this.getFallbackTopics();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process raw Discourse topics into standardized format
|
||||
* @param {Array} topics - Raw topics from Discourse API
|
||||
* @param {number} limit - Number of topics to return
|
||||
* @returns {Array} Processed topics
|
||||
*/
|
||||
processTopics(topics, limit) {
|
||||
return topics
|
||||
.slice(0, limit)
|
||||
.map(topic => ({
|
||||
id: topic.id,
|
||||
title: topic.title,
|
||||
excerpt: this.extractExcerpt(topic.excerpt),
|
||||
url: `${this.baseUrl}/t/${topic.slug}/${topic.id}`,
|
||||
replies: topic.reply_count,
|
||||
views: topic.views,
|
||||
created_at: topic.created_at,
|
||||
category: 'Announcements',
|
||||
category_id: this.categoryId,
|
||||
author: topic.last_poster_username,
|
||||
author_avatar: this.getAvatarUrl(topic.last_poster_username)
|
||||
}))
|
||||
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); // Latest first
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract excerpt from topic content
|
||||
* @param {string} excerpt - Raw excerpt from Discourse
|
||||
* @returns {string} Cleaned excerpt
|
||||
*/
|
||||
extractExcerpt(excerpt) {
|
||||
if (!excerpt) return 'Click to read more';
|
||||
|
||||
// Remove HTML tags and clean up; collapse whitespace; do not add manual ellipsis
|
||||
return excerpt
|
||||
.replace(/<[^>]*>/g, '') // Remove HTML tags
|
||||
.replace(/ /g, ' ') // Replace with spaces
|
||||
.replace(/&/g, '&') // Replace & with &
|
||||
.replace(/</g, '<') // Replace < with <
|
||||
.replace(/>/g, '>') // Replace > with >
|
||||
.replace(/\s+/g, ' ') // Collapse all whitespace/newlines
|
||||
.trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get avatar URL for user
|
||||
* @param {string} username - Username
|
||||
* @returns {string} Avatar URL
|
||||
*/
|
||||
getAvatarUrl(username) {
|
||||
if (!username) return `${this.baseUrl}/letter_avatar_proxy/v4/letter/u/1.png`;
|
||||
return `${this.baseUrl}/user_avatar/${this.baseUrl.replace('https://', '')}/${username}/40/1_1.png`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fallback topics when API fails
|
||||
* @returns {Array} Fallback topics
|
||||
*/
|
||||
getFallbackTopics() {
|
||||
return [
|
||||
{
|
||||
id: 110,
|
||||
title: "enviPath Beta Update: Major Improvements to Prediction, Analysis & Collaboration!",
|
||||
excerpt: "We're excited to announce major updates to the enviPath beta platform! This release includes significant improvements to our prediction algorithms, enhanced analysis tools, and new collaboration features that will make environmental biotransformation research more accessible and efficient.",
|
||||
url: "https://community.envipath.org/t/envipath-beta-update-major-improvements-to-prediction-analysis-collaboration/110",
|
||||
replies: 0,
|
||||
views: 16,
|
||||
created_at: "2025-09-23T00:00:00Z",
|
||||
category: "Announcements",
|
||||
category_id: 10,
|
||||
author: "wicker",
|
||||
author_avatar: "https://community.envipath.org/user_avatar/community.envipath.org/wicker/40/1_1.png"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date for display
|
||||
* @param {string} dateString - ISO date string
|
||||
* @returns {string} Formatted date
|
||||
*/
|
||||
formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load topics and call render function
|
||||
* @param {string} containerId - ID of container element
|
||||
* @param {Function} renderCallback - Function to render topics
|
||||
*/
|
||||
async loadTopics(containerId = 'community-news-container', renderCallback = null) {
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container) {
|
||||
console.error(`Container with ID '${containerId}' not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide loading spinner
|
||||
const loading = document.getElementById('loading');
|
||||
if (loading) {
|
||||
loading.style.display = 'none';
|
||||
}
|
||||
|
||||
try {
|
||||
const topics = await this.fetchTopics();
|
||||
|
||||
if (renderCallback && typeof renderCallback === 'function') {
|
||||
renderCallback(topics);
|
||||
} else {
|
||||
// Default rendering - just log topics
|
||||
console.log('Topics loaded:', topics);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading topics:', error);
|
||||
container.innerHTML = '<p class="text-neutral">No updates found. Head over to the <a href="https://community.envipath.org" target="_blank" class="link link-primary">community</a> to see the latest discussions.</p>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other scripts
|
||||
window.DiscourseAPI = DiscourseAPI;
|
||||
|
||||
// Auto-initialize if container exists
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (document.getElementById('community-news-container')) {
|
||||
const discourseAPI = new DiscourseAPI();
|
||||
discourseAPI.loadTopics('community-news-container', function(topics) {
|
||||
// This will be handled by the template's render function
|
||||
if (window.renderDiscourseTopics) {
|
||||
window.renderDiscourseTopics(topics);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_compound_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Compound</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_compound_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Compound</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,11 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#new_compound_structure_modal"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Compound Structure</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_compound_structure_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Compound Structure</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_edge_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Edge</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_edge_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Edge</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,5 +1,4 @@
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_group_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Group</a
|
||||
>
|
||||
<a role="button" data-toggle="modal" data-target="#new_group_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Group</a>
|
||||
</li>
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit and meta.enabled_features.MODEL_BUILDING %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_model_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Model</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_model_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Model</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_node_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Node</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_node_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Node</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,20 +1,12 @@
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_package_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Package</a
|
||||
>
|
||||
<a role="button" data-toggle="modal" data-target="#new_package_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Package</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#import_package_modal">
|
||||
<span class="glyphicon glyphicon-import"></span> Import Package from JSON</a
|
||||
>
|
||||
<a role="button" data-toggle="modal" data-target="#import_package_modal">
|
||||
<span class="glyphicon glyphicon-import"></span> Import Package from JSON</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#import_legacy_package_modal"
|
||||
>
|
||||
<span class="glyphicon glyphicon-import"></span> Import Package from legacy
|
||||
JSON</a
|
||||
>
|
||||
</li>
|
||||
<a role="button" data-toggle="modal" data-target="#import_legacy_package_modal">
|
||||
<span class="glyphicon glyphicon-import"></span> Import Package from legacy JSON</a>
|
||||
</li>
|
||||
@ -1,9 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
href="{% if meta.current_package %}{{ meta.current_package.url }}/predict{% else %}{{ meta.server_url }}/predict{% endif %}"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Pathway</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#predict_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Pathway</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_reaction_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Reaction</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_reaction_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Reaction</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_rule_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Rule</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_rule_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Rule</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_scenario_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Scenario</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_scenario_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span> New Scenario</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,7 +1,6 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_setting_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span>New Setting</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_setting_modal">
|
||||
<span class="glyphicon glyphicon-plus"></span>New Setting</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,43 +1,32 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_compound_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#add_structure_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Add Structure</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#generic_set_external_reference_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_compound_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#add_structure_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Add Structure</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_set_external_reference_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a>
|
||||
</li>
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,35 +1,22 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#edit_compound_structure_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#generic_set_external_reference_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_compound_structure_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_set_external_reference_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Edge</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Edge</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_group_member_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Add/Remove Member</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Group</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<i class="glyphicon glyphicon-trash"></i> Add/Remove Member</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Group</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,22 +1,18 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_model_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Model</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#evaluate_model_modal">
|
||||
<i class="glyphicon glyphicon-ok"></i> Evaluate Model</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#retrain_model_modal">
|
||||
<i class="glyphicon glyphicon-repeat"></i> Retrain Model</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Model</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_model_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Model</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#evaluate_model_modal">
|
||||
<i class="glyphicon glyphicon-ok"></i> Evaluate Model</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#retrain_model_modal">
|
||||
<i class="glyphicon glyphicon-repeat"></i> Retrain Model</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Model</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,22 +1,18 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_node_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Node</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Node</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_node_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Node</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Node</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,36 +1,26 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_package_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Package</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#edit_package_permissions_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-user"></i> Edit Permissions</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#publish_package_modal">
|
||||
<i class="glyphicon glyphicon-bullhorn"></i> Publish Package</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#export_package_modal">
|
||||
<i class="glyphicon glyphicon-bullhorn"></i> Export Package as JSON</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_license_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> License</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Package</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_package_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Package</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_package_permissions_modal">
|
||||
<i class="glyphicon glyphicon-user"></i> Edit Permissions</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#publish_package_modal">
|
||||
<i class="glyphicon glyphicon-bullhorn"></i> Publish Package</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#export_package_modal">
|
||||
<i class="glyphicon glyphicon-bullhorn"></i> Export Package as JSON</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_license_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> License</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Package</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,92 +1,59 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#add_pathway_node_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Add Compound</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Add Reaction</a
|
||||
>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#add_pathway_node_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Add Compound</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Add Reaction</a>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="button"
|
||||
data-toggle="modal"
|
||||
data-target="#download_pathway_csv_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-floppy-save"></i> Download Pathway as CSV</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="button"
|
||||
data-toggle="modal"
|
||||
data-target="#download_pathway_image_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-floppy-save"></i> Download Pathway as Image</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#download_pathway_csv_modal">
|
||||
<i class="glyphicon glyphicon-floppy-save"></i> Download Pathway as CSV</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#download_pathway_image_modal">
|
||||
<i class="glyphicon glyphicon-floppy-save"></i> Download Pathway as Image</a>
|
||||
</li>
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
class="button"
|
||||
data-toggle="modal"
|
||||
data-target="#identify_missing_rules_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-question-sign"></i> Identify Missing
|
||||
Rules</a
|
||||
>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#edit_pathway_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Pathway</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a
|
||||
>
|
||||
</li>
|
||||
{# <li>#}
|
||||
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
|
||||
{# <i class="glyphicon glyphicon-plus"></i> Calculate Compound Properties</a>#}
|
||||
{# </li>#}
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<a
|
||||
class="button"
|
||||
data-toggle="modal"
|
||||
data-target="#delete_pathway_node_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="button"
|
||||
data-toggle="modal"
|
||||
data-target="#delete_pathway_edge_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Pathway</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#identify_missing_rules_modal">
|
||||
<i class="glyphicon glyphicon-question-sign"></i> Identify Missing Rules</a>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#edit_pathway_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Pathway</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
{# <li>#}
|
||||
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
|
||||
{# <i class="glyphicon glyphicon-plus"></i> Calculate Compound Properties</a>#}
|
||||
{# </li>#}
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#delete_pathway_node_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#delete_pathway_edge_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Pathway</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,38 +1,28 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_reaction_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#generic_set_external_reference_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_reaction_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_set_external_reference_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a>
|
||||
</li>
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,29 +1,24 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
<i class="glyphicon glyphicon-duplicate"></i> Copy</a>
|
||||
</li>
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Rule</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Rule</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@ -1,25 +1,14 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
class="button"
|
||||
data-toggle="modal"
|
||||
data-target="#add_additional_information_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-trash"></i> Add Additional Information</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="button"
|
||||
data-toggle="modal"
|
||||
data-target="#update_scenario_additional_information_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-trash"></i> Set Additional Information</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Scenario</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#add_additional_information_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Add Additional Information</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#update_scenario_additional_information_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Set Additional Information</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Scenario</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,30 +1,22 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_user_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Update</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_password_modal">
|
||||
<i class="glyphicon glyphicon-lock"></i> Update Password</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="modal"
|
||||
data-target="#new_prediction_setting_modal"
|
||||
>
|
||||
<i class="glyphicon glyphicon-plus"></i> New Prediction Setting</a
|
||||
>
|
||||
</li>
|
||||
{# <li>#}
|
||||
{# <a role="button" data-toggle="modal" data-target="#manage_api_token_modal">#}
|
||||
{# <i class="glyphicon glyphicon-console"></i> Manage API Token</a>#}
|
||||
{# </li>#}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Account</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_user_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Update</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#edit_password_modal">
|
||||
<i class="glyphicon glyphicon-lock"></i> Update Password</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#new_prediction_setting_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> New Prediction Setting</a>
|
||||
</li>
|
||||
{# <li>#}
|
||||
{# <a role="button" data-toggle="modal" data-target="#manage_api_token_modal">#}
|
||||
{# <i class="glyphicon glyphicon-console"></i> Manage API Token</a>#}
|
||||
{# </li>#}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Account</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,17 +1,12 @@
|
||||
{% extends "framework.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div id="searchContent">
|
||||
|
||||
<div id=searchContent>
|
||||
<form id="admin-form" action="{{ SERVER_BASE }}/admin" method="post">
|
||||
<div class="form-group">
|
||||
<label for="textarea">Query</label>
|
||||
<textarea
|
||||
id="textarea"
|
||||
class="form-control"
|
||||
rows="10"
|
||||
placeholder="Paste query here"
|
||||
required
|
||||
>
|
||||
<div class="form-group">
|
||||
<label for="textarea">Query</label>
|
||||
<textarea id="textarea" class="form-control" rows="10" placeholder="Paste query here" required>
|
||||
PREFIX pps: <http://localhost:8080/vocabulary#>
|
||||
SELECT ?name (count(?objId) as ?xcnt)
|
||||
WHERE {
|
||||
@ -20,29 +15,32 @@ WHERE {
|
||||
?packageId pps:reviewStatus 'reviewed' .
|
||||
?packageId pps:pathway ?objId .
|
||||
} GROUP BY ?name
|
||||
</textarea
|
||||
>
|
||||
</div>
|
||||
<button id="submit" type="button" class="btn btn-primary">Submit</button>
|
||||
</textarea>
|
||||
</div>
|
||||
<button id="submit" type="button" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
<p></p>
|
||||
</div>
|
||||
<div id="results"></div>
|
||||
<div id="loading"></div>
|
||||
<script>
|
||||
$(function () {
|
||||
$("#submit").on("click", function () {
|
||||
</div>
|
||||
<div id="results">
|
||||
</div>
|
||||
<div id="loading"></div>
|
||||
</div>
|
||||
<script>
|
||||
$(function() {
|
||||
$('#submit').on('click', function() {
|
||||
|
||||
makeLoadingGif("#loading", "{% static '/images/wait.gif' %}");
|
||||
|
||||
data = {
|
||||
query: $("#textarea").val(),
|
||||
};
|
||||
"query": $("#textarea").val()
|
||||
}
|
||||
|
||||
$.post("{{ SERVER_BASE }}/expire", data, function (result) {
|
||||
$("#loading").empty();
|
||||
queryResultToTable("results", result);
|
||||
});
|
||||
});
|
||||
$.post("{{ SERVER_BASE }}/expire", data, function(result) {
|
||||
$("#loading").empty();
|
||||
queryResultToTable("results", result);
|
||||
})
|
||||
});
|
||||
</script>
|
||||
})
|
||||
</script>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@ -2,79 +2,70 @@
|
||||
{% load static %}
|
||||
{% load envipytags %}
|
||||
{% block content %}
|
||||
<div class="panel-group" id="reviewListAccordion">
|
||||
<div class="panel panel-default">
|
||||
<div
|
||||
class="panel-heading"
|
||||
id="headingPanel"
|
||||
style="font-size:2rem;height: 46px"
|
||||
>
|
||||
Jobs
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>Job Logs Desc</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="panel panel-default panel-heading list-group-item"
|
||||
style="background-color:silver"
|
||||
>
|
||||
<h4 class="panel-title">
|
||||
<a
|
||||
id="job-accordion-link"
|
||||
data-toggle="collapse"
|
||||
data-parent="#job-accordion"
|
||||
href="#jobs"
|
||||
>
|
||||
Jobs
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="jobs" class="panel-collapse in collapse">
|
||||
<div class="panel-body list-group-item" id="job-content">
|
||||
<table class="table-bordered table-hover table">
|
||||
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
||||
<th scope="col">ID</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Queued</th>
|
||||
<th scope="col">Done</th>
|
||||
<th scope="col">Result</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for job in jobs %}
|
||||
<tr>
|
||||
<td>{{ job.task_id }}</td>
|
||||
<td>{{ job.job_name }}</td>
|
||||
<td>{{ job.status }}</td>
|
||||
<td>{{ job.created }}</td>
|
||||
<td>{{ job.done_at }}</td>
|
||||
{% if job.task_result and job.task_result|is_url == True %}
|
||||
<td><a href="{{ job.task_result }}">Result</a></td>
|
||||
{% elif job.task_result %}
|
||||
<td>{{ job.task_result|slice:"40" }}...</td>
|
||||
{% else %}
|
||||
<td>Empty</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="panel-group" id="reviewListAccordion">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||
Jobs
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Job Logs Desc
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
<h4 class="panel-title">
|
||||
<a id="job-accordion-link" data-toggle="collapse" data-parent="#job-accordion" href="#jobs">
|
||||
Jobs
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="jobs"
|
||||
class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item" id="job-content">
|
||||
<table class="table table-bordered table-hover">
|
||||
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
||||
<th scope="col">ID</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Queued</th>
|
||||
<th scope="col">Done</th>
|
||||
<th scope="col">Result</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for job in jobs %}
|
||||
<tr>
|
||||
<td>{{ job.task_id }}</td>
|
||||
<td>{{ job.job_name }}</td>
|
||||
<td>{{ job.status }}</td>
|
||||
<td>{{ job.created }}</td>
|
||||
<td>{{ job.done_at }}</td>
|
||||
{% if job.task_result and job.task_result|is_url == True %}
|
||||
<td><a href="{{ job.task_result }}">Result</a></td>
|
||||
{% elif job.task_result %}
|
||||
<td>{{ job.task_result|slice:"40" }}...</td>
|
||||
{% else %}
|
||||
<td>Empty</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Unreviewable objects such as User / Group / Setting -->
|
||||
<ul class='list-group'>
|
||||
{% for obj in objects %}
|
||||
{% if object_type == 'user' %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.username }}</a>
|
||||
{% else %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Unreviewable objects such as User / Group / Setting -->
|
||||
<ul class="list-group">
|
||||
{% for obj in objects %}
|
||||
{% if object_type == 'user' %}
|
||||
<a class="list-group-item" href="{{ obj.url }}"
|
||||
>{{ obj.username }}</a
|
||||
>
|
||||
{% else %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
@ -2,427 +2,269 @@
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
|
||||
{% if object_type != 'package' %}
|
||||
<div>
|
||||
<div id="load-all-error" style="display: none;">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<span
|
||||
class="glyphicon glyphicon-exclamation-sign"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span class="sr-only">Error:</span>
|
||||
Getting objects failed!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
id="object-search"
|
||||
class="form-control"
|
||||
placeholder="Search by name"
|
||||
style="display: none;"
|
||||
/>
|
||||
<p></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% if object_type == 'package' %}
|
||||
{% include "modals/collections/new_package_modal.html" %}
|
||||
{% include "modals/collections/import_package_modal.html" %}
|
||||
{% include "modals/collections/import_legacy_package_modal.html" %}
|
||||
{% elif object_type == 'compound' %}
|
||||
{% include "modals/collections/new_compound_modal.html" %}
|
||||
{% elif object_type == 'rule' %}
|
||||
{% include "modals/collections/new_rule_modal.html" %}
|
||||
{% elif object_type == 'reaction' %}
|
||||
{% include "modals/collections/new_reaction_modal.html" %}
|
||||
{% elif object_type == 'pathway' %}
|
||||
{# {% include "modals/collections/new_pathway_modal.html" %} #}
|
||||
{% elif object_type == 'node' %}
|
||||
{% include "modals/collections/new_node_modal.html" %}
|
||||
{% elif object_type == 'edge' %}
|
||||
{% include "modals/collections/new_edge_modal.html" %}
|
||||
{% elif object_type == 'scenario' %}
|
||||
{% include "modals/collections/new_scenario_modal.html" %}
|
||||
{% elif object_type == 'model' %}
|
||||
{% include "modals/collections/new_model_modal.html" %}
|
||||
{% elif object_type == 'setting' %}
|
||||
{#{% include "modals/collections/new_setting_modal.html" %}#}
|
||||
{% elif object_type == 'user' %}
|
||||
<div></div>
|
||||
{% elif object_type == 'group' %}
|
||||
{% include "modals/collections/new_group_modal.html" %}
|
||||
{% endif %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
<div class="panel-group" id="reviewListAccordion">
|
||||
<div class="panel panel-default">
|
||||
<div
|
||||
class="panel-heading"
|
||||
id="headingPanel"
|
||||
style="font-size:2rem;height: 46px"
|
||||
>
|
||||
{% if object_type == 'package' %}
|
||||
Packages
|
||||
{% elif object_type == 'compound' %}
|
||||
Compounds
|
||||
{% elif object_type == 'structure' %}
|
||||
Compound structures
|
||||
{% elif object_type == 'rule' %}
|
||||
Rules
|
||||
{% elif object_type == 'reaction' %}
|
||||
Reactions
|
||||
{% elif object_type == 'pathway' %}
|
||||
Pathways
|
||||
{% elif object_type == 'node' %}
|
||||
Nodes
|
||||
{% elif object_type == 'edge' %}
|
||||
Edges
|
||||
{% elif object_type == 'scenario' %}
|
||||
Scenarios
|
||||
{% elif object_type == 'model' %}
|
||||
Model
|
||||
{% elif object_type == 'setting' %}
|
||||
Settings
|
||||
{% elif object_type == 'user' %}
|
||||
Users
|
||||
{% elif object_type == 'group' %}
|
||||
Groups
|
||||
{% endif %}
|
||||
<div
|
||||
id="actionsButton"
|
||||
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
|
||||
class="dropdown"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
class="dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
><span class="glyphicon glyphicon-wrench"></span> Actions
|
||||
<span class="caret"></span><span style="padding-right:1em"></span
|
||||
></a>
|
||||
<ul id="actionsList" class="dropdown-menu">
|
||||
{% block actions %}
|
||||
{% if object_type == 'package' %}
|
||||
{% include "actions/collections/package.html" %}
|
||||
{% elif object_type == 'compound' %}
|
||||
{% include "actions/collections/compound.html" %}
|
||||
{% elif object_type == 'structure' %}
|
||||
{% include "actions/collections/compound_structure.html" %}
|
||||
{% elif object_type == 'rule' %}
|
||||
{% include "actions/collections/rule.html" %}
|
||||
{% elif object_type == 'reaction' %}
|
||||
{% include "actions/collections/reaction.html" %}
|
||||
{% elif object_type == 'setting' %}
|
||||
{% include "actions/collections/setting.html" %}
|
||||
{% elif object_type == 'scenario' %}
|
||||
{% include "actions/collections/scenario.html" %}
|
||||
{% elif object_type == 'model' %}
|
||||
{% include "actions/collections/model.html" %}
|
||||
{% elif object_type == 'pathway' %}
|
||||
{% include "actions/collections/pathway.html" %}
|
||||
{% elif object_type == 'node' %}
|
||||
{% include "actions/collections/node.html" %}
|
||||
{% elif object_type == 'edge' %}
|
||||
{% include "actions/collections/edge.html" %}
|
||||
{% elif object_type == 'group' %}
|
||||
{% include "actions/collections/group.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<!-- Set Text above links -->
|
||||
{% if object_type == 'package' %}
|
||||
<p>
|
||||
A package contains pathways, rules, etc. and can reflect specific
|
||||
experimental conditions.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'compound' %}
|
||||
<p>
|
||||
A compound stores the structure of a molecule and can include
|
||||
meta-information.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/compounds"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'structure' %}
|
||||
<p>
|
||||
The structures stored in this compound
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/compounds"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'rule' %}
|
||||
<p>
|
||||
A rule describes a biotransformation reaction template that is
|
||||
defined as SMIRKS.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/Rules"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'reaction' %}
|
||||
<p>
|
||||
A reaction is a specific biotransformation from educt compounds to
|
||||
product compounds.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/reactions"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'pathway' %}
|
||||
<p>
|
||||
A pathway displays the (predicted) biodegradation of a compound as
|
||||
graph.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/pathways"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'node' %}
|
||||
<p>
|
||||
Nodes represent the (predicted) compounds in a graph.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/nodes"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'edge' %}
|
||||
<p>
|
||||
Edges represent the links between Nodes in a graph
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/edges"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'scenario' %}
|
||||
<p>
|
||||
A scenario contains meta-information that can be attached to other
|
||||
data (compounds, rules, ..).
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/scenarios"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'model' %}
|
||||
<p>
|
||||
A model applies machine learning to limit the combinatorial
|
||||
explosion.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/relative_reasoning"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'setting' %}
|
||||
<p>
|
||||
A setting includes configuration parameters for pathway predictions.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/settings"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'user' %}
|
||||
<p>
|
||||
Register now to create own packages and to submit and manage your
|
||||
data.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/users"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'group' %}
|
||||
<p>
|
||||
Users can team up in groups to share packages.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/groups"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<!-- If theres nothing to show extend the text above -->
|
||||
{% if reviewed_objects and unreviewed_objects %}
|
||||
{% if reviewed_objects|length == 0 and unreviewed_objects|length == 0 %}
|
||||
<p>
|
||||
Nothing found. There are two possible reasons: <br /><br />1.
|
||||
There is no content yet.<br />2. You have no reading
|
||||
permissions.<br /><br />Please be sure you have at least reading
|
||||
permissions.
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if reviewed_objects %}
|
||||
{% if reviewed_objects|length > 0 %}
|
||||
<div
|
||||
class="panel panel-default panel-heading list-group-item"
|
||||
style="background-color:silver"
|
||||
>
|
||||
<h4 class="panel-title">
|
||||
<a
|
||||
id="ReviewedLink"
|
||||
data-toggle="collapse"
|
||||
data-parent="#reviewListAccordion"
|
||||
href="#Reviewed"
|
||||
>Reviewed</a
|
||||
>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="Reviewed" class="panel-collapse in collapse">
|
||||
<div class="panel-body list-group-item" id="ReviewedContent">
|
||||
{% if object_type == 'package' %}
|
||||
{% for obj in reviewed_objects %}
|
||||
<a class="list-group-item" href="{{ obj.url }}"
|
||||
>{{ obj.name|safe }}
|
||||
<span
|
||||
class="glyphicon glyphicon-star"
|
||||
aria-hidden="true"
|
||||
style="float:right"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title=""
|
||||
data-original-title="Reviewed"
|
||||
>
|
||||
</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for obj in reviewed_objects|slice:":50" %}
|
||||
<a class="list-group-item" href="{{ obj.url }}"
|
||||
>{{ obj.name|safe }}{# <i>({{ obj.package.name }})</i> #}
|
||||
<span
|
||||
class="glyphicon glyphicon-star"
|
||||
aria-hidden="true"
|
||||
style="float:right"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title=""
|
||||
data-original-title="Reviewed"
|
||||
>
|
||||
</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if object_type != 'package' %}
|
||||
<div>
|
||||
<div id="load-all-error" style="display: none;">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
|
||||
<span class="sr-only">Error:</span>
|
||||
Getting objects failed!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="text" id="object-search" class="form-control" placeholder="Search by name"
|
||||
style="display: none;">
|
||||
<p></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% if object_type == 'package' %}
|
||||
{% include "modals/collections/new_package_modal.html" %}
|
||||
{% include "modals/collections/import_package_modal.html" %}
|
||||
{% include "modals/collections/import_legacy_package_modal.html" %}
|
||||
{% elif object_type == 'compound' %}
|
||||
{% include "modals/collections/new_compound_modal.html" %}
|
||||
{% elif object_type == 'rule' %}
|
||||
{% include "modals/collections/new_rule_modal.html" %}
|
||||
{% elif object_type == 'reaction' %}
|
||||
{% include "modals/collections/new_reaction_modal.html" %}
|
||||
{% elif object_type == 'pathway' %}
|
||||
{# {% include "modals/collections/new_pathway_modal.html" %} #}
|
||||
{% elif object_type == 'node' %}
|
||||
{% include "modals/collections/new_node_modal.html" %}
|
||||
{% elif object_type == 'edge' %}
|
||||
{% include "modals/collections/new_edge_modal.html" %}
|
||||
{% elif object_type == 'scenario' %}
|
||||
{% include "modals/collections/new_scenario_modal.html" %}
|
||||
{% elif object_type == 'model' %}
|
||||
{% include "modals/collections/new_model_modal.html" %}
|
||||
{% elif object_type == 'setting' %}
|
||||
{#{% include "modals/collections/new_setting_modal.html" %}#}
|
||||
{% elif object_type == 'user' %}
|
||||
<div></div>
|
||||
{% elif object_type == 'group' %}
|
||||
{% include "modals/collections/new_group_modal.html" %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if unreviewed_objects %}
|
||||
<div
|
||||
class="panel panel-default panel-heading list-group-item"
|
||||
style="background-color:silver"
|
||||
>
|
||||
<h4 class="panel-title">
|
||||
<a
|
||||
id="UnreviewedLink"
|
||||
data-toggle="collapse"
|
||||
data-parent="#unReviewListAccordion"
|
||||
href="#Unreviewed"
|
||||
>Unreviewed</a
|
||||
>
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
id="Unreviewed"
|
||||
class="panel-collapse {% if reviewed_objects|length == 0 or object_type == 'package' %}in{% endif %} collapse"
|
||||
>
|
||||
<div class="panel-body list-group-item" id="UnreviewedContent">
|
||||
{% endblock action_modals %}
|
||||
|
||||
<div class="panel-group" id="reviewListAccordion">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||
{% if object_type == 'package' %}
|
||||
{% for obj in unreviewed_objects %}
|
||||
<a class="list-group-item" href="{{ obj.url }}"
|
||||
>{{ obj.name|safe }}</a
|
||||
>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for obj in unreviewed_objects|slice:":50" %}
|
||||
<a class="list-group-item" href="{{ obj.url }}"
|
||||
>{{ obj.name|safe }}</a
|
||||
>
|
||||
{% endfor %}
|
||||
Packages
|
||||
{% elif object_type == 'compound' %}
|
||||
Compounds
|
||||
{% elif object_type == 'structure' %}
|
||||
Compound structures
|
||||
{% elif object_type == 'rule' %}
|
||||
Rules
|
||||
{% elif object_type == 'reaction' %}
|
||||
Reactions
|
||||
{% elif object_type == 'pathway' %}
|
||||
Pathways
|
||||
{% elif object_type == 'node' %}
|
||||
Nodes
|
||||
{% elif object_type == 'edge' %}
|
||||
Edges
|
||||
{% elif object_type == 'scenario' %}
|
||||
Scenarios
|
||||
{% elif object_type == 'model' %}
|
||||
Model
|
||||
{% elif object_type == 'setting' %}
|
||||
Settings
|
||||
{% elif object_type == 'user' %}
|
||||
Users
|
||||
{% elif object_type == 'group' %}
|
||||
Groups
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="actionsButton"
|
||||
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
|
||||
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
aria-haspopup="true" aria-expanded="false"><span
|
||||
class="glyphicon glyphicon-wrench"></span> Actions <span class="caret"></span><span
|
||||
style="padding-right:1em"></span></a>
|
||||
<ul id="actionsList" class="dropdown-menu">
|
||||
{% block actions %}
|
||||
{% if object_type == 'package' %}
|
||||
{% include "actions/collections/package.html" %}
|
||||
{% elif object_type == 'compound' %}
|
||||
{% include "actions/collections/compound.html" %}
|
||||
{% elif object_type == 'structure' %}
|
||||
{% include "actions/collections/compound_structure.html" %}
|
||||
{% elif object_type == 'rule' %}
|
||||
{% include "actions/collections/rule.html" %}
|
||||
{% elif object_type == 'reaction' %}
|
||||
{% include "actions/collections/reaction.html" %}
|
||||
{% elif object_type == 'setting' %}
|
||||
{% include "actions/collections/setting.html" %}
|
||||
{% elif object_type == 'scenario' %}
|
||||
{% include "actions/collections/scenario.html" %}
|
||||
{% elif object_type == 'model' %}
|
||||
{% include "actions/collections/model.html" %}
|
||||
{% elif object_type == 'pathway' %}
|
||||
{% include "actions/collections/pathway.html" %}
|
||||
{% elif object_type == 'node' %}
|
||||
{% include "actions/collections/node.html" %}
|
||||
{% elif object_type == 'edge' %}
|
||||
{% include "actions/collections/edge.html" %}
|
||||
{% elif object_type == 'group' %}
|
||||
{% include "actions/collections/group.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if objects %}
|
||||
<!-- Unreviewable objects such as User / Group / Setting -->
|
||||
<ul class="list-group">
|
||||
{% for obj in objects %}
|
||||
{% if object_type == 'user' %}
|
||||
<a class="list-group-item" href="{{ obj.url }}"
|
||||
>{{ obj.username|safe }}</a
|
||||
>
|
||||
{% else %}
|
||||
<a class="list-group-item" href="{{ obj.url }}"
|
||||
>{{ obj.name|safe }}</a
|
||||
>
|
||||
<div class="panel-body">
|
||||
<!-- Set Text above links -->
|
||||
{% if object_type == 'package' %}
|
||||
<p>A package contains pathways, rules, etc. and can reflect specific experimental
|
||||
conditions. <a target="_blank" href="https://wiki.envipath.org/index.php/packages" role="button">Learn
|
||||
more >></a></p>
|
||||
{% elif object_type == 'compound' %}
|
||||
<p>A compound stores the structure of a molecule and can include meta-information.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/compounds" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'structure' %}
|
||||
<p>The structures stored in this compound
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/compounds" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'rule' %}
|
||||
<p>A rule describes a biotransformation reaction template that is defined as SMIRKS.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/Rules" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'reaction' %}
|
||||
<p>A reaction is a specific biotransformation from educt compounds to product compounds.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/reactions" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'pathway' %}
|
||||
<p>A pathway displays the (predicted) biodegradation of a compound as graph.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/pathways" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'node' %}
|
||||
<p>Nodes represent the (predicted) compounds in a graph.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/nodes" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'edge' %}
|
||||
<p>Edges represent the links between Nodes in a graph
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/edges" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'scenario' %}
|
||||
<p>A scenario contains meta-information that can be attached to other data (compounds, rules, ..).
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/scenarios" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'model' %}
|
||||
<p>A model applies machine learning to limit the combinatorial explosion.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/relative_reasoning" role="button">Learn
|
||||
more
|
||||
>></a></p>
|
||||
{% elif object_type == 'setting' %}
|
||||
<p>A setting includes configuration parameters for pathway predictions.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/settings" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'user' %}
|
||||
<p>Register now to create own packages and to submit and manage your data.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/users" role="button">Learn more
|
||||
>></a></p>
|
||||
{% elif object_type == 'group' %}
|
||||
<p>Users can team up in groups to share packages.
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/groups" role="button">Learn more
|
||||
>></a></p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<!-- If theres nothing to show extend the text above -->
|
||||
{% if reviewed_objects and unreviewed_objects %}
|
||||
{% if reviewed_objects|length == 0 and unreviewed_objects|length == 0 %}
|
||||
<p>Nothing found. There are two possible reasons: <br><br>1. There is no content yet.<br>2. You have no
|
||||
reading permissions.<br><br>Please be sure you have at least reading permissions.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if reviewed_objects %}
|
||||
{% if reviewed_objects|length > 0 %}
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
<h4 class="panel-title">
|
||||
<a id="ReviewedLink" data-toggle="collapse" data-parent="#reviewListAccordion"
|
||||
href="#Reviewed">Reviewed</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="Reviewed" class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item" id="ReviewedContent">
|
||||
{% if object_type == 'package' %}
|
||||
{% for obj in reviewed_objects %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}
|
||||
<span class="glyphicon glyphicon-star" aria-hidden="true"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for obj in reviewed_objects|slice:":50" %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}{# <i>({{ obj.package.name }})</i> #}
|
||||
<span class="glyphicon glyphicon-star" aria-hidden="true"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if unreviewed_objects %}
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver"><h4
|
||||
class="panel-title"><a id="UnreviewedLink" data-toggle="collapse" data-parent="#unReviewListAccordion"
|
||||
href="#Unreviewed">Unreviewed</a></h4></div>
|
||||
<div id="Unreviewed" class="panel-collapse collapse {% if reviewed_objects|length == 0 or object_type == 'package' %}in{% endif %}">
|
||||
<div class="panel-body list-group-item" id="UnreviewedContent">
|
||||
{% if object_type == 'package' %}
|
||||
{% for obj in unreviewed_objects %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for obj in unreviewed_objects|slice:":50" %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if objects %}
|
||||
<!-- Unreviewable objects such as User / Group / Setting -->
|
||||
<ul class='list-group'>
|
||||
{% for obj in objects %}
|
||||
{% if object_type == 'user' %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.username }}</a>
|
||||
{% else %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<style>
|
||||
.spinner-widget {
|
||||
position: fixed; /* stays in place on scroll */
|
||||
bottom: 20px; /* distance from bottom */
|
||||
right: 20px; /* distance from right */
|
||||
z-index: 9999; /* above most elements */
|
||||
width: 60px; /* adjust to gif size */
|
||||
height: 60px;
|
||||
}
|
||||
.spinner-widget {
|
||||
position: fixed; /* stays in place on scroll */
|
||||
bottom: 20px; /* distance from bottom */
|
||||
right: 20px; /* distance from right */
|
||||
z-index: 9999; /* above most elements */
|
||||
width: 60px; /* adjust to gif size */
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.spinner-widget img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.spinner-widget img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="load-all-loading" class="spinner-widget" style="display: none">
|
||||
<img
|
||||
id="loading-gif"
|
||||
src="{% static '/images/wait.gif' %}"
|
||||
alt="Loading..."
|
||||
/>
|
||||
<img id="loading-gif" src="{% static '/images/wait.gif' %}" alt="Loading...">
|
||||
</div>
|
||||
</div>
|
||||
{# prettier-ignore-start #}
|
||||
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
@ -458,7 +300,7 @@
|
||||
}, 2500);
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
$('#modal-form-delete-submit').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#modal-form-delete').submit();
|
||||
@ -474,5 +316,4 @@
|
||||
|
||||
});
|
||||
</script>
|
||||
{# prettier-ignore-end #}
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,75 +1,55 @@
|
||||
{% extends "framework.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="smiles"
|
||||
name="smiles"
|
||||
placeholder="SMILES"
|
||||
value="{{ smiles }}"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="smiles"
|
||||
name="smirks"
|
||||
placeholder="SMIRKS"
|
||||
value="{{ smirks }}"
|
||||
/>
|
||||
<button type="submit" class="btn btn-primary">Test</button>
|
||||
</form>
|
||||
</div>
|
||||
{% if result %}
|
||||
{{ smiles }}
|
||||
<p></p>
|
||||
<img
|
||||
width="400"
|
||||
src="{% url 'depict' %}?smiles={{ smiles|urlencode }}"
|
||||
/><br />
|
||||
<p></p>
|
||||
{% if rule %}
|
||||
{{ smirks }}
|
||||
<p></p>
|
||||
{{ rule.reactants_smarts }}
|
||||
<p></p>
|
||||
{{ rule.products_smarts }}
|
||||
<p></p>
|
||||
<div>{{ rule.as_svg|safe }}</div>
|
||||
{% endif %}
|
||||
<h2>Diff</h2>
|
||||
{% if diff %}
|
||||
{% for d in diff %}
|
||||
{{ d }}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ "No diff" }}
|
||||
{% endif %}
|
||||
<div>
|
||||
<div class="col-md-6">
|
||||
<h2>Ambit</h2>
|
||||
{% for p in ambit_res %}
|
||||
{{ p }}<br />
|
||||
<img
|
||||
width="400"
|
||||
src="{% url 'depict' %}?smiles={{ p|urlencode }}"
|
||||
/><br />
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h2>RDKit</h2>
|
||||
{% for p in rdkit_res %}
|
||||
{{ p }}<br />
|
||||
<img
|
||||
width="400"
|
||||
src="{% url 'depict' %}?smiles={{ p|urlencode }}"
|
||||
/><br />
|
||||
{% endfor %}
|
||||
</div>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="text" class="form-control" id="smiles" name="smiles" placeholder="SMILES"
|
||||
value="{{ smiles }}"/>
|
||||
<input type="text" class="form-control" id="smiles" name="smirks" placeholder="SMIRKS"
|
||||
value="{{ smirks }}"/>
|
||||
<button type="submit" class="btn btn-primary">Test</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if result %}
|
||||
{{ smiles }}<p></p>
|
||||
<img width='400' src='{% url 'depict' %}?smiles={{ smiles|urlencode }}'><br>
|
||||
<p></p>
|
||||
{% if rule %}
|
||||
{{ smirks }}
|
||||
<p></p>
|
||||
{{ rule.reactants_smarts }}
|
||||
<p></p>
|
||||
{{ rule.products_smarts }}
|
||||
<p></p>
|
||||
<div>
|
||||
{{ rule.as_svg|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<h2>Diff</h2>
|
||||
{% if diff %}
|
||||
{% for d in diff %}
|
||||
{{ d }}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ "No diff" }}
|
||||
{% endif %}
|
||||
<div>
|
||||
<div class="col-md-6">
|
||||
<h2>Ambit</h2>
|
||||
{% for p in ambit_res %}
|
||||
{{ p }}<br>
|
||||
<img width='400' src='{% url 'depict' %}?smiles={{ p|urlencode }}'><br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h2>RDKit</h2>
|
||||
{% for p in rdkit_res %}
|
||||
{{ p }}<br>
|
||||
<img width='400' src='{% url 'depict' %}?smiles={{ p|urlencode }}'><br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
{% extends "framework.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="alert alert-error" role="alert">
|
||||
|
||||
<div class="alert alert-error" role="alert">
|
||||
<h4 class="alert-heading">Bad Request!</h4>
|
||||
<p>Lorem</p>
|
||||
<hr />
|
||||
<hr>
|
||||
<p class="mb-0">
|
||||
You can find out more about permissions in our
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button"
|
||||
>Wiki >></a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
You can find out more about permissions in our <a target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button">Wiki >></a></p>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
{% extends "framework.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="alert alert-error" role="alert">
|
||||
|
||||
<div class="alert alert-error" role="alert">
|
||||
<h4 class="alert-heading">Access Denied!</h4>
|
||||
<p>Access to X denied.</p>
|
||||
<hr />
|
||||
<p>Access to X denied. </p>
|
||||
<hr>
|
||||
<p class="mb-0">
|
||||
You can find out more about permissions in our
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button"
|
||||
>Wiki >></a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
You can find out more about permissions in our <a target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button">Wiki >></a></p>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
{% extends "framework.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="alert alert-error" role="alert">
|
||||
|
||||
<div class="alert alert-error" role="alert">
|
||||
<h4 class="alert-heading">Not Found!</h4>
|
||||
<p>Does not exist</p>
|
||||
<hr />
|
||||
<hr>
|
||||
<p class="mb-0">
|
||||
You can find out more about permissions in our
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button"
|
||||
>Wiki >></a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
You can find out more about permissions in our <a target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button">Wiki >></a></p>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
{% extends "framework.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">{{ error_message }}</h4>
|
||||
<hr />
|
||||
<p class="mb-0">{{ error_detail }}</p>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">{{ error_message }}</h4>
|
||||
<hr>
|
||||
<p class="mb-0">
|
||||
{{ error_detail }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
{% extends "framework.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">Your account has not been activated yet!</h4>
|
||||
<p>
|
||||
Your account has not been activated yet. If you have questions
|
||||
<a href="mailto:admin@envipath.org">contact us.</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">Your account has not been activated yet!</h4>
|
||||
<p>Your account has not been activated yet. If you have questions <a href="mailto:admin@envipath.org">contact
|
||||
us.</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,106 +1,77 @@
|
||||
<!doctype html>
|
||||
<html data-theme="envipath">
|
||||
{% load static %}
|
||||
<head>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
{% load static %}
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<meta name="csrf-token" content="{{ csrf_token }}" />
|
||||
{# Favicon #}
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
type="image/png"
|
||||
href="{% static 'images/favicon.ico' %}"
|
||||
/>
|
||||
|
||||
{# Tailwind CSS disabled for legacy Bootstrap framework #}
|
||||
{# Pages using this framework will be migrated to framework_modern.html incrementally #}
|
||||
{# <link href="{% static 'css/output.css' %}" rel="stylesheet" type="text/css"/> #}
|
||||
|
||||
{# Legacy Bootstrap 3.3.7 - scoped to .legacy-bootstrap #}
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%; /* ensure body fills viewport */
|
||||
overflow-x: hidden; /* prevent horizontal scroll */
|
||||
}
|
||||
</style>
|
||||
{# TODO use bundles from bootstrap 3.3.7 #}
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script>
|
||||
<link
|
||||
href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.7.3/css/bootstrap-select.min.css"
|
||||
/>
|
||||
<link href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.7.3/css/bootstrap-select.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.7.3/js/bootstrap-select.min.js"></script>
|
||||
<script src="https://community.envipath.org/javascripts/embed-topics.js"></script>
|
||||
<!-- CDN END -->
|
||||
|
||||
{# Bootstrap compatibility styles #}
|
||||
<style>
|
||||
/* Ensure proper viewport behavior */
|
||||
html,
|
||||
body {
|
||||
height: 100%; /* ensure body fills viewport */
|
||||
overflow-x: hidden; /* prevent horizontal scroll */
|
||||
}
|
||||
</style>
|
||||
|
||||
<meta name="csrf-token" content="{{ csrf_token }}">
|
||||
<script>
|
||||
const csrftoken = document.querySelector("[name=csrf-token]").content;
|
||||
const csrftoken = document.querySelector('[name=csrf-token]').content;
|
||||
|
||||
// Setup CSRF header for all jQuery AJAX requests
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr, settings) {
|
||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
},
|
||||
});
|
||||
// Setup CSRF header for all jQuery AJAX requests
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{# Favicon #}
|
||||
<link rel="shortcut icon" type="image/png" href="{% static 'images/favicon.ico' %}"/>
|
||||
<!-- {# C3 CSS #}-->
|
||||
<!-- <link id="css-c3" href="{% static 'css/c3.css' %}" rel="stylesheet" type="text/css"/>-->
|
||||
<!-- {# EP CSS #}-->
|
||||
<!-- <link id="css-pps_white_general" href="{% static 'css/epp.css' %}" rel="stylesheet" type="text/css"/>-->
|
||||
|
||||
|
||||
{# General EP JS #}
|
||||
<script src="{% static 'js/pps.js' %}"></script>
|
||||
{# Modal Steps for Stepwise Modal Wizards #}
|
||||
<script src="{% static 'js/jquery-bootstrap-modal-steps.js' %}"></script>
|
||||
|
||||
{% if not debug %}
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = (window._paq = window._paq || []);
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(["trackPageView"]);
|
||||
_paq.push(["enableLinkTracking"]);
|
||||
(function () {
|
||||
var u = "//matomo.envipath.com/";
|
||||
_paq.push(["setTrackerUrl", u + "matomo.php"]);
|
||||
_paq.push(["setSiteId", "{{ meta.site_id }}"]);
|
||||
var d = document,
|
||||
g = d.createElement("script"),
|
||||
s = d.getElementsByTagName("script")[0];
|
||||
g.async = true;
|
||||
g.src = u + "matomo.js";
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = window._paq = window._paq || [];
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function () {
|
||||
var u = "//matomo.envipath.com/";
|
||||
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
||||
_paq.push(['setSiteId', '10']);
|
||||
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
||||
g.async = true;
|
||||
g.src = u + 'matomo.js';
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
<!-- Legacy Bootstrap navbar - isolated from Tailwind -->
|
||||
<div class="legacy-bootstrap">
|
||||
<nav
|
||||
class="navbar navbar-default navbar-inverse"
|
||||
style="border-radius:0px;"
|
||||
role="navigation"
|
||||
>
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header navbar-header-framework">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-inverse" style="border-radius:0px;" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header navbar-header-framework">
|
||||
<!-- <button type="button" class="navbar-toggle navbar-toggle-framework" data-toggle="collapse"-->
|
||||
<!-- data-target="#navbarCollapse">-->
|
||||
<!-- <span class="sr-only">Toggle navigation</span>-->
|
||||
@ -108,310 +79,198 @@
|
||||
<!-- <span class="icon-bar"></span>-->
|
||||
<!-- <span class="icon-bar"></span>-->
|
||||
<!-- </button>-->
|
||||
<a
|
||||
id="pictureLink"
|
||||
href="{{ meta.server_url }}"
|
||||
class="navbar-brand"
|
||||
>
|
||||
<img
|
||||
id="image-logo-short-white.svg"
|
||||
src="{% static "/images/logo-short-white.svg" %}"
|
||||
width="100"
|
||||
alt="enviPath"
|
||||
/>
|
||||
<a id="pictureLink" href="{{ meta.server_url }}" class="navbar-brand">
|
||||
<img id="image-logo-short-white.svg" src='{% static "/images/logo-short-white.svg" %}' width="100"
|
||||
alt="enviPath">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div
|
||||
class="navbar-collapse collapse-framework navbar-collapse-framework collapse"
|
||||
id="navbarCollapse"
|
||||
>
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse collapse-framework navbar-collapse-framework" id="navbarCollapse">
|
||||
<ul class="nav navbar-nav navbar-nav-framework">
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/predict"> Predict Pathway </a>
|
||||
</li>
|
||||
{# <li class="dropdown">#}
|
||||
{# <a data-toggle="dropdown" class="dropdown-toggle" href="#">Predict Pathway<b class="caret"></b></a>#}
|
||||
{# <ul role="menu" class="dropdown-menu">#}
|
||||
{# <li>#}
|
||||
{# <a class="button" data-toggle="modal" data-target="#predict_modal">#}
|
||||
{# <i class=" glyphicon glyphicon-tag"></i> Predict Pathway#}
|
||||
{# </a>#}
|
||||
{# </li>#}
|
||||
{# <li>#}
|
||||
{# <a class="button" data-toggle="modal" data-target="#batch_predict_modal">#}
|
||||
{# <i class=" glyphicon glyphicon-tags"></i> Batch Prediction#}
|
||||
{# </a>#}
|
||||
{# </li>#}
|
||||
{# </ul>#}
|
||||
{# </li>#}
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/package" id="packageLink"
|
||||
>Package</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/model" id="modelLink"
|
||||
>Modelling</a
|
||||
>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#"
|
||||
>Browse Data<b class="caret"></b
|
||||
></a>
|
||||
<ul role="menu" class="dropdown-menu">
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/pathway" id="pathwayLink"
|
||||
>Pathway</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/rule" id="ruleLink">Rule</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/compound" id="compoundLink"
|
||||
>Compound</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/reaction" id="reactionLink"
|
||||
>Reaction</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="{{ meta.server_url }}/model"
|
||||
id="relative-reasoningLink"
|
||||
>Model</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/scenario" id="scenarioLink"
|
||||
>Scenario</a
|
||||
>
|
||||
</li>
|
||||
{# <li><a href="{{ meta.server_url }}/setting" id="settingLink">Setting</a></li>#}
|
||||
{# <li><a href="{{ meta.server_url }}/user" id="userLink">User</a></li>#}
|
||||
{# <li><a href="{{ meta.server_url }}/group" id="groupLink">Group</a></li>#}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul
|
||||
class="nav navbar-nav navbar-right navbar-nav-framework navbar-right-framework"
|
||||
>
|
||||
<li>
|
||||
<a href="https://community.envipath.org/" id="communityLink"
|
||||
>Community</a
|
||||
>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#"
|
||||
>Info <b class="caret"></b
|
||||
></a>
|
||||
<ul role="menu" class="dropdown-menu">
|
||||
<!--<li><a href="{{ meta.server_url }}/funding" id="fundingLink">Funding</a></li>-->
|
||||
<li>
|
||||
<a
|
||||
href="https://community.envipath.org/t/envipath-license/109"
|
||||
id="licenceLink"
|
||||
>Licences</a
|
||||
>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/"
|
||||
id="wikiLink"
|
||||
>Documentation Wiki</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
id="citeButton"
|
||||
data-toggle="modal"
|
||||
data-target="#citemodal"
|
||||
>How to cite enviPath</a
|
||||
>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li><a>Version: {{ meta.version }}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if meta.user.username == 'anonymous' %}
|
||||
<li>
|
||||
<a
|
||||
href="{% url 'login' %}"
|
||||
id="loginButton"
|
||||
style="margin-right:10px"
|
||||
>Login</a
|
||||
>
|
||||
<a href="#" data-toggle="modal" data-target="#predict_modal">
|
||||
Predict Pathway
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
{# <li class="dropdown">#}
|
||||
{# <a data-toggle="dropdown" class="dropdown-toggle" href="#">Predict Pathway<b class="caret"></b></a>#}
|
||||
{# <ul role="menu" class="dropdown-menu">#}
|
||||
{# <li>#}
|
||||
{# <a class="button" data-toggle="modal" data-target="#predict_modal">#}
|
||||
{# <i class=" glyphicon glyphicon-tag"></i> Predict Pathway#}
|
||||
{# </a>#}
|
||||
{# </li>#}
|
||||
{# <li>#}
|
||||
{# <a class="button" data-toggle="modal" data-target="#batch_predict_modal">#}
|
||||
{# <i class=" glyphicon glyphicon-tags"></i> Batch Prediction#}
|
||||
{# </a>#}
|
||||
{# </li>#}
|
||||
{# </ul>#}
|
||||
{# </li>#}
|
||||
<li><a href="{{ meta.server_url }}/package" id="packageLink">Package</a></li>
|
||||
<li><a href="{{ meta.server_url }}/search" id="searchLink">Search</a></li>
|
||||
<li><a href="{{ meta.server_url }}/model" id="modelLink">Modelling</a></li>
|
||||
<li class="dropdown">
|
||||
<a
|
||||
data-toggle="dropdown"
|
||||
id="loggedInButton"
|
||||
class="dropdown-toggle"
|
||||
id="logedInButton"
|
||||
href="#"
|
||||
>
|
||||
<div id="username">
|
||||
{{ user.username }}<b class="caret"></b>
|
||||
</div>
|
||||
</a>
|
||||
<ul role="menu" class="dropdown-menu">
|
||||
<li>
|
||||
<a href="{{ meta.user.url }}" id="accountbutton"
|
||||
>My Account</a
|
||||
>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<form
|
||||
class="navbar-form navbar-left navbar-left-framework"
|
||||
role="logout"
|
||||
action="{% url 'logout' %}"
|
||||
method="post"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<input type="hidden" name="logout" value="true" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">
|
||||
Logout
|
||||
</button>
|
||||
</form>
|
||||
</ul>
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">Browse Data<b class="caret"></b></a>
|
||||
<ul role="menu" class="dropdown-menu">
|
||||
<li><a href="{{ meta.server_url }}/pathway" id="pathwayLink">Pathway</a></li>
|
||||
<li><a href="{{ meta.server_url }}/rule" id="ruleLink">Rule</a></li>
|
||||
<li><a href="{{ meta.server_url }}/compound" id="compoundLink">Compound</a></li>
|
||||
<li><a href="{{ meta.server_url }}/reaction" id="reactionLink">Reaction</a></li>
|
||||
<li><a href="{{ meta.server_url }}/model" id="relative-reasoningLink">Model</a></li>
|
||||
<li><a href="{{ meta.server_url }}/scenario" id="scenarioLink">Scenario</a></li>
|
||||
{# <li><a href="{{ meta.server_url }}/setting" id="settingLink">Setting</a></li>#}
|
||||
{# <li><a href="{{ meta.server_url }}/user" id="userLink">User</a></li>#}
|
||||
{# <li><a href="{{ meta.server_url }}/group" id="groupLink">Group</a></li>#}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- End legacy Bootstrap navbar -->
|
||||
|
||||
<div id="docContent" class="content container">
|
||||
{% if breadcrumbs %}
|
||||
<div id="bread">
|
||||
<ol class="breadcrumb">
|
||||
{% for elem in breadcrumbs %}
|
||||
{% for name, url in elem.items %}
|
||||
{% if forloop.parentloop.last %}
|
||||
<li class="active">{{ name }}</li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav navbar-nav navbar-right navbar-nav-framework navbar-right-framework">
|
||||
<li><a href="https://community.envipath.org/" id="communityLink">Community</a></li>
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">Info <b class="caret"></b></a>
|
||||
<ul role="menu" class="dropdown-menu">
|
||||
<!--<li><a href="{{ meta.server_url }}/funding" id="fundingLink">Funding</a></li>-->
|
||||
<li><a href="https://community.envipath.org/t/envipath-license/109" id="licenceLink">Licences</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a target="_blank" href="https://wiki.envipath.org/" id="wikiLink">Documentation Wiki</a>
|
||||
</li>
|
||||
<li><a href="#" id="citeButton" data-toggle="modal" data-target="#citemodal">How to cite
|
||||
enviPath</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a>Version: {{ meta.version }}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if meta.user.username == 'anonymous' %}
|
||||
<li>
|
||||
<a href="#signup" id="loginButton" data-toggle="modal" data-target="#signupmodal"
|
||||
style="margin-right:10px">Login</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<a href="{{ url }}">{{ name }}</a>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" id="loggedInButton" class="dropdown-toggle" id="logedInButton"
|
||||
href="#">
|
||||
<div id="username">
|
||||
{{ user.username }}<b class="caret"></b>
|
||||
</div>
|
||||
</a>
|
||||
<ul role="menu" class="dropdown-menu">
|
||||
<li>
|
||||
<a href="{{ meta.user.url }}" id="accountbutton">My Account</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<form class="navbar-form navbar-left navbar-left-framework" role="logout"
|
||||
action="{% url 'logout' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<input type="hidden" name="logout" value="true">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default">Logout</button>
|
||||
</form>
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if message %}
|
||||
<div id="message">{{ message }}</div>
|
||||
{% endif %}
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
{% if meta.url_contains_package and meta.current_package.license %}
|
||||
</div>
|
||||
</nav>
|
||||
<div id="docContent" class="content container">
|
||||
{% if breadcrumbs %}
|
||||
<div id="bread">
|
||||
<ol class="breadcrumb">
|
||||
{% for elem in breadcrumbs %}
|
||||
{% for name, url in elem.items %}
|
||||
{% if forloop.parentloop.last %}
|
||||
<li class="active">{{ name }}</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<a href="{{ url }}">{{ name }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if message %}
|
||||
<div id="message">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
{% if meta.url_contains_package and meta.current_package.license %}
|
||||
<p></p>
|
||||
<div class="panel-group" id="license_accordion">
|
||||
<div
|
||||
class="panel panel-default list-group-item"
|
||||
style="background-color:#f5f5f5"
|
||||
>
|
||||
<div class="panel-title">
|
||||
<a
|
||||
data-toggle="collapse"
|
||||
data-parent="#licence_accordion"
|
||||
href="#license"
|
||||
>License</a
|
||||
>
|
||||
<div class="panel panel-default list-group-item" style="background-color:#f5f5f5">
|
||||
<div class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#licence_accordion" href="#license">License</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="license" class="panel-collapse in collapse">
|
||||
<div class="panel-body list-group-item">
|
||||
<a target="_blank" href="{{ meta.current_package.license.link }}">
|
||||
<img src="{{ meta.current_package.license.image_link }}" />
|
||||
</a>
|
||||
<div id="license" class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item">
|
||||
<a target="_blank" href="{{ meta.current_package.license.link }}">
|
||||
<img src="{{ meta.current_package.license.image_link }}">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- FOOTER - Legacy Bootstrap -->
|
||||
<div class="legacy-bootstrap">
|
||||
<div class="container text-center">
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<ul class="nav nav-pills nav-justified">
|
||||
<li>
|
||||
<a href="http://ml.auckland.ac.nz" target="_blank">
|
||||
<img
|
||||
id="image-uoalogo"
|
||||
height="60"
|
||||
src="{% static "/images/UoA-Logo-Primary-RGB-Small.png" %}"
|
||||
alt="The Univserity of Auckland"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://eawag.ch" target="_blank">
|
||||
<img
|
||||
id="image-ealogo"
|
||||
height="60"
|
||||
src="{% static "/images/ealogo.gif" %}"
|
||||
alt="Eawag"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.uzh.ch/" target="_blank">
|
||||
<img
|
||||
id="image-ufzlogo"
|
||||
height="60"
|
||||
src="{% static "/images/uzh-logo.svg" %}"
|
||||
alt="University of Zurich"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- FOOTER -->
|
||||
<div class="container text-center">
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<ul class="nav nav-pills nav-justified">
|
||||
<ul class="nav nav-pills nav-justified">
|
||||
<li>
|
||||
<a href="http://ml.auckland.ac.nz" target="_blank">
|
||||
<img id="image-uoalogo" height="60" src='{% static "/images/UoA-Logo-Primary-RGB-Small.png" %}'
|
||||
alt="The Univserity of Auckland"/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://eawag.ch" target="_blank">
|
||||
<img id="image-ealogo" height="60" src='{% static "/images/ealogo.gif" %}' alt="Eawag"/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.uzh.ch/" target="_blank">
|
||||
<img id="image-ufzlogo" height="60" src='{% static "/images/uzh-logo.svg" %}'
|
||||
alt="University of Zurich"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<ul class="nav nav-pills nav-justified">
|
||||
<!-- <li><a href="https://envipath.com/imprint/" target="_blank">Impressum/Imprint</a></li>-->
|
||||
<li>
|
||||
<a href="mailto:admin@envipath.org" target="_blank">Contact</a>
|
||||
</li>
|
||||
<li><a href="mailto:admin@envipath.org" target="_blank">Contact</a></li>
|
||||
<!-- <li><a href="http://envipath.com" target="_blank"> enviPath UG (haftungsbeschränkt) & Co. KG ©-->
|
||||
<!-- {{ YEAR }}</a></li>-->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- End legacy Bootstrap footer -->
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
// Hide actionsbutton if theres no action defined
|
||||
if ($("#actionsButton ul").children().length > 0) {
|
||||
$("#actionsButton").show();
|
||||
if ($('#actionsButton ul').children().length > 0) {
|
||||
$('#actionsButton').show();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% block modals %}
|
||||
{% include "modals/cite_modal.html" %}
|
||||
{% include "modals/predict_modal.html" %}
|
||||
{% include "modals/batch_predict_modal.html" %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
});
|
||||
</script>
|
||||
{% block modals %}
|
||||
{% include "modals/cite_modal.html" %}
|
||||
{% include "modals/signup_modal.html" %}
|
||||
{% include "modals/predict_modal.html" %}
|
||||
{% include "modals/batch_predict_modal.html" %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,223 +0,0 @@
|
||||
<!doctype html>
|
||||
<html data-theme="envipath" lang="en">
|
||||
{% load static %}
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="csrf-token" content="{{ csrf_token }}" />
|
||||
|
||||
{# Favicon #}
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
type="image/png"
|
||||
href="{% static 'images/favicon.ico' %}"
|
||||
/>
|
||||
|
||||
{# Tailwind CSS + DaisyUI Output #}
|
||||
<link
|
||||
href="{% static 'css/output.css' %}"
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
/>
|
||||
|
||||
{# jQuery - Keep for compatibility with existing JS #}
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
|
||||
{# Font Awesome #}
|
||||
<link
|
||||
href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
{# Discourse embed for community #}
|
||||
<script src="https://community.envipath.org/javascripts/embed-topics.js"></script>
|
||||
|
||||
<script>
|
||||
const csrftoken = document.querySelector("[name=csrf-token]").content;
|
||||
|
||||
// Setup CSRF header for all jQuery AJAX requests
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr, settings) {
|
||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
{# General EP JS #}
|
||||
<script src="{% static 'js/pps.js' %}"></script>
|
||||
{# Modal Steps for Stepwise Modal Wizards #}
|
||||
<script src="{% static 'js/jquery-bootstrap-modal-steps.js' %}"></script>
|
||||
|
||||
{% if not debug %}
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = (window._paq = window._paq || []);
|
||||
_paq.push(["trackPageView"]);
|
||||
_paq.push(["enableLinkTracking"]);
|
||||
(function () {
|
||||
var u = "//matomo.envipath.com/";
|
||||
_paq.push(["setTrackerUrl", u + "matomo.php"]);
|
||||
_paq.push(["setSiteId", "{{ meta.site_id }}"]);
|
||||
var d = document,
|
||||
g = d.createElement("script"),
|
||||
s = d.getElementsByTagName("script")[0];
|
||||
g.async = true;
|
||||
g.src = u + "matomo.js";
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
{% endif %}
|
||||
</head>
|
||||
<body class="bg-base-300 min-h-screen">
|
||||
{% include "includes/navbar.html" %}
|
||||
|
||||
{# Main Content Area #}
|
||||
<main class="w-full">
|
||||
{% block main_content %}
|
||||
{# Breadcrumbs - outside main content, optional #}
|
||||
{% if breadcrumbs %}
|
||||
<div id="bread" class="mx-auto max-w-7xl px-4 py-4">
|
||||
<div class="breadcrumbs text-sm">
|
||||
<ul>
|
||||
{% for elem in breadcrumbs %}
|
||||
{% for name, url in elem.items %}
|
||||
{% if forloop.parentloop.last %}
|
||||
<li>{{ name }}</li>
|
||||
{% else %}
|
||||
<li><a href="{{ url }}">{{ name }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Main content container - paper effect on medium+ screens #}
|
||||
<div
|
||||
id="docContent"
|
||||
class="bg-base-100 mx-auto md:my-8 md:max-w-6xl md:rounded-lg md:shadow-xl"
|
||||
>
|
||||
{# Messages - inside paper #}
|
||||
{% if message %}
|
||||
<div id="message" class="alert alert-info m-4">{{ message }}</div>
|
||||
{% endif %}
|
||||
|
||||
{# Page content - no enforced styles #}
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
|
||||
{# License - inside paper if present #}
|
||||
{% if meta.url_contains_package and meta.current_package.license %}
|
||||
<div class="collapse-arrow bg-base-200 collapse p-8">
|
||||
<input type="checkbox" checked />
|
||||
<div class="collapse-title text-xl font-medium">License</div>
|
||||
<div class="collapse-content">
|
||||
<a
|
||||
target="_blank"
|
||||
href="{{ meta.current_package.license.link }}"
|
||||
>
|
||||
<img
|
||||
src="{{ meta.current_package.license.image_link }}"
|
||||
alt="License"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock main_content %}
|
||||
</main>
|
||||
|
||||
{% include "includes/footer.html" %}
|
||||
|
||||
{# Floating Help Tab #}
|
||||
{% if not public_mode %}
|
||||
<div class="fixed top-1/2 right-0 z-50 -translate-y-1/2">
|
||||
<a
|
||||
href="https://community.envipath.org/"
|
||||
target="_blank"
|
||||
class="btn btn-secondary hover:btn-secondary-focus text-secondary-content flex items-center justify-center text-sm shadow-lg transition-all duration-300 hover:-translate-x-1 hover:scale-105"
|
||||
title="Get Help from the Community"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-message-circle-question-mark-icon lucide-message-circle-question-mark"
|
||||
>
|
||||
<path
|
||||
d="M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719"
|
||||
/>
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
|
||||
<path d="M12 17h.01" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block modals %}
|
||||
{% include "modals/search_modal.html" %}
|
||||
{% endblock %}
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
// Hide actionsbutton if there's no action defined
|
||||
if ($("#actionsButton ul").children().length > 0) {
|
||||
$("#actionsButton").show();
|
||||
}
|
||||
});
|
||||
|
||||
// Open search modal function
|
||||
function openSearchModal() {
|
||||
const searchModal = document.getElementById("search_modal");
|
||||
if (searchModal) {
|
||||
searchModal.showModal();
|
||||
}
|
||||
}
|
||||
|
||||
// Click handler for search badge
|
||||
const searchTrigger = document.getElementById("search-trigger");
|
||||
if (searchTrigger) {
|
||||
searchTrigger.addEventListener("click", function (event) {
|
||||
event.preventDefault();
|
||||
openSearchModal();
|
||||
});
|
||||
}
|
||||
|
||||
// Global keyboard shortcut for search (Cmd+K on Mac, Ctrl+K on Windows/Linux)
|
||||
document.addEventListener("keydown", function (event) {
|
||||
// Check if user is typing in an input field
|
||||
const activeElement = document.activeElement;
|
||||
const isInputField =
|
||||
activeElement &&
|
||||
(activeElement.tagName === "INPUT" ||
|
||||
activeElement.tagName === "TEXTAREA" ||
|
||||
activeElement.contentEditable === "true");
|
||||
|
||||
if (isInputField) {
|
||||
return; // Don't trigger shortcut when typing in input fields
|
||||
}
|
||||
|
||||
// Check for Cmd+K (Mac) or Ctrl+K (Windows/Linux)
|
||||
const isMac = /Mac/.test(navigator.platform);
|
||||
const isCorrectModifier = isMac ? event.metaKey : event.ctrlKey;
|
||||
|
||||
if (isCorrectModifier && event.key === "k") {
|
||||
event.preventDefault();
|
||||
openSearchModal();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,94 +0,0 @@
|
||||
{% load static %}
|
||||
<div class="bg-base-300 text-base-content mx-auto mt-10 lg:max-w-5xl">
|
||||
<footer class="footer sm:footer-horizontal p-10">
|
||||
{% if not public_mode %}
|
||||
<nav>
|
||||
<h6 class="footer-title">Services</h6>
|
||||
<a class="link link-hover" href="/predict">Predict</a>
|
||||
<a class="link link-hover" href="/package">Packages</a>
|
||||
{% if user.is_authenticated %}
|
||||
<a class="link link-hover" href="/model">Your Collections</a>
|
||||
{% endif %}
|
||||
<a
|
||||
href="https://wiki.envipath.org/"
|
||||
target="_blank"
|
||||
class="link link-hover"
|
||||
>Documentation</a
|
||||
>
|
||||
</nav>
|
||||
{% endif %}
|
||||
<nav>
|
||||
<h6 class="footer-title">Company</h6>
|
||||
<a class="link link-hover" href="/about">About us</a>
|
||||
<a class="link link-hover" href="/contact">Contact us</a>
|
||||
<a class="link link-hover" href="/careers">Careers</a>
|
||||
<a class="link link-hover" href="/legal">Legal</a>
|
||||
</nav>
|
||||
<nav>
|
||||
<h6 class="footer-title">Legal</h6>
|
||||
<a class="link link-hover" href="/terms">Terms of use</a>
|
||||
<a class="link link-hover" href="/privacy">Privacy policy</a>
|
||||
<a class="link link-hover" href="/cookie-policy">Cookie policy</a>
|
||||
<a class="link link-hover" href="/cite">Cite enviPath</a>
|
||||
</nav>
|
||||
</footer>
|
||||
<footer class="footer border-t-2 border-neutral-300 px-10 py-4">
|
||||
<div class="flex w-full flex-row items-start justify-between">
|
||||
<aside class="grid-flow-col items-center">
|
||||
<svg
|
||||
class="fill-neutral-content m-2 h-14 flex-shrink-0"
|
||||
viewbox="0 0 65 65"
|
||||
>
|
||||
<use
|
||||
href="{% static "/images/logo-square.svg" %}#ep-logo-square"
|
||||
></use>
|
||||
</svg>
|
||||
|
||||
enviPath Ltd.
|
||||
<br />
|
||||
Biodegredation prediction since 2015.
|
||||
</aside>
|
||||
<aside class="text-base-200 mt-2 text-sm">
|
||||
<span class="text-xs tracking-tight">Version</span>
|
||||
<span class="text-base font-bold">{{ meta.version }}</span>
|
||||
</aside>
|
||||
</div>
|
||||
<nav class="md:place-self-center md:justify-self-end">
|
||||
<div class="grid grid-flow-col gap-4">
|
||||
<a href="https://www.youtube.com/@envipath7231" target="_blank">
|
||||
<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 fill-current"
|
||||
>
|
||||
<title>YouTube</title>
|
||||
<path
|
||||
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://community.envipath.org/" target="_blank">
|
||||
<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 fill-current"
|
||||
>
|
||||
<title>Discourse</title>
|
||||
<path
|
||||
d="M12.103 0C18.666 0 24 5.485 24 11.997c0 6.51-5.33 11.99-11.9 11.99L0 24V11.79C0 5.28 5.532 0 12.103 0zm.116 4.563c-2.593-.003-4.996 1.352-6.337 3.57-1.33 2.208-1.387 4.957-.148 7.22L4.4 19.61l4.794-1.074c2.745 1.225 5.965.676 8.136-1.39 2.17-2.054 2.86-5.228 1.737-7.997-1.135-2.778-3.84-4.59-6.84-4.585h-.008z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/company/envipath/" target="_blank">
|
||||
<img
|
||||
src="{% static "/images/linkedin.png" %}"
|
||||
alt="LinkedIn"
|
||||
class="h-6 w-6"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</footer>
|
||||
</div>
|
||||
@ -1,150 +0,0 @@
|
||||
{% load static %}
|
||||
{# Modern DaisyUI Navbar #}
|
||||
<div class="navbar x-50 bg-neutral-50 text-neutral-950 shadow-lg">
|
||||
<div class="navbar-start">
|
||||
<a href="{{ meta.server_url }}" class="btn btn-ghost text-xl normal-case">
|
||||
<svg class="fill-base-content h-8" viewBox="0 0 104 26" role="img">
|
||||
<use href="{% static "/images/logo-name.svg" %}#ep-logo-name" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if not public_mode %}
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<a
|
||||
href="{{ meta.server_url }}/predict"
|
||||
role="button"
|
||||
class="btn btn-ghost"
|
||||
id="predictLink"
|
||||
>Predict</a
|
||||
>
|
||||
<!-- <li><a href="{{ meta.server_url }}/package" id="packageLink">Package</a></li> -->
|
||||
<!--<li><a href="{{ meta.server_url }}/browse" id="browseLink">Browse</a></li>-->
|
||||
<div class="dropdown dropdown-center">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost">Browse</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm"
|
||||
>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/package" id="packageLink">Package</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/pathway" id="pathwayLink">Pathway</a>
|
||||
</li>
|
||||
<li><a href="{{ meta.server_url }}/rule" id="ruleLink">Rule</a></li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/compound" id="compoundLink"
|
||||
>Compound</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/reaction" id="reactionLink"
|
||||
>Reaction</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/model" id="relative-reasoningLink"
|
||||
>Model</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ meta.server_url }}/scenario" id="scenarioLink"
|
||||
>Scenario</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="navbar-end">
|
||||
{% if not public_mode %}
|
||||
<a id="search-trigger" role="button" class="cursor-pointer">
|
||||
<div
|
||||
class="badge badge-dash bg-base-200 text-base-content/50 m-1 flex items-center space-x-1 p-2"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-search-icon lucide-search"
|
||||
>
|
||||
<path d="m21 21-4.34-4.34" />
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
</svg>
|
||||
<span id="search-shortcut">⌘K</span>
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if meta.user.username == 'anonymous' or public_mode %}
|
||||
<a href="{% url 'login' %}" id="loginButton" class="p-2">Login</a>
|
||||
{% else %}
|
||||
<div class="dropdown dropdown-end">
|
||||
<div
|
||||
tabindex="0"
|
||||
role="button"
|
||||
class="btn btn-ghost btn-circle m-1"
|
||||
id="loggedInButton"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-circle-user-icon lucide-circle-user"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<circle cx="12" cy="10" r="3" />
|
||||
<path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662" />
|
||||
</svg>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="dropdown-content menu bg-base-100 rounded-box z-50 w-52 p-2 shadow-sm"
|
||||
>
|
||||
<li><a href="{{ meta.user.url }}" id="accountbutton">Settings</a></li>
|
||||
<li>
|
||||
<form
|
||||
id="logoutForm"
|
||||
action="{% url 'logout' %}"
|
||||
method="post"
|
||||
style="display: none;"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="logout" value="true" />
|
||||
</form>
|
||||
<a
|
||||
href="#"
|
||||
id="logoutButton"
|
||||
onclick="event.preventDefault(); document.getElementById('logoutForm').submit();"
|
||||
>Logout</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// OS-aware search shortcut display
|
||||
(function () {
|
||||
const isMac = /Mac/.test(navigator.platform);
|
||||
const shortcutElement = document.getElementById("search-shortcut");
|
||||
if (shortcutElement) {
|
||||
shortcutElement.textContent = isMac ? "⌘K" : "Ctrl+K";
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
@ -1,453 +1,186 @@
|
||||
{% extends "framework_modern.html" %}
|
||||
{% extends "framework.html" %}
|
||||
{% load static %}
|
||||
{% block main_content %}
|
||||
<!-- Hero Section with Logo and Search -->
|
||||
<section class="hero relative mx-auto h-fit w-full max-w-5xl shadow-none">
|
||||
<div
|
||||
class="hero from-primary-800 to-primary-600 min-h-[calc(100vh*0.4)] bg-gradient-to-br"
|
||||
style="background-image: url('{% static "/images/hero.png" %}'); background-size: cover; background-position: center;"
|
||||
>
|
||||
<div class="hero-overlay"></div>
|
||||
<!-- Predict Pathway text over the image -->
|
||||
<div class="absolute bottom-40 left-1/8 z-10 -translate-x-8">
|
||||
<h2 class="text-base-100 text-left text-3xl text-shadow-lg">
|
||||
Predict Your Pathway
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="bg-base-200 mx-auto max-w-5xl shadow-md">
|
||||
<!-- Predict Pathway Section -->
|
||||
<div
|
||||
class="relative z-20 mx-auto -mt-32 mb-10 w-full flex-col lg:flex-row-reverse"
|
||||
>
|
||||
<div
|
||||
class="card bg-base-100 mx-auto w-3/4 shrink-0 shadow-xl transition-all duration-300 ease-in-out"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="my-4 ml-8 flex h-fit flex-row items-center justify-start">
|
||||
<div class="flex items-center gap-1">
|
||||
<label class="swap btn btn-ghost btn-sm p-1" title="Input Mode">
|
||||
<input type="checkbox" />
|
||||
<span class="swap-on flex items-center gap-1">
|
||||
<div
|
||||
class="bg-neutral/50 text-neutral-content flex items-center justify-center rounded-full p-1"
|
||||
>
|
||||
<svg
|
||||
aria-label="smiles mode"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
class="size-5"
|
||||
>
|
||||
<g
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="round"
|
||||
stroke-width="2"
|
||||
fill="currentColor"
|
||||
stroke="none"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8 2.75A.75.75 0 0 1 8.75 2h7.5a.75.75 0 0 1 0 1.5h-3.215l-4.483 13h2.698a.75.75 0 0 1 0 1.5h-7.5a.75.75 0 0 1 0-1.5h3.215l4.483-13H8.75A.75.75 0 0 1 8 2.75Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="ext-xs">SMILES</span>
|
||||
</span>
|
||||
<span class="swap-off flex items-center gap-1">
|
||||
<div
|
||||
class="bg-neutral/50 text-neutral-content flex items-center justify-center rounded-full p-1"
|
||||
>
|
||||
<svg
|
||||
aria-label="draw mode"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
stroke="none"
|
||||
class="size-5"
|
||||
>
|
||||
<path
|
||||
d="m2.695 14.762-1.262 3.155a.5.5 0 0 0 .65.65l3.155-1.262a4 4 0 0 0 1.343-.886L17.5 5.501a2.121 2.121 0 0 0-3-3L3.58 13.419a4 4 0 0 0-.885 1.343Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-base/50 text-xs">Draw</span>
|
||||
</span>
|
||||
</label>
|
||||
{% block content %}
|
||||
<!-- TODO rename ids as well as remove pathways if modal is closed!-->
|
||||
<div class="modal fade" tabindex="-1" id="foundMatching" role="dialog" aria-labelledby="foundModal"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title" id="newPackMod">Found Pathway in Database</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>We found at least one pathway in the database with the given root
|
||||
compound. Do you want to open any of the existing pathways or
|
||||
predict a new one? To open an existing pathway, simply click
|
||||
on the pathway, to predict a new one, click Predict. The predicted
|
||||
pathway might differ from the ones in the database due to the
|
||||
settings used in the prediction.</p>
|
||||
<div id="foundPathways"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="modal-predict" class="btn btn-primary" href="#">Predict</a>
|
||||
<button type="button" id="cancel-predict" class="btn btn-default" data-dismiss="modal">Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset
|
||||
class="fieldset overflow-hidden transition-all duration-300 ease-in-out"
|
||||
>
|
||||
<form
|
||||
id="index-form"
|
||||
action="{{ meta.current_package.url }}/pathway"
|
||||
method="POST"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<div
|
||||
id="text-input-container"
|
||||
class="scale-100 transform opacity-100 transition-all duration-300 ease-in-out"
|
||||
>
|
||||
<div class="join mx-auto w-full">
|
||||
<input
|
||||
type="text"
|
||||
id="index-form-text-input"
|
||||
placeholder="canonical SMILES string"
|
||||
class="input input-md join-item grow"
|
||||
/>
|
||||
<button class="btn btn-neutral join-item">Predict!</button>
|
||||
</div>
|
||||
<div class="label relative mt-1 w-full">
|
||||
<div class="flex gap-2">
|
||||
<a
|
||||
href="#"
|
||||
class="example-link hover:text-primary cursor-pointer"
|
||||
data-smiles="CN1C=NC2=C1C(=O)N(C(=O)N2C)C"
|
||||
title="load example"
|
||||
>Caffeine</a
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
class="example-link hover:text-primary cursor-pointer"
|
||||
data-smiles="CC(C)CC1=CC=C(C=C1)C(C)C(=O)O"
|
||||
title="load example"
|
||||
>Ibuprofen</a
|
||||
>
|
||||
</div>
|
||||
<a class="absolute top-0 left-[calc(100%-5.4rem)]" href="#"
|
||||
>Advanced</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="ketcher-container"
|
||||
class="hidden w-full scale-95 transform opacity-0 transition-all duration-300 ease-in-out"
|
||||
>
|
||||
<iframe
|
||||
id="index-ketcher"
|
||||
src="{% static '/js/ketcher2/ketcher.html' %}"
|
||||
width="100%"
|
||||
height="400"
|
||||
class="rounded-lg"
|
||||
></iframe>
|
||||
<button
|
||||
class="btn btn-lg bg-primary-950 text-primary-50 join-item mt-2 w-full"
|
||||
>
|
||||
Predict!
|
||||
</button>
|
||||
<div class="mt-1 flex w-full justify-end">
|
||||
<a class="label justify-end" href="/predict">Advanced</a>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
type="hidden"
|
||||
id="index-form-smiles"
|
||||
name="smiles"
|
||||
value="smiles"
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
id="index-form-predict"
|
||||
name="predict"
|
||||
value="predict"
|
||||
/>
|
||||
<input type="hidden" id="current-action" value="predict" />
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Community News Section -->
|
||||
<section class="bg-base-200 z-10 mx-8 py-16">
|
||||
<div class="mx-auto max-w-7xl px-4">
|
||||
<h2 class="h2 mb-8 text-left font-bold">Community Updates</h2>
|
||||
|
||||
<div id="community-news-container" class="flex justify-center gap-4">
|
||||
<!-- News cards will be populated here -->
|
||||
<div id="loading" class="flex w-full justify-center">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-right">
|
||||
<a
|
||||
href="https://community.envipath.org/c/announcements/10"
|
||||
target="_blank"
|
||||
class="btn btn-ghost btn-sm"
|
||||
>
|
||||
Read More Announcements
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Discourse API integration -->
|
||||
<script src="{% static 'js/discourse-api.js' %}"></script>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Mission Statement Section -->
|
||||
<section class="from-base-200 to-base-100 bg-gradient-to-b py-16">
|
||||
<div class="mx-auto px-8 md:px-12">
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="w-1/3">
|
||||
<img
|
||||
src="{% static "/images/ep-rule-artwork.png" %}"
|
||||
alt="rule-based iterative tree greneration"
|
||||
class="h-full w-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
<div class="mr-8 w-2/3 space-y-4 text-left">
|
||||
<h2 class="h2 mb-8 font-bold">About enviPath</h2>
|
||||
<p class="">
|
||||
enviPath is a database and prediction system for the microbial
|
||||
biotransformation of organic environmental contaminants. The
|
||||
database provides the possibility to store and view experimentally
|
||||
observed biotransformation pathways.
|
||||
</p>
|
||||
<p class="">
|
||||
The pathway prediction system provides different relative
|
||||
reasoning models to predict likely biotransformation pathways and
|
||||
products. Explore our tools and contribute to advancing
|
||||
environmental biotransformation research.
|
||||
</p>
|
||||
<div class="float-right flex flex-row gap-4">
|
||||
<a href="/about" class="btn btn-ghost-neutral">Read More</a>
|
||||
<a href="/about" class="btn btn-neutral">Publications</a>
|
||||
<div class="row">
|
||||
<div class="col-xs-8">
|
||||
<div class="jumbotron">
|
||||
<h1>
|
||||
<img id="image-logo-long" class="img-responsive" alt="enviPath" width="1000ex"
|
||||
src='{% static "/images/logo-long.svg" %}'/>
|
||||
</h1>
|
||||
<p>enviPath is a database and prediction system for the microbial
|
||||
biotransformation of organic environmental contaminants. The
|
||||
database provides the possibility to store and view experimentally
|
||||
observed biotransformation pathways. The pathway prediction system
|
||||
provides different relative reasoning models to predict likely biotransformation
|
||||
pathways and products. You can try it out below.
|
||||
</p>
|
||||
<p>
|
||||
<a class="btn" style="background-color:#222222;color:#9d9d9d" role="button" target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/Main_Page">Learn more >></a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Partners Section -->
|
||||
<section class="bg-base-100 py-14 sm:py-12">
|
||||
<div class="mx-auto px-6 lg:px-8">
|
||||
<div class="divider">
|
||||
<h2 class="text-center text-lg/8 font-semibold">Backed by Science</h2>
|
||||
<div id="loading"></div>
|
||||
<div class="col-xs-4">
|
||||
<d-topics-list discourse-url="https://community.envipath.org" per-page="10" category="10"
|
||||
template="complete"></d-topics-list>
|
||||
</div>
|
||||
<div
|
||||
class="mx-auto mt-10 grid max-w-lg grid-cols-4 items-center gap-x-8 gap-y-10 sm:max-w-xl sm:grid-cols-6 sm:gap-x-10 lg:mx-0 lg:max-w-none lg:grid-cols-3"
|
||||
>
|
||||
<img
|
||||
src="{% static "/images/uoa-logo-small.png" %}"
|
||||
alt="The University of Auckland"
|
||||
class="max-h-20 w-full object-contain lg:col-span-1"
|
||||
/>
|
||||
<img
|
||||
src="{% static "/images/logo-eawag.svg" %}"
|
||||
alt="Eawag"
|
||||
class="max-h-12 w-full object-contain lg:col-span-1"
|
||||
/>
|
||||
<img
|
||||
src="{% static "/images/uzh-logo.svg" %}"
|
||||
alt="University of Zurich"
|
||||
class="2 max-h-16 w-full object-contain lg:col-span-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script language="javascript">
|
||||
var currentPackage = "{{ meta.current_package.url }}";
|
||||
|
||||
// Discourse API integration is now handled by discourse-api.js
|
||||
|
||||
// Function to render Discourse topics into cards
|
||||
function renderDiscourseTopics(topics) {
|
||||
const container = document.getElementById("community-news-container");
|
||||
if (!container) return;
|
||||
|
||||
// Clear container
|
||||
container.innerHTML = "";
|
||||
|
||||
// Create cards for each topic
|
||||
topics.forEach((topic) => {
|
||||
const card = createDiscourseCard(topic);
|
||||
container.insertAdjacentHTML("beforeend", card);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to create HTML card for a topic
|
||||
function createDiscourseCard(topic) {
|
||||
const date = new Date(topic.created_at).toLocaleDateString();
|
||||
|
||||
return `
|
||||
<div class="card bg-white shadow-xs hover:shadow-lg transition-shadow duration-300 h-64 w-75 flex-shrink-0">
|
||||
<div class="card-body flex flex-col h-full">
|
||||
<h3 class="card-title leading-tight font-normal tracking-tight h-12 mb-2 line-clamp-2 text-ellipsis wrap-break-word overflow-hidden">
|
||||
<a href="${topic.url}" target="_blank" class="hover:text-primary">
|
||||
${topic.title}
|
||||
</a>
|
||||
</h3>
|
||||
<div class="text-sm line-clamp-4 break-words" >
|
||||
${topic.excerpt}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="avatar tooltip tooltip-right" data-tip="${topic.author}">
|
||||
<div class="w-8 rounded-full">
|
||||
<img src="${topic.author_avatar}" alt="${topic.author}" />
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-xs text-gray-500">${date}</span>
|
||||
</div>
|
||||
<a href="${topic.url}" target="_blank" class="btn btn-ghost text-neutral-500 rounded-full p-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 7v14"/>
|
||||
<path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<form id="index-form" action="{{ meta.current_package.url }}/pathway" method="POST">
|
||||
{% csrf_token %}
|
||||
<div class="input-group" id="index-form-bar">
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<iframe id="index-form-ketcher" src="{% static '/js/ketcher2/ketcher.html' %}" width="100%"
|
||||
height="510"></iframe>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
<input type="text" class="form-control" id='index-form-text-input'
|
||||
placeholder="Enter a SMILES to predict a Pathway or type something to search">
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false" id="action-button">Predict <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a id="dropdown-predict">Predict</a></li>
|
||||
<li><a id="dropdown-search">Search</a></li>
|
||||
</ul>
|
||||
<button class="btn" style="background-color:#222222;color:#9d9d9d" type="button" id="run-button">Go!
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" id="index-form-smiles" name="smiles" value="smiles">
|
||||
<input type="hidden" id="index-form-predict" name="predict" value="predict">
|
||||
</form>
|
||||
</div>
|
||||
<p></p>
|
||||
<script language="javascript">
|
||||
var currentPackage = "{{ meta.current_package.url }}";
|
||||
|
||||
// Make render function globally available
|
||||
window.renderDiscourseTopics = renderDiscourseTopics;
|
||||
function goButtonClicked() {
|
||||
$(this).prop("disabled", true);
|
||||
|
||||
// Toggle functionality with smooth animations
|
||||
function toggleInputMode() {
|
||||
const toggle = $('input[type="checkbox"]');
|
||||
const textContainer = $("#text-input-container");
|
||||
const ketcherContainer = $("#ketcher-container");
|
||||
const formCard = $(".card");
|
||||
const fieldset = $(".fieldset");
|
||||
var action = $('#action-button').text().trim();
|
||||
|
||||
if (toggle.is(":checked")) {
|
||||
// Draw mode - show Ketcher, hide text input
|
||||
textContainer.addClass("opacity-0 transform scale-95");
|
||||
textContainer.removeClass("opacity-100 transform scale-100");
|
||||
var textSmiles = $('#index-form-text-input').val().trim();
|
||||
|
||||
// Adjust fieldset padding for Ketcher mode - reduce padding and make more compact
|
||||
fieldset.removeClass("p-8");
|
||||
fieldset.addClass("p-4");
|
||||
if (textSmiles === '') {
|
||||
$(this).prop("disabled", false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for fade out to complete, then hide and show new content
|
||||
setTimeout(() => {
|
||||
textContainer.addClass("hidden");
|
||||
ketcherContainer.removeClass("hidden opacity-0 transform scale-95");
|
||||
ketcherContainer.addClass("opacity-100 transform scale-100");
|
||||
var ketcherSmiles = getKetcher('index-form-ketcher').getSmiles().trim();
|
||||
|
||||
// Force re-evaluation of iframe size
|
||||
const iframe = document.getElementById("index-ketcher");
|
||||
if (iframe) {
|
||||
iframe.style.height = "400px";
|
||||
}
|
||||
}, 300);
|
||||
} else {
|
||||
// SMILES mode - show text input, hide Ketcher
|
||||
ketcherContainer.addClass("opacity-0 transform scale-95");
|
||||
ketcherContainer.removeClass("opacity-100 transform scale-100");
|
||||
if (action !== 'Search' && ketcherSmiles !== '' && textSmiles !== ketcherSmiles) {
|
||||
console.log("Ketcher and TextInput differ!");
|
||||
}
|
||||
|
||||
// Restore fieldset padding for text input mode
|
||||
fieldset.removeClass("p-4");
|
||||
fieldset.addClass("p-8");
|
||||
|
||||
// Wait for fade out to complete, then hide and show new content
|
||||
setTimeout(() => {
|
||||
ketcherContainer.addClass("hidden");
|
||||
textContainer.removeClass("hidden opacity-0 transform scale-95");
|
||||
textContainer.addClass("opacity-100 transform scale-100");
|
||||
}, 300);
|
||||
|
||||
// Transfer SMILES from Ketcher to text input if available
|
||||
if (window.indexKetcher && window.indexKetcher.getSmiles) {
|
||||
const smiles = window.indexKetcher.getSmiles();
|
||||
if (smiles && smiles.trim() !== "") {
|
||||
$("#index-form-text-input").val(smiles);
|
||||
}
|
||||
if (action === 'Search') {
|
||||
var par = {};
|
||||
par['search'] = textSmiles;
|
||||
par['mode'] = 'text';
|
||||
var queryString = $.param(par, true);
|
||||
window.location.href = "/search?" + queryString;
|
||||
} else {
|
||||
$('#index-form-smiles').val(textSmiles);
|
||||
$('#index-form').submit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ketcher integration
|
||||
function indexKetcherToTextInput() {
|
||||
$("#index-form-smiles").val(this.ketcher.getSmiles());
|
||||
}
|
||||
function actionDropdownClicked() {
|
||||
var suffix = ' <span class="caret"></span>';
|
||||
var dropdownVal = $(this).text();
|
||||
|
||||
$(function () {
|
||||
// Initialize fieldset with proper padding
|
||||
$(".fieldset").addClass("p-8");
|
||||
if (dropdownVal === 'Search') {
|
||||
$("#index-form").attr("action", '/search');
|
||||
$("#index-form").attr("method", 'GET');
|
||||
} else {
|
||||
$("#index-form").attr("action", currentPackage + "/pathway");
|
||||
}
|
||||
|
||||
// Toggle event listener
|
||||
$('input[type="checkbox"]').on("change", toggleInputMode);
|
||||
$('#action-button').html(dropdownVal + suffix);
|
||||
}
|
||||
|
||||
// Ketcher iframe load handler
|
||||
$("#index-ketcher").on("load", function () {
|
||||
const checkKetcherReady = () => {
|
||||
const win = this.contentWindow;
|
||||
if (win.ketcher && "editor" in win.ketcher) {
|
||||
window.indexKetcher = win.ketcher;
|
||||
win.ketcher.editor.event.change.handlers.push({
|
||||
once: false,
|
||||
priority: 0,
|
||||
f: indexKetcherToTextInput,
|
||||
ketcher: win.ketcher,
|
||||
function ketcherToTextInput() {
|
||||
$('#index-form-text-input').val(this.ketcher.getSmiles());
|
||||
}
|
||||
|
||||
$(function () {
|
||||
|
||||
$('#index-form').on("keydown", function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
goButtonClicked();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setTimeout(checkKetcherReady, 100);
|
||||
}
|
||||
};
|
||||
checkKetcherReady();
|
||||
});
|
||||
|
||||
// Handle example link clicks
|
||||
$(".example-link").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
const smiles = $(this).data("smiles");
|
||||
const title = $(this).attr("title");
|
||||
// Code that should be executed once DOM is ready goes here
|
||||
$('#dropdown-predict').on('click', actionDropdownClicked);
|
||||
$('#dropdown-search').on('click', actionDropdownClicked);
|
||||
|
||||
// Check if we're in Ketcher mode or text input mode
|
||||
if ($('input[type="checkbox"]').is(":checked")) {
|
||||
// In Ketcher mode - set the SMILES in Ketcher
|
||||
if (window.indexKetcher && window.indexKetcher.setMolecule) {
|
||||
window.indexKetcher.setMolecule(smiles);
|
||||
}
|
||||
} else {
|
||||
// In text input mode - set the SMILES in the text input
|
||||
$("#index-form-text-input").val(smiles);
|
||||
}
|
||||
$('#run-button').on('click', goButtonClicked);
|
||||
|
||||
// Show a brief feedback
|
||||
const originalText = $(this).text();
|
||||
$(this).text(`loaded!`);
|
||||
setTimeout(() => {
|
||||
$(this).text(originalText);
|
||||
}, 1000);
|
||||
});
|
||||
// Update Ketcher Width
|
||||
var fullWidth = $('#index-form-bar').width();
|
||||
$('#index-form-ketcher').width(fullWidth);
|
||||
|
||||
// Handle form submission on Enter
|
||||
$("#index-form").on("submit", function (e) {
|
||||
e.preventDefault();
|
||||
// add a listener that gets triggered whenever the structure in ketcher has changed
|
||||
$('#index-form-ketcher').on('load', function () {
|
||||
const checkKetcherReady = () => {
|
||||
win = this.contentWindow
|
||||
if (win.ketcher && 'editor' in win.ketcher) {
|
||||
win.ketcher.editor.event.change.handlers.push({
|
||||
once: false,
|
||||
priority: 0,
|
||||
f: ketcherToTextInput,
|
||||
ketcher: win.ketcher
|
||||
});
|
||||
} else {
|
||||
setTimeout(checkKetcherReady, 100);
|
||||
}
|
||||
};
|
||||
|
||||
var textSmiles = "";
|
||||
checkKetcherReady();
|
||||
});
|
||||
|
||||
// Check if we're in Ketcher mode and extract SMILES
|
||||
if ($('input[type="checkbox"]').is(":checked") && window.indexKetcher) {
|
||||
textSmiles = window.indexKetcher.getSmiles().trim();
|
||||
} else {
|
||||
textSmiles = $("#index-form-text-input").val().trim();
|
||||
}
|
||||
|
||||
if (textSmiles === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
$("#index-form-smiles").val(textSmiles);
|
||||
$("#index-form").attr("action", currentPackage + "/pathway");
|
||||
$("#index-form").attr("method", "POST");
|
||||
this.submit();
|
||||
});
|
||||
|
||||
// Discourse topics are now loaded automatically by discourse-api.js
|
||||
});
|
||||
</script>
|
||||
{% endblock main_content %}
|
||||
});
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,71 +1,44 @@
|
||||
{% extends "framework.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="panel-group" id="migration-detail">
|
||||
<div class="panel-group" id="migration-detail">
|
||||
<div class="panel panel-default">
|
||||
<div
|
||||
class="panel-heading"
|
||||
id="headingPanel"
|
||||
style="font-size:2rem;height: 46px"
|
||||
>
|
||||
Migration Status BT Rules
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>Rules with Error: {{ error }}/{{ total }}</p>
|
||||
<p>Rules without Error: {{ success }}/{{ total }}</p>
|
||||
</div>
|
||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||
Migration Status BT Rules
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>Rules with Error: {{ error }}/{{ total }} </p>
|
||||
<p>Rules without Error: {{ success }}/{{ total }}</p>
|
||||
</div>
|
||||
|
||||
{% for obj in results %}
|
||||
<div
|
||||
class="panel panel-default panel-heading list-group-item"
|
||||
style="background-color:silver"
|
||||
>
|
||||
{% if obj.status %}
|
||||
<span
|
||||
class="glyphicon glyphicon-ok"
|
||||
aria-hidden="true"
|
||||
style="float:right"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title=""
|
||||
data-original-title="Reviewed"
|
||||
>
|
||||
{% for obj in results %}
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
{% if obj.status %}
|
||||
<span class="glyphicon glyphicon-ok" aria-hidden="true"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
</span>
|
||||
{% else %}
|
||||
<span
|
||||
class="glyphicon glyphicon-remove"
|
||||
aria-hidden="true"
|
||||
style="float:right"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title=""
|
||||
data-original-title="Reviewed"
|
||||
>
|
||||
{% else %}
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
</span>
|
||||
{% endif %}
|
||||
<h4 class="panel-title">
|
||||
<a
|
||||
id="{{ obj.id }}-link"
|
||||
data-toggle="collapse"
|
||||
data-parent="#migration-detail"
|
||||
href="#{{ obj.id }}"
|
||||
>{{ obj.name|safe }}</a
|
||||
>
|
||||
</h4>
|
||||
{% endif %}
|
||||
<h4 class="panel-title">
|
||||
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
|
||||
href="#{{ obj.id }}">{{ obj.name }}</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
id="{{ obj.id }}"
|
||||
class="panel-collapse {% if not obj.status %}in{% endif %} collapse"
|
||||
>
|
||||
<div class="panel-body list-group-item">
|
||||
<a class="list-group-item" href="{{ obj.detail_url }}"
|
||||
>{{ obj.name|safe }} Migration Detail Page</a
|
||||
>
|
||||
</div>
|
||||
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
|
||||
<div class="panel-body list-group-item">
|
||||
<a class="list-group-item" href="{{ obj.detail_url }}">{{ obj.name }} Migration Detail Page</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script></script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,77 +1,45 @@
|
||||
{% extends "framework.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="panel-group" id="migration-detail">
|
||||
<div class="panel panel-default">
|
||||
<div
|
||||
class="panel-heading"
|
||||
id="headingPanel"
|
||||
style="font-size:2rem;height: 46px"
|
||||
>
|
||||
Migration Status for {{ bt_rule_name }}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
A package contains pathways, rules, etc. and can reflect specific
|
||||
experimental conditions.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
role="button"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<div class="panel-group" id="migration-detail">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||
Migration Status for {{ bt_rule_name }}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>A package contains pathways, rules, etc. and can reflect specific experimental
|
||||
conditions. <a target="_blank" href="https://wiki.envipath.org/index.php/packages" role="button">Learn
|
||||
more >></a></p>
|
||||
</div>
|
||||
|
||||
{% for obj in results %}
|
||||
<div
|
||||
class="panel panel-default panel-heading list-group-item"
|
||||
style="background-color:silver"
|
||||
>
|
||||
{% if obj.status %}
|
||||
<span
|
||||
class="glyphicon glyphicon-ok"
|
||||
aria-hidden="true"
|
||||
style="float:right"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title=""
|
||||
data-original-title="Reviewed"
|
||||
>
|
||||
</span>
|
||||
{% else %}
|
||||
<span
|
||||
class="glyphicon glyphicon-remove"
|
||||
aria-hidden="true"
|
||||
style="float:right"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
title=""
|
||||
data-original-title="Reviewed"
|
||||
>
|
||||
</span>
|
||||
{% endif %}
|
||||
<h4 class="panel-title">
|
||||
<a
|
||||
id="{{ obj.id }}-link"
|
||||
data-toggle="collapse"
|
||||
data-parent="#migration-detail"
|
||||
href="#{{ obj.id }}"
|
||||
>{{ obj.name|safe }}</a
|
||||
>
|
||||
</h4>
|
||||
{% for obj in results %}
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
{% if obj.status %}
|
||||
<span class="glyphicon glyphicon-ok" aria-hidden="true"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
</span>
|
||||
{% endif %}
|
||||
<h4 class="panel-title">
|
||||
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
|
||||
href="#{{ obj.id }}">{{ obj.name }}</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
|
||||
<div class="panel-body list-group-item">
|
||||
<pre>{{ obj.detail }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div
|
||||
id="{{ obj.id }}"
|
||||
class="panel-collapse {% if not obj.status %}in{% endif %} collapse"
|
||||
>
|
||||
<div class="panel-body list-group-item">
|
||||
<pre>{{ obj.detail }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script></script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,48 +1,31 @@
|
||||
<div
|
||||
class="modal fade bs-modal-lg"
|
||||
id="citemodal"
|
||||
tabindex="-1"
|
||||
role="dialog"
|
||||
aria-labelledby="myLargeModalLabel"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>How to cite enviPath</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ol class="list-group list-group-numbered">
|
||||
<li class="list-group-item">
|
||||
Hafner, J., Lorsbach, T., Schmidt, S. <em>et al.</em>
|
||||
<cite
|
||||
>Advancements in biotransformation pathway prediction:
|
||||
enhancements, datasets, and novel functionalities in
|
||||
enviPath.</cite
|
||||
>
|
||||
<a href="https://doi.org/10.1186/s13321-024-00881-6" target="_blank"
|
||||
>J Cheminform 16, 93 (2024)</a
|
||||
>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
Wicker, J., Lorsbach, T., Gütlein, M., Schmid, E., Latino, D.,
|
||||
Kramer, S., Fenner, K.
|
||||
<cite
|
||||
>enviPath - The environmental contaminant biotransformation
|
||||
pathway resource</cite
|
||||
>
|
||||
<a href="https://doi.org/10.1093/nar/gkv1229" target="_blank">
|
||||
Nucleic Acids Research, Volume 44, Issue D1, 4 January 2016, Pages
|
||||
D502-D508
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal fade bs-modal-lg" id="citemodal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>How to cite enviPath</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ol class="list-group list-group-numbered">
|
||||
<li class="list-group-item">
|
||||
Hafner, J., Lorsbach, T., Schmidt, S. <em>et al.</em>
|
||||
<cite>Advancements in biotransformation pathway prediction: enhancements, datasets, and novel
|
||||
functionalities in enviPath.</cite>
|
||||
<a href="https://doi.org/10.1186/s13321-024-00881-6" target="_blank">J Cheminform 16, 93
|
||||
(2024)</a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
Wicker, J., Lorsbach, T., Gütlein, M., Schmid, E., Latino, D., Kramer, S., Fenner, K.
|
||||
<cite>enviPath - The environmental contaminant biotransformation pathway resource</cite>
|
||||
<a href="https://doi.org/10.1093/nar/gkv1229" target="_blank">
|
||||
Nucleic Acids Research, Volume 44, Issue D1, 4 January 2016, Pages D502-D508
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,70 +1,42 @@
|
||||
<div
|
||||
class="modal fade"
|
||||
tabindex="-1"
|
||||
id="import_legacy_package_modal"
|
||||
role="dialog"
|
||||
aria-labelledby="import_legacy_package_modal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Import Package from legacy System</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Create a Package based on the JSON Export of the legacy system.</p>
|
||||
<form
|
||||
id="import-legacy-package-modal-form"
|
||||
accept-charset="UTF-8"
|
||||
data-remote="true"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label class="btn btn-primary" for="legacyJsonFile">
|
||||
<input
|
||||
id="legacyJsonFile"
|
||||
name="file"
|
||||
type="file"
|
||||
style="display:none;"
|
||||
onchange="$('#upload-legacy-file-info').html(this.files[0].name)"
|
||||
/>
|
||||
Choose JSON File
|
||||
</label>
|
||||
<span class="label label-info" id="upload-legacy-file-info"></span>
|
||||
<input
|
||||
type="hidden"
|
||||
value="import-legacy-package-json"
|
||||
name="hidden"
|
||||
readonly=""
|
||||
/>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a
|
||||
id="import-legacy-package-modal-form-submit"
|
||||
class="btn btn-primary"
|
||||
href="#"
|
||||
>Submit</a
|
||||
>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal fade" tabindex="-1" id="import_legacy_package_modal" role="dialog"
|
||||
aria-labelledby="import_legacy_package_modal" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Import Package from legacy System</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Create a Package based on the JSON Export of the legacy system.</p>
|
||||
<form id="import-legacy-package-modal-form" accept-charset="UTF-8" data-remote="true" method="post"
|
||||
enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label class="btn btn-primary" for="legacyJsonFile">
|
||||
<input id="legacyJsonFile" name="file" type="file" style="display:none;"
|
||||
onchange="$('#upload-legacy-file-info').html(this.files[0].name)">
|
||||
Choose JSON File
|
||||
</label>
|
||||
<span class="label label-info" id="upload-legacy-file-info"></span>
|
||||
<input type="hidden" value="import-legacy-package-json" name="hidden" readonly="">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="import-legacy-package-modal-form-submit" class="btn btn-primary" href="#">Submit</a>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
$("#import-legacy-package-modal-form-submit").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
$("#import-legacy-package-modal-form").submit();
|
||||
$(function () {
|
||||
$('#import-legacy-package-modal-form-submit').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#import-legacy-package-modal-form').submit();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,70 +1,42 @@
|
||||
<div
|
||||
class="modal fade"
|
||||
tabindex="-1"
|
||||
id="import_package_modal"
|
||||
role="dialog"
|
||||
aria-labelledby="import_package_modal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Import Package</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Create a Package based on a JSON Export.</p>
|
||||
<form
|
||||
id="import-package-modal-form"
|
||||
accept-charset="UTF-8"
|
||||
data-remote="true"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label class="btn btn-primary" for="jsonFile">
|
||||
<input
|
||||
id="jsonFile"
|
||||
name="file"
|
||||
type="file"
|
||||
style="display:none;"
|
||||
onchange="$('#upload-file-info').html(this.files[0].name)"
|
||||
/>
|
||||
Choose JSON File
|
||||
</label>
|
||||
<span class="label label-info" id="upload-file-info"></span>
|
||||
<input
|
||||
type="hidden"
|
||||
value="import-package-json"
|
||||
name="hidden"
|
||||
readonly=""
|
||||
/>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a
|
||||
id="import-package-modal-form-submit"
|
||||
class="btn btn-primary"
|
||||
href="#"
|
||||
>Submit</a
|
||||
>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal fade" tabindex="-1" id="import_package_modal" role="dialog"
|
||||
aria-labelledby="import_package_modal" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Import Package</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Create a Package based on a JSON Export.</p>
|
||||
<form id="import-package-modal-form" accept-charset="UTF-8" data-remote="true" method="post"
|
||||
enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label class="btn btn-primary" for="jsonFile">
|
||||
<input id="jsonFile" name="file" type="file" style="display:none;"
|
||||
onchange="$('#upload-file-info').html(this.files[0].name)">
|
||||
Choose JSON File
|
||||
</label>
|
||||
<span class="label label-info" id="upload-file-info"></span>
|
||||
<input type="hidden" value="import-package-json" name="hidden" readonly="">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="import-package-modal-form-submit" class="btn btn-primary" href="#">Submit</a>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
$("#import-package-modal-form-submit").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
$("#import-package-modal-form").submit();
|
||||
$(function () {
|
||||
$('#import-package-modal-form-submit').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#import-package-modal-form').submit();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,119 +1,78 @@
|
||||
{% load static %}
|
||||
<div
|
||||
class="modal fade bs-modal-lg"
|
||||
id="new_compound_modal"
|
||||
tabindex="-1"
|
||||
aria-labelledby="new_compound_modal"
|
||||
aria-modal="true"
|
||||
role="dialog"
|
||||
>
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Create a new Compound</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form
|
||||
id="new_compound_modal_form"
|
||||
accept-charset="UTF-8"
|
||||
action="{% url 'package compound list' meta.current_package.uuid %}"
|
||||
data-remote="true"
|
||||
method="post"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<label for="compound-name">Name</label>
|
||||
<input
|
||||
id="compound-name"
|
||||
class="form-control"
|
||||
name="compound-name"
|
||||
placeholder="Name"
|
||||
/>
|
||||
<label for="compound-description">Description</label>
|
||||
<input
|
||||
id="compound-description"
|
||||
class="form-control"
|
||||
name="compound-description"
|
||||
placeholder="Description"
|
||||
/>
|
||||
<label for="compound-smiles">SMILES</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="compound-smiles"
|
||||
placeholder="SMILES"
|
||||
id="compound-smiles"
|
||||
/>
|
||||
<p></p>
|
||||
<div>
|
||||
<iframe
|
||||
id="new_compound_ketcher"
|
||||
src="{% static '/js/ketcher2/ketcher.html' %}"
|
||||
width="100%"
|
||||
height="510"
|
||||
></iframe>
|
||||
</div>
|
||||
<p></p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary pull-left"
|
||||
data-dismiss="modal"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
id="new_compound_modal_form_submit"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal fade bs-modal-lg" id="new_compound_modal" tabindex="-1" aria-labelledby="new_compound_modal" aria-modal="true"
|
||||
role="dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Create a new Compound</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="new_compound_modal_form" accept-charset="UTF-8" action="{% url 'package compound list' meta.current_package.uuid %}" data-remote="true" method="post">
|
||||
{% csrf_token %}
|
||||
<label for="compound-name">Name</label>
|
||||
<input id="compound-name" class="form-control" name="compound-name" placeholder="Name"/>
|
||||
<label for="compound-description">Description</label>
|
||||
<input id="compound-description" class="form-control" name="compound-description" placeholder="Description"/>
|
||||
<label for="compound-smiles">SMILES</label>
|
||||
<input type="text" class="form-control" name="compound-smiles" placeholder="SMILES" id="compound-smiles">
|
||||
<p></p>
|
||||
<div>
|
||||
<iframe id="new_compound_ketcher" src="{% static '/js/ketcher2/ketcher.html' %}" width="100%"
|
||||
height="510"></iframe>
|
||||
</div>
|
||||
<p></p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary pull-left" data-dismiss="modal">Close
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="new_compound_modal_form_submit">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
function newCompoundModalketcherToNewCompoundModalTextInput() {
|
||||
$("#compound-smiles").val(this.ketcher.getSmiles());
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$("#new_compound_ketcher").on("load", function () {
|
||||
const checkKetcherReady = () => {
|
||||
win = this.contentWindow;
|
||||
if (win.ketcher && "editor" in win.ketcher) {
|
||||
win.ketcher.editor.event.change.handlers.push({
|
||||
once: false,
|
||||
priority: 0,
|
||||
f: newCompoundModalketcherToNewCompoundModalTextInput,
|
||||
ketcher: win.ketcher,
|
||||
});
|
||||
} else {
|
||||
setTimeout(checkKetcherReady, 100);
|
||||
}
|
||||
};
|
||||
function newCompoundModalketcherToNewCompoundModalTextInput() {
|
||||
$('#compound-smiles').val(this.ketcher.getSmiles());
|
||||
}
|
||||
|
||||
checkKetcherReady();
|
||||
$(function() {
|
||||
|
||||
$('#new_compound_ketcher').on('load', function() {
|
||||
const checkKetcherReady = () => {
|
||||
win = this.contentWindow
|
||||
if (win.ketcher && 'editor' in win.ketcher) {
|
||||
win.ketcher.editor.event.change.handlers.push({
|
||||
once: false,
|
||||
priority: 0,
|
||||
f: newCompoundModalketcherToNewCompoundModalTextInput,
|
||||
ketcher: win.ketcher
|
||||
});
|
||||
} else {
|
||||
setTimeout(checkKetcherReady, 100);
|
||||
}
|
||||
};
|
||||
|
||||
checkKetcherReady();
|
||||
})
|
||||
|
||||
$(function() {
|
||||
$('#new_compound_modal_form_submit').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).prop("disabled",true);
|
||||
|
||||
|
||||
|
||||
// submit form
|
||||
$('#new_compound_modal_form').submit();
|
||||
});
|
||||
});
|
||||
|
||||
$(function () {
|
||||
$("#new_compound_modal_form_submit").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
$(this).prop("disabled", true);
|
||||
});
|
||||
|
||||
// submit form
|
||||
$("#new_compound_modal_form").submit();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,70 +1,45 @@
|
||||
<div
|
||||
class="modal fade"
|
||||
tabindex="-1"
|
||||
id="new_group_modal"
|
||||
role="dialog"
|
||||
aria-labelledby="new_group_modal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">New Group</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
Create new Group. You can assign users to the group once it is
|
||||
created. Description can be changed after creation.
|
||||
</p>
|
||||
<form
|
||||
id="new_group_modal_form"
|
||||
accept-charset="UTF-8"
|
||||
action="{{ SERVER_BASE }}/group"
|
||||
data-remote="true"
|
||||
method="post"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="name">Name</label>
|
||||
<input
|
||||
id="name"
|
||||
type="text"
|
||||
name="group-name"
|
||||
class="form-control"
|
||||
placeholder="Name"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="description">Description</label>
|
||||
<input
|
||||
id="description"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Description..."
|
||||
name="group-description"
|
||||
/>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="new_group_modal_form_submit" class="btn btn-primary" href="#"
|
||||
>Submit</a
|
||||
>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal fade" tabindex="-1" id="new_group_modal" role="dialog" aria-labelledby="new_group_modal"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">New Group</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Create new Group. You can assign users to the group once
|
||||
it is created. Description can be changed after creation.</p>
|
||||
<form id="new_group_modal_form" accept-charset="UTF-8" action="{{ SERVER_BASE }}/group"
|
||||
data-remote="true"
|
||||
method="post">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="name">Name</label>
|
||||
<input id="name" type="text" name="group-name" class="form-control" placeholder="Name"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="description">Description</label>
|
||||
<input id="description" type="text" class="form-control" placeholder="Description..."
|
||||
name="group-description"/>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="new_group_modal_form_submit" class="btn btn-primary" href="#">Submit</a>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
$("#new_group_modal_form_submit").on("click", function () {
|
||||
$("#new_group_modal_form").submit();
|
||||
$(function() {
|
||||
$('#new_group_modal_form_submit').on('click', function() {
|
||||
$('#new_group_modal_form').submit();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,270 +1,187 @@
|
||||
<div
|
||||
class="modal fade"
|
||||
tabindex="-1"
|
||||
id="new_model_modal"
|
||||
role="dialog"
|
||||
aria-labelledby="new_model_modal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">New Model</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form
|
||||
id="new_model_form"
|
||||
accept-charset="UTF-8"
|
||||
action="{{ meta.current_package.url }}/model"
|
||||
data-remote="true"
|
||||
method="post"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<div class="jumbotron">
|
||||
Create a new Model to limit the number of degradation products in
|
||||
the prediction. You just need to set a name and the packages you
|
||||
want the object to be based on. There are multiple types of models
|
||||
available. For additional information have a look at our
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/relative-reasoning"
|
||||
role="button"
|
||||
>wiki >></a
|
||||
>
|
||||
</div>
|
||||
<!-- Name -->
|
||||
<label for="model-name">Name</label>
|
||||
<input
|
||||
id="model-name"
|
||||
name="model-name"
|
||||
class="form-control"
|
||||
placeholder="Name"
|
||||
/>
|
||||
<div class="modal fade" tabindex="-1" id="new_model_modal" role="dialog" aria-labelledby="new_model_modal"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title">New Model</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="new_model_form" accept-charset="UTF-8" action="{{ meta.current_package.url }}/model"
|
||||
data-remote="true" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="jumbotron">Create a new Model to
|
||||
limit the number of degradation products in the
|
||||
prediction. You just need to set a name and the packages
|
||||
you want the object to be based on. There are multiple types of models available.
|
||||
For additional information have a look at our
|
||||
<a target="_blank" href="https://wiki.envipath.org/index.php/relative-reasoning" role="button">wiki
|
||||
>></a>
|
||||
</div>
|
||||
<!-- Name -->
|
||||
<label for="model-name">Name</label>
|
||||
<input id="model-name" name="model-name" class="form-control" placeholder="Name"/>
|
||||
|
||||
<!-- Description -->
|
||||
<label for="model-description">Description</label>
|
||||
<input
|
||||
id="model-description"
|
||||
name="model-description"
|
||||
class="form-control"
|
||||
placeholder="Description"
|
||||
/>
|
||||
<!-- Description -->
|
||||
<label for="model-description">Description</label>
|
||||
<input id="model-description" name="model-description" class="form-control"
|
||||
placeholder="Description"/>
|
||||
|
||||
<!-- Model Type -->
|
||||
<label for="model-type">Model Type</label>
|
||||
<select
|
||||
id="model-type"
|
||||
name="model-type"
|
||||
class="form-control"
|
||||
data-width="100%"
|
||||
>
|
||||
<option disabled selected>Select Model Type</option>
|
||||
{% for k, v in model_types.items %}
|
||||
<option value="{{ v }}">{{ k }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<!-- Model Type -->
|
||||
<label for="model-type">Model Type</label>
|
||||
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
||||
<option disabled selected>Select Model Type</option>
|
||||
{% for k, v in model_types.items %}
|
||||
<option value="{{ v }}">{{ k }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<!-- Rule Packages -->
|
||||
<div id="rule-packages" class="ep-model-param mlrr rbrr">
|
||||
<label for="model-rule-packages">Rule Packages</label>
|
||||
<select
|
||||
id="model-rule-packages"
|
||||
name="model-rule-packages"
|
||||
data-actions-box="true"
|
||||
class="form-control"
|
||||
multiple
|
||||
data-width="100%"
|
||||
>
|
||||
<option disabled>Reviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Rule Packages -->
|
||||
<div id="rule-packages" class="ep-model-param mlrr rbrr">
|
||||
<label for="model-rule-packages">Rule Packages</label>
|
||||
<select id="model-rule-packages" name="model-rule-packages" data-actions-box='true'
|
||||
class="form-control" multiple data-width='100%'>
|
||||
<option disabled>Reviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<option disabled>Unreviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if not obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<option disabled>Unreviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if not obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Data Packages -->
|
||||
<div id="data-packages" class="ep-model-param mlrr rbrr enviformer">
|
||||
<label for="model-data-packages">Data Packages</label>
|
||||
<select
|
||||
id="model-data-packages"
|
||||
name="model-data-packages"
|
||||
data-actions-box="true"
|
||||
class="form-control"
|
||||
multiple
|
||||
data-width="100%"
|
||||
>
|
||||
<option disabled>Reviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Data Packages -->
|
||||
<div id="data-packages" class="ep-model-param mlrr rbrr enviformer">
|
||||
<label for="model-data-packages">Data Packages</label>
|
||||
<select id="model-data-packages" name="model-data-packages" data-actions-box='true'
|
||||
class="form-control" multiple data-width='100%'>
|
||||
<option disabled>Reviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<option disabled>Unreviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if not obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<option disabled>Unreviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if not obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Fingerprinter -->
|
||||
<div id="fingerprinter" class="ep-model-param mlrr">
|
||||
<label for="model-fingerprinter">Fingerprinter</label>
|
||||
<select
|
||||
id="model-fingerprinter"
|
||||
name="model-fingerprinter"
|
||||
data-actions-box="true"
|
||||
class="form-control"
|
||||
multiple
|
||||
data-width="100%"
|
||||
>
|
||||
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
||||
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
|
||||
<option disabled selected>
|
||||
Select Additional Fingerprinter / Descriptor
|
||||
</option>
|
||||
{% for k, v in additional_descriptors.items %}
|
||||
<option value="{{ v }}">{{ k }}</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
<!-- Fingerprinter -->
|
||||
<div id="fingerprinter" class="ep-model-param mlrr">
|
||||
<label for="model-fingerprinter">Fingerprinter</label>
|
||||
<select id="model-fingerprinter" name="model-fingerprinter" data-actions-box='true'
|
||||
class="form-control" multiple data-width='100%'>
|
||||
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
||||
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
|
||||
<option disabled selected>Select Additional Fingerprinter / Descriptor</option>
|
||||
{% for k, v in additional_descriptors.items %}
|
||||
<option value="{{ v }}">{{ k }}</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Threshold -->
|
||||
<div id="threshold" class="ep-model-param mlrr enviformer">
|
||||
<label for="model-threshold">Threshold</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.05"
|
||||
value="0.5"
|
||||
id="model-threshold"
|
||||
name="model-threshold"
|
||||
class="form-control"
|
||||
/>
|
||||
</div>
|
||||
<!-- Threshold -->
|
||||
<div id="threshold" class="ep-model-param mlrr enviformer">
|
||||
<label for="model-threshold">Threshold</label>
|
||||
<input type="number" min="0" max="1" step="0.05" value="0.5" id="model-threshold"
|
||||
name="model-threshold" class="form-control">
|
||||
</div>
|
||||
|
||||
<div id="appdomain" class="ep-model-param mlrr">
|
||||
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
|
||||
<!-- Build AD? -->
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="build-app-domain"
|
||||
name="build-app-domain"
|
||||
/>Also build an Applicability Domain?
|
||||
</label>
|
||||
</div>
|
||||
<div id="ad-params" style="display:none">
|
||||
<!-- Num Neighbors -->
|
||||
<label for="num-neighbors">Number of Neighbors</label>
|
||||
<input
|
||||
id="num-neighbors"
|
||||
name="num-neighbors"
|
||||
type="number"
|
||||
class="form-control"
|
||||
value="5"
|
||||
step="1"
|
||||
min="0"
|
||||
max="10"
|
||||
/>
|
||||
<!-- Local Compatibility -->
|
||||
<label for="local-compatibility-threshold"
|
||||
>Local Compatibility Threshold</label
|
||||
>
|
||||
<input
|
||||
id="local-compatibility-threshold"
|
||||
name="local-compatibility-threshold"
|
||||
type="number"
|
||||
class="form-control"
|
||||
value="0.5"
|
||||
step="0.01"
|
||||
min="0"
|
||||
max="1"
|
||||
/>
|
||||
<!-- Reliability -->
|
||||
<label for="reliability-threshold">Reliability Threshold</label>
|
||||
<input
|
||||
id="reliability-threshold"
|
||||
name="reliability-threshold"
|
||||
type="number"
|
||||
class="form-control"
|
||||
value="0.5"
|
||||
step="0.01"
|
||||
min="0"
|
||||
max="1"
|
||||
/>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="new_model_modal_form_submit" class="btn btn-primary" href="#"
|
||||
>Submit</a
|
||||
>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div id="appdomain" class="ep-model-param mlrr">
|
||||
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
|
||||
<!-- Build AD? -->
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="build-app-domain" name="build-app-domain">Also build an
|
||||
Applicability Domain?
|
||||
</label>
|
||||
</div>
|
||||
<div id="ad-params" style="display:none">
|
||||
<!-- Num Neighbors -->
|
||||
<label for="num-neighbors">Number of Neighbors</label>
|
||||
<input id="num-neighbors" name="num-neighbors" type="number" class="form-control"
|
||||
value="5"
|
||||
step="1" min="0" max="10">
|
||||
<!-- Local Compatibility -->
|
||||
<label for="local-compatibility-threshold">Local Compatibility Threshold</label>
|
||||
<input id="local-compatibility-threshold" name="local-compatibility-threshold"
|
||||
type="number"
|
||||
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||
<!-- Reliability -->
|
||||
<label for="reliability-threshold">Reliability Threshold</label>
|
||||
<input id="reliability-threshold" name="reliability-threshold" type="number"
|
||||
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="new_model_modal_form_submit" class="btn btn-primary" href="#">Submit</a>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
// Built in Model Types
|
||||
var nativeModelTypes = ["mlrr", "rbrr", "enviformer"];
|
||||
$(function () {
|
||||
// Built in Model Types
|
||||
var nativeModelTypes = [
|
||||
"mlrr",
|
||||
"rbrr",
|
||||
"enviformer",
|
||||
]
|
||||
|
||||
// Initially hide all "specific" forms
|
||||
$(".ep-model-param").each(function () {
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
$('#model-type').selectpicker();
|
||||
$("#model-fingerprinter").selectpicker();
|
||||
$("#model-rule-packages").selectpicker();
|
||||
$("#model-data-packages").selectpicker();
|
||||
|
||||
$("#build-app-domain").change(function () {
|
||||
if ($(this).is(":checked")) {
|
||||
$('#ad-params').show();
|
||||
} else {
|
||||
$('#ad-params').hide();
|
||||
}
|
||||
});
|
||||
|
||||
// On change hide all and show only selected
|
||||
$("#model-type").change(function () {
|
||||
$('.ep-model-param').hide();
|
||||
var modelType = $('#model-type').val();
|
||||
if (nativeModelTypes.indexOf(modelType) !== -1) {
|
||||
$('.' + modelType).show();
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
|
||||
$('#new_model_modal_form_submit').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#new_model_form').submit();
|
||||
});
|
||||
|
||||
// Initially hide all "specific" forms
|
||||
$(".ep-model-param").each(function () {
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
$("#model-type").selectpicker();
|
||||
$("#model-fingerprinter").selectpicker();
|
||||
$("#model-rule-packages").selectpicker();
|
||||
$("#model-data-packages").selectpicker();
|
||||
|
||||
$("#build-app-domain").change(function () {
|
||||
if ($(this).is(":checked")) {
|
||||
$("#ad-params").show();
|
||||
} else {
|
||||
$("#ad-params").hide();
|
||||
}
|
||||
});
|
||||
|
||||
// On change hide all and show only selected
|
||||
$("#model-type").change(function () {
|
||||
$(".ep-model-param").hide();
|
||||
var modelType = $("#model-type").val();
|
||||
if (nativeModelTypes.indexOf(modelType) !== -1) {
|
||||
$("." + modelType).show();
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
|
||||
$("#new_model_modal_form_submit").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
$("#new_model_form").submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||