diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..4146bb7 --- /dev/null +++ b/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": [ + [ + "@babel/preset-env" + ] + ] +} \ No newline at end of file diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..650742c --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,10 @@ +[production staging] +>5% +last 2 versions +Firefox ESR +not ie < 11 + +[development] +last 1 chrome version +last 1 firefox version +last 1 edge version diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..6748500 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,30 @@ +[run] +source = + arches_vue_utils/ + +omit = + */python?.?/* + */migrations/* + */settings*.py + */urls.py + */wsgi.py + */hosts.py + */celery.py + */__init__.py + +data_file = coverage/python/.coverage + +[report] +show_missing = true + +exclude_lines = + pragma: no cover + +[html] +directory = coverage/python/htmlcov + +[xml] +output = coverage/python/coverage.xml + +[json] +output = coverage/python/coverage.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..924ef88 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Known binary formats +*.png binary +*.jpg binary +*.ico binary +*.gif binary +*.ttf binary +*.woff binary +*.woff2 binary diff --git a/.github/actions/build-and-test-branch/action.yml b/.github/actions/build-and-test-branch/action.yml new file mode 100644 index 0000000..41921f2 --- /dev/null +++ b/.github/actions/build-and-test-branch/action.yml @@ -0,0 +1,109 @@ +name: 'Build and test branch' +description: 'Builds and tests a branch' +inputs: + branch-type: + description: 'String denoting either `target` or `feature` branch' + required: true + project-name: + description: 'String denoting the name of the project' + required: true + secrets: + description: 'Secrets from main.yml as JSON' +runs: + using: 'composite' + steps: + - name: Install Java, GDAL, and other system dependencies + run: | + sudo apt update + sudo apt-get install libxml2-dev libpq-dev openjdk-8-jdk libgdal-dev libxslt-dev + echo Postgres and ES dependencies installed + shell: bash + + - name: Set up Elasticsearch + uses: ankane/setup-elasticsearch@v1 + with: + elasticsearch-version: 8 + + - name: Install Python packages + run: | + python -m pip install --upgrade pip + pip install '.[dev]' + echo Python packages installed + shell: bash + + - name: Ensure frontend configuration files exist + run: | + python manage.py check + shell: bash + + - name: Install Arches applications + uses: ./.github/actions/install-arches-applications + with: + secrets: ${{ inputs.secrets }} + + - name: Install frontend dependencies + run: | + npm install + shell: bash + + - name: Webpack frontend files + run: | + npm run build_test + shell: bash + + - name: Check frontend formatting with prettier + run: | + npm run prettier:check + shell: bash + + - name: Check backend formatting with black + run: | + black . --check --exclude=node_modules + shell: bash + + - name: Check line endings on all but ontology (.xml) files + run: | + ! git ls-files --eol | grep -v '.xml' | grep 'w/crlf\|w/mixed' + shell: bash + + - name: Run frontend tests + run: | + npm run vitest + mv coverage/frontend/coverage.xml ${{ inputs.branch-type }}_branch_frontend_coverage.xml + shell: bash + + - name: Check for missing migrations + run: | + python manage.py makemigrations --check + shell: bash + + - name: Ensure previous Python coverage data is erased + run: | + coverage erase + shell: bash + + - name: Run Python unit tests + run: | + python -W default::DeprecationWarning -m coverage run manage.py test tests --settings="tests.test_settings" + shell: bash + + - name: Generate Python report coverage + run: | + coverage report + coverage json + mv coverage/python/coverage.json ${{ inputs.branch-type }}_branch_python_coverage.json + shell: bash + + - name: Upload frontend coverage report as artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.branch-type }}-branch-frontend-coverage-report + path: ${{ inputs.branch-type }}_branch_frontend_coverage.xml + overwrite: true + + - name: Upload Python coverage report as artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.branch-type }}-branch-python-coverage-report + path: ${{ inputs.branch-type }}_branch_python_coverage.json + overwrite: true diff --git a/.github/actions/install-arches-applications/action.yml b/.github/actions/install-arches-applications/action.yml new file mode 100644 index 0000000..703e33a --- /dev/null +++ b/.github/actions/install-arches-applications/action.yml @@ -0,0 +1,29 @@ +name: 'Install Arches Applications' +description: 'Manually edit this file to install all Arches Applications declared in settings.py, but not declared in `pyproject.toml`' +inputs: + secrets: + description: 'Secrets from main.yml as JSON' +runs: + using: 'composite' + steps: + + # Manually add any ARCHES_APPLICATIONS to this file if not already declared in `pyproject.toml`. + # Below is a template for adding an application in a private repository. + # Be sure to delete the `no-op step` if adding when updating this file. + + - name: No-op step to maintain workflow structure + run: echo "No-op step" + shell: bash + + # - name: Checkout ${my_arches_application_name} + # uses: actions/checkout@v4 + # with: + # repository: ${my_arches_application_repository}/${my_arches_application_name} + # token: ${{ fromJSON(inputs.secrets).${my_github_personal_access_token} }} + # path: ${my_arches_application_name} + + # - name: Install ${my_arches_application_name} + # run: | + # pip install ./${my_arches_application_name} + # echo ${my_arches_application_name} installed + # shell: bash diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..db51c4c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,272 @@ +name: CI + +on: + # push: -- just run on PRs for now + pull_request: + workflow_dispatch: + +jobs: + build_target_branch: + runs-on: ubuntu-latest + + services: + postgres: + image: postgis/postgis:13-3.0 + env: + POSTGRES_PASSWORD: postgis + POSTGRES_DB: arches_vue_utils + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + strategy: + fail-fast: false + matrix: + python-version: ["3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + check-latest: true + + - name: Checkout into target branch + uses: actions/checkout@v4 + with: + repository: ${{ github.repository }} + ref: ${{ github.event.pull_request.base.ref }} + path: . + + - name: Build and test branch + uses: ./.github/actions/build-and-test-branch + with: + secrets: ${{ toJSON(secrets) }} + project-name: 'arches_vue_utils' + branch-type: 'target' + + build_feature_branch: + runs-on: ubuntu-latest + + services: + postgres: + image: postgis/postgis:13-3.0 + env: + POSTGRES_PASSWORD: postgis + POSTGRES_DB: arches_vue_utils + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + check-latest: true + + - name: Checkout into feature branch + uses: actions/checkout@v4 + with: + repository: ${{ github.repository }} + ref: ${{ github.ref }} + path: . + + - name: Build and test branch + uses: ./.github/actions/build-and-test-branch + with: + secrets: ${{ toJSON(secrets) }} + project-name: 'arches_vue_utils' + branch-type: 'feature' + + check_frontend_coverage: + runs-on: ubuntu-latest + needs: [build_feature_branch, build_target_branch] + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' # Use the latest available version + check-latest: true + + - name: Download feature branch frontend coverage report artifact + uses: actions/download-artifact@v4 + with: + name: feature-branch-frontend-coverage-report + path: . + + - name: Extract feature branch frontend coverage data + shell: pwsh + run: | + [xml]$xml = Get-Content feature_branch_frontend_coverage.xml + $metrics = $xml.coverage.project.metrics + + $statements = [double]$metrics.statements + $coveredstatements = [double]$metrics.coveredstatements + $conditionals = [double]$metrics.conditionals + $coveredconditionals = [double]$metrics.coveredconditionals + $methods = [double]$metrics.methods + $coveredmethods = [double]$metrics.coveredmethods + $elements = [double]$metrics.elements + $coveredelements = [double]$metrics.coveredelements + + $statement_coverage = 0.0 + $conditional_coverage = 0.0 + $method_coverage = 0.0 + $element_coverage = 0.0 + + if ($statements -gt 0) { + $statement_coverage = ($coveredstatements / $statements) * 100 + } + if ($conditionals -gt 0) { + $conditional_coverage = ($coveredconditionals / $conditionals) * 100 + } + if ($methods -gt 0) { + $method_coverage = ($coveredmethods / $methods) * 100 + } + if ($elements -gt 0) { + $element_coverage = ($coveredelements / $elements) * 100 + } + + $nonZeroCount = 0 + $totalCoverage = 0.0 + + if ($statements -gt 0) { $nonZeroCount++; $totalCoverage += $statement_coverage } + if ($conditionals -gt 0) { $nonZeroCount++; $totalCoverage += $conditional_coverage } + if ($methods -gt 0) { $nonZeroCount++; $totalCoverage += $method_coverage } + if ($elements -gt 0) { $nonZeroCount++; $totalCoverage += $element_coverage } + + $feature_branch_frontend_coverage = 0.0 + if ($nonZeroCount -gt 0) { + $feature_branch_frontend_coverage = $totalCoverage / $nonZeroCount + } + + Write-Output "feature_branch_frontend_coverage=$feature_branch_frontend_coverage" | Out-File -Append $env:GITHUB_ENV + + - name: Download target branch frontend coverage report artifact + continue-on-error: true + uses: actions/download-artifact@v4 + with: + name: target-branch-frontend-coverage-report + path: . + + - name: Check if target branch frontend coverage report artifact exists + run: | + if [ -f target_branch_frontend_coverage.xml ]; then + echo "target_branch_frontend_coverage_artifact_exists=true" >> $GITHUB_ENV + else + echo "Target branch coverage not found. Defaulting to 0% coverage." + echo "target_branch_frontend_coverage_artifact_exists=false" >> $GITHUB_ENV + fi + + - name: Extract target branch frontend coverage data + if: ${{ env.target_branch_frontend_coverage_artifact_exists == 'true' }} + shell: pwsh + run: | + [xml]$xml = Get-Content target_branch_frontend_coverage.xml + $metrics = $xml.coverage.project.metrics + + $statements = [double]$metrics.statements + $coveredstatements = [double]$metrics.coveredstatements + $conditionals = [double]$metrics.conditionals + $coveredconditionals = [double]$metrics.coveredconditionals + $methods = [double]$metrics.methods + $coveredmethods = [double]$metrics.coveredmethods + $elements = [double]$metrics.elements + $coveredelements = [double]$metrics.coveredelements + + $statement_coverage = 0.0 + $conditional_coverage = 0.0 + $method_coverage = 0.0 + $element_coverage = 0.0 + + if ($statements -gt 0) { + $statement_coverage = ($coveredstatements / $statements) * 100 + } + if ($conditionals -gt 0) { + $conditional_coverage = ($coveredconditionals / $conditionals) * 100 + } + if ($methods -gt 0) { + $method_coverage = ($coveredmethods / $methods) * 100 + } + if ($elements -gt 0) { + $element_coverage = ($coveredelements / $elements) * 100 + } + + $nonZeroCount = 0 + $totalCoverage = 0.0 + + if ($statements -gt 0) { $nonZeroCount++; $totalCoverage += $statement_coverage } + if ($conditionals -gt 0) { $nonZeroCount++; $totalCoverage += $conditional_coverage } + if ($methods -gt 0) { $nonZeroCount++; $totalCoverage += $method_coverage } + if ($elements -gt 0) { $nonZeroCount++; $totalCoverage += $element_coverage } + + $target_branch_frontend_coverage = 0.0 + if ($nonZeroCount -gt 0) { + $target_branch_frontend_coverage = $totalCoverage / $nonZeroCount + } + + Write-Output "target_branch_frontend_coverage=$target_branch_frontend_coverage" | Out-File -Append $env:GITHUB_ENV + + - name: Compare frontend feature coverage with target coverage + if: github.event_name == 'pull_request' + run: | + feature_branch_frontend_coverage=${feature_branch_frontend_coverage} + target_branch_frontend_coverage=${target_branch_frontend_coverage:-0.0} + + # Compare feature coverage with target coverage using floating-point comparison + if awk -v feature="$feature_branch_frontend_coverage" -v target="$target_branch_frontend_coverage" 'BEGIN { exit (feature < target) ? 0 : 1 }'; then + echo "Coverage decreased from $target_branch_frontend_coverage% to $feature_branch_frontend_coverage%. Please add or update tests to increase coverage." + exit 1 + else + echo "Feature branch coverage ($feature_branch_frontend_coverage%) >= Target branch coverage ($target_branch_frontend_coverage%)." + fi + + check_python_coverage: + runs-on: ubuntu-latest + needs: [build_feature_branch, build_target_branch] + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' # Use the latest available version + check-latest: true + + - name: Download feature branch Python coverage report artifact + uses: actions/download-artifact@v4 + with: + name: feature-branch-python-coverage-report + path: . + + - name: Download target branch Python coverage report artifact + uses: actions/download-artifact@v4 + with: + name: target-branch-python-coverage-report + path: . + + - name: Compare Python feature coverage with target coverage + if: github.event_name == 'pull_request' + run: | + feature_branch_python_coverage=$(cat feature_branch_python_coverage.json | grep -o '"totals": {[^}]*' | grep -o '"percent_covered": [0-9.]*' | awk -F ': ' '{print $2}') + target_branch_python_coverage=$(cat target_branch_python_coverage.json | grep -o '"totals": {[^}]*' | grep -o '"percent_covered": [0-9.]*' | awk -F ': ' '{print $2}') + + # Compare feature coverage with target coverage using floating-point comparison + if awk -v feature="$feature_branch_python_coverage" -v target="$target_branch_python_coverage" 'BEGIN { exit (feature < target) ? 0 : 1 }'; then + echo "Coverage decreased from $target_branch_python_coverage% to $feature_branch_python_coverage%. Please add or update tests to increase coverage." + exit 1 + else + echo "Feature branch coverage ($feature_branch_python_coverage%) >= Target branch coverage ($target_branch_python_coverage%)." + fi \ No newline at end of file diff --git a/.gitignore b/.gitignore index 82f9275..c4cf08f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,162 +1,19 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: +*.pyc *.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/latest/usage/project/#working-with-version-control -.pdm.toml -.pdm-python -.pdm-build/ - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +node_modules +coverage/ +arches_vue_utils/logs +arches_vue_utils/export_deliverables +arches_vue_utils/cantaloupe/* +arches_vue_utils/staticfiles +arches_vue_utils/media/packages +arches_vue_utils/media/build/ +arches_vue_utils/uploadedfiles/* +arches_vue_utils/settings_local.py +webpack-stats.json +.vscode/ +*.egg-info +.DS_STORE +CACHE +.tsconfig-paths.json +.frontend-configuration-settings.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..7b9d4ad --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +--- +repos: + + - repo: meta + hooks: + - id: check-hooks-apply + + - repo: https://github.com/psf/black + rev: 24.4.2 + hooks: + - id: black + args: [--quiet] + exclude: node_modules + + - repo: local + hooks: + - id: prettier + name: prettier + entry: npm run prettier:fix + language: system + files: arches_vue_utils/src + - id: eslint + name: eslint + entry: npm run eslint:fix + language: system + files: arches_vue_utils/src + - id: typescript + name: typescript + entry: bash -c 'npm run ts:check' + language: system + types_or: [ + "ts", + "vue", + ] diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3baef1c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleAttributePerLine": true, + "tabWidth": 4 +} diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..40db42c --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "stylelint-config-standard" +} diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..c210332 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +graft * diff --git a/README.md b/README.txt similarity index 100% rename from README.md rename to README.txt diff --git a/arches_vue_utils/__init__.py b/arches_vue_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/apps.py b/arches_vue_utils/apps.py new file mode 100644 index 0000000..772c579 --- /dev/null +++ b/arches_vue_utils/apps.py @@ -0,0 +1,13 @@ +from django.apps import AppConfig +from django.conf import settings + +from arches.settings_utils import generate_frontend_configuration + + +class ArchesVueUtilsConfig(AppConfig): + name = "arches_vue_utils" + is_arches_application = True + + def ready(self): + if settings.APP_NAME.lower() == self.name: + generate_frontend_configuration() diff --git a/arches_vue_utils/celery.py b/arches_vue_utils/celery.py new file mode 100644 index 0000000..c0cb831 --- /dev/null +++ b/arches_vue_utils/celery.py @@ -0,0 +1,13 @@ +from __future__ import absolute_import, unicode_literals +import os +from celery import Celery + +import platform + +if platform.system().lower() == "windows": + os.environ.setdefault("FORKED_BY_MULTIPROCESSING", "1") + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "arches_vue_utils.settings") +app = Celery("arches_vue_utils") +app.config_from_object("django.conf:settings", namespace="CELERY") +app.autodiscover_tasks() diff --git a/arches_vue_utils/datatypes/__init__.py b/arches_vue_utils/datatypes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/functions/__init__.py b/arches_vue_utils/functions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/hosts.py b/arches_vue_utils/hosts.py new file mode 100644 index 0000000..9d948de --- /dev/null +++ b/arches_vue_utils/hosts.py @@ -0,0 +1,11 @@ +import re +from django_hosts import patterns, host + +host_patterns = patterns( + "", + host( + re.sub(r"_", r"-", r"arches_vue_utils"), + "arches_vue_utils.urls", + name="arches_vue_utils", + ), +) diff --git a/arches_vue_utils/locale/.gitkeep b/arches_vue_utils/locale/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/management/__init__.py b/arches_vue_utils/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/management/commands/__init__.py b/arches_vue_utils/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/media/css/themes/_project.scss b/arches_vue_utils/media/css/themes/_project.scss new file mode 100644 index 0000000..c4e26c3 --- /dev/null +++ b/arches_vue_utils/media/css/themes/_project.scss @@ -0,0 +1,6 @@ +// use this file to override specific colors in the application +// see https://github.com/archesproject/arches/tree/master/arches/app/media/css/themes/_default.scss +// in the arches repo for the colors that can be overridden +// +// eg: +// $link-color: red; diff --git a/arches_vue_utils/media/img/favicon.png b/arches_vue_utils/media/img/favicon.png new file mode 100644 index 0000000..652c785 Binary files /dev/null and b/arches_vue_utils/media/img/favicon.png differ diff --git a/arches_vue_utils/media/js/reports/default.js b/arches_vue_utils/media/js/reports/default.js new file mode 100644 index 0000000..f130b77 --- /dev/null +++ b/arches_vue_utils/media/js/reports/default.js @@ -0,0 +1,14 @@ +define([ + 'knockout', + 'viewmodels/report', + 'templates/views/report-templates/default.htm' +], function(ko, ReportViewModel, defaultReportTemplate) { + return ko.components.register('default-report', { + viewModel: function(params) { + params.configKeys = []; + + ReportViewModel.apply(this, [params]); + }, + template: defaultReportTemplate + }); +}); diff --git a/arches_vue_utils/search_components/__init__.py b/arches_vue_utils/search_components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/search_indexes/__init__.py b/arches_vue_utils/search_indexes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/search_indexes/sample_index.py b/arches_vue_utils/search_indexes/sample_index.py new file mode 100644 index 0000000..cd9c1e8 --- /dev/null +++ b/arches_vue_utils/search_indexes/sample_index.py @@ -0,0 +1,20 @@ +from arches.app.search.base_index import BaseIndex + + +class SampleIndex(BaseIndex): + def prepare_index(self): + self.index_metadata = { + "mappings": { + "properties": { + "tile_count": {"type": "keyword"}, + "graph_id": {"type": "keyword"}, + } + } + } + super(SampleIndex, self).prepare_index() + + def get_documents_to_index(self, resourceinstance, tiles): + return ( + {"tile_count": len(tiles), "graph_id": resourceinstance.graph_id}, + str(resourceinstance.resourceinstanceid), + ) diff --git a/arches_vue_utils/settings.py b/arches_vue_utils/settings.py new file mode 100644 index 0000000..3ee19b8 --- /dev/null +++ b/arches_vue_utils/settings.py @@ -0,0 +1,435 @@ +""" +Django settings for arches_vue_utils project. +""" + +import os +import inspect +import semantic_version +from datetime import datetime, timedelta +from django.utils.translation import gettext_lazy as _ + +try: + from arches.settings import * +except ImportError: + pass + +APP_NAME = "arches_vue_utils" +APP_VERSION = semantic_version.Version(major=0, minor=0, patch=0) +APP_ROOT = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) + +WEBPACK_LOADER = { + "DEFAULT": { + "STATS_FILE": os.path.join(APP_ROOT, "..", "webpack/webpack-stats.json"), + }, +} + +DATATYPE_LOCATIONS.append("arches_vue_utils.datatypes") +FUNCTION_LOCATIONS.append("arches_vue_utils.functions") +ETL_MODULE_LOCATIONS.append("arches_vue_utils.etl_modules") +SEARCH_COMPONENT_LOCATIONS.append("arches_vue_utils.search_components") + +LOCALE_PATHS.insert(0, os.path.join(APP_ROOT, "locale")) + +FILE_TYPE_CHECKING = "lenient" +FILE_TYPES = [ + "bmp", + "gif", + "jpg", + "jpeg", + "json", + "pdf", + "png", + "psd", + "rtf", + "tif", + "tiff", + "xlsx", + "csv", + "zip", +] +FILENAME_GENERATOR = "arches.app.utils.storage_filename_generator.generate_filename" +UPLOADED_FILES_DIR = "uploadedfiles" + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-ak-a8(i7%dh=0(t5wr#knc0a_z=vjdbg*k5)v5gx_nd^ajgx)l" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ROOT_URLCONF = "arches_vue_utils.urls" +ROOT_HOSTCONF = "arches_vue_utils.hosts" + +DEFAULT_HOST = "arches_vue_utils" + +# Modify this line as needed for your project to connect to elasticsearch with a password that you generate +ELASTICSEARCH_CONNECTION_OPTIONS = { + "request_timeout": 30, + "verify_certs": False, + "basic_auth": ("elastic", "E1asticSearchforArche5"), +} + +# If you need to connect to Elasticsearch via an API key instead of username/password, use the syntax below: +# ELASTICSEARCH_CONNECTION_OPTIONS = {"request_timeout": 30, "verify_certs": False, "api_key": ""} +# ELASTICSEARCH_CONNECTION_OPTIONS = {"request_timeout": 30, "verify_certs": False, "api_key": ("", "")} + +# Your Elasticsearch instance needs to be configured with xpack.security.enabled=true to use API keys - update elasticsearch.yml or .env file and restart. + +# Set the ELASTIC_PASSWORD environment variable in either the docker-compose.yml or .env file to the password you set for the elastic user, +# otherwise a random password will be generated. + +# API keys can be generated via the Elasticsearch API: https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html +# Or Kibana: https://www.elastic.co/guide/en/kibana/current/api-keys.html + +# a prefix to append to all elasticsearch indexes, note: must be lower case +ELASTICSEARCH_PREFIX = "arches_vue_utils" + +ELASTICSEARCH_CUSTOM_INDEXES = [] +# [{ +# 'module': 'arches_vue_utils.search_indexes.sample_index.SampleIndex', +# 'name': 'my_new_custom_index', <-- follow ES index naming rules +# 'should_update_asynchronously': False <-- denotes if asynchronously updating the index would affect custom functionality within the project. +# }] + +KIBANA_URL = "http://localhost:5601/" +KIBANA_CONFIG_BASEPATH = "kibana" # must match Kibana config.yml setting (server.basePath) but without the leading slash, +# also make sure to set server.rewriteBasePath: true + +LOAD_DEFAULT_ONTOLOGY = False +LOAD_PACKAGE_ONTOLOGIES = True + +# This is the namespace to use for export of data (for RDF/XML for example) +# It must point to the url where you host your site +# Make sure to use a trailing slash +ARCHES_NAMESPACE_FOR_DATA_EXPORT = "http://localhost:8000/" + +DATABASES = { + "default": { + "ATOMIC_REQUESTS": False, + "AUTOCOMMIT": True, + "CONN_MAX_AGE": 0, + "ENGINE": "django.contrib.gis.db.backends.postgis", + "HOST": "localhost", + "NAME": "arches_vue_utils", + "OPTIONS": {}, + "PASSWORD": "postgis", + "PORT": "5432", + "POSTGIS_TEMPLATE": "template_postgis", + "TEST": {"CHARSET": None, "COLLATION": None, "MIRROR": None, "NAME": None}, + "TIME_ZONE": None, + "USER": "postgres", + } +} + +SEARCH_THUMBNAILS = False + +INSTALLED_APPS = ( + "webpack_loader", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.gis", + "django_hosts", + "arches", + "arches.app.models", + "arches.management", + "guardian", + "captcha", + "revproxy", + "corsheaders", + "oauth2_provider", + "django_celery_results", + # "silk", + "arches_vue_utils", # Ensure the project is listed before any other arches applications +) + +# Placing this last ensures any templates provided by Arches Applications +# take precedence over core arches templates in arches/app/templates. +INSTALLED_APPS += ("arches.app",) + +MIDDLEWARE = [ + "corsheaders.middleware.CorsMiddleware", + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + #'arches.app.utils.middleware.TokenMiddleware', + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "arches.app.utils.middleware.ModifyAuthorizationHeader", + "oauth2_provider.middleware.OAuth2TokenMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "arches.app.utils.middleware.SetAnonymousUser", + # "silk.middleware.SilkyMiddleware", +] + +MIDDLEWARE.insert( # this must resolve to first MIDDLEWARE entry + 0, "django_hosts.middleware.HostsRequestMiddleware" +) + +MIDDLEWARE.append( # this must resolve last MIDDLEWARE entry + "django_hosts.middleware.HostsResponseMiddleware" +) + +STATICFILES_DIRS = build_staticfiles_dirs(app_root=APP_ROOT) + +TEMPLATES = build_templates_config( + debug=DEBUG, + app_root=APP_ROOT, +) + +ALLOWED_HOSTS = [] + +SYSTEM_SETTINGS_LOCAL_PATH = os.path.join( + APP_ROOT, "system_settings", "System_Settings.json" +) +WSGI_APPLICATION = "arches_vue_utils.wsgi.application" + +# URL that handles the media served from MEDIA_ROOT, used for managing stored files. +# It must end in a slash if set to a non-empty value. +MEDIA_URL = "/files/" + +# Absolute filesystem path to the directory that will hold user-uploaded files. +MEDIA_ROOT = os.path.join(APP_ROOT) + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = "/static/" + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = os.path.join(APP_ROOT, "staticfiles") + +# when hosting Arches under a sub path set this value to the sub path eg : "/{sub_path}/" +FORCE_SCRIPT_NAME = None + +RESOURCE_IMPORT_LOG = os.path.join(APP_ROOT, "logs", "resource_import.log") +DEFAULT_RESOURCE_IMPORT_USER = {"username": "admin", "userid": 1} + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "console": { + "format": "%(asctime)s %(name)-12s %(levelname)-8s %(message)s", + }, + }, + "handlers": { + "file": { + "level": "WARNING", # DEBUG, INFO, WARNING, ERROR + "class": "logging.FileHandler", + "filename": os.path.join(APP_ROOT, "arches.log"), + "formatter": "console", + }, + "console": { + "level": "WARNING", + "class": "logging.StreamHandler", + "formatter": "console", + }, + }, + "loggers": { + "arches": { + "handlers": ["file", "console"], + "level": "WARNING", + "propagate": True, + } + }, +} + +# Rate limit for authentication views +# See options (including None or python callables): +# https://django-ratelimit.readthedocs.io/en/stable/rates.html#rates-chapter +RATE_LIMIT = "5/m" + +# Sets default max upload size to 15MB +DATA_UPLOAD_MAX_MEMORY_SIZE = 15728640 + +# Unique session cookie ensures that logins are treated separately for each app +SESSION_COOKIE_NAME = "arches_vue_utils" + +# For more info on configuring your cache: https://docs.djangoproject.com/en/2.2/topics/cache/ +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.dummy.DummyCache", + }, + "user_permission": { + "BACKEND": "django.core.cache.backends.db.DatabaseCache", + "LOCATION": "user_permission_cache", + }, +} + +# Hide nodes and cards in a report that have no data +HIDE_EMPTY_NODES_IN_REPORT = False + +BYPASS_UNIQUE_CONSTRAINT_TILE_VALIDATION = False +BYPASS_REQUIRED_VALUE_TILE_VALIDATION = False + +DATE_IMPORT_EXPORT_FORMAT = ( + "%Y-%m-%d" # Custom date format for dates imported from and exported to csv +) + +# This is used to indicate whether the data in the CSV and SHP exports should be +# ordered as seen in the resource cards or not. +EXPORT_DATA_FIELDS_IN_CARD_ORDER = False + +# Identify the usernames and duration (seconds) for which you want to cache the time wheel +CACHE_BY_USER = {"default": 3600 * 24, "anonymous": 3600 * 24} # 24hrs # 24hrs + +TILE_CACHE_TIMEOUT = 600 # seconds +CLUSTER_DISTANCE_MAX = 5000 # meters +GRAPH_MODEL_CACHE_TIMEOUT = None + +OAUTH_CLIENT_ID = "" #'9JCibwrWQ4hwuGn5fu2u1oRZSs9V6gK8Vu8hpRC4' + +APP_TITLE = "Arches | Heritage Data Management" +COPYRIGHT_TEXT = "All Rights Reserved." +COPYRIGHT_YEAR = "2019" + +ENABLE_CAPTCHA = False +# RECAPTCHA_PUBLIC_KEY = '' +# RECAPTCHA_PRIVATE_KEY = '' +# RECAPTCHA_USE_SSL = False +NOCAPTCHA = True +# RECAPTCHA_PROXY = 'http://127.0.0.1:8000' + +# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' #<-- Only need to uncomment this for testing without an actual email server +# EMAIL_USE_TLS = True +# EMAIL_HOST = 'smtp.gmail.com' +EMAIL_HOST_USER = "xxxx@xxx.com" +# EMAIL_HOST_PASSWORD = 'xxxxxxx' +# EMAIL_PORT = 587 + +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER + +CELERY_BROKER_URL = "" # RabbitMQ --> "amqp://guest:guest@localhost", Redis --> "redis://localhost:6379/0" +CELERY_ACCEPT_CONTENT = ["json"] +CELERY_RESULT_BACKEND = ( + "django-db" # Use 'django-cache' if you want to use your cache as your backend +) +CELERY_TASK_SERIALIZER = "json" + + +CELERY_SEARCH_EXPORT_EXPIRES = 24 * 3600 # seconds +CELERY_SEARCH_EXPORT_CHECK = 3600 # seconds + +CELERY_BEAT_SCHEDULE = { + "delete-expired-search-export": { + "task": "arches.app.tasks.delete_file", + "schedule": CELERY_SEARCH_EXPORT_CHECK, + }, + "notification": { + "task": "arches.app.tasks.message", + "schedule": CELERY_SEARCH_EXPORT_CHECK, + "args": ("Celery Beat is Running",), + }, +} + +# Set to True if you want to send celery tasks to the broker without being able to detect celery. +# This might be necessary if the worker pool is regulary fully active, with no idle workers, or if +# you need to run the celery task using solo pool (e.g. on Windows). You may need to provide another +# way of monitoring celery so you can detect the background task not being available. +CELERY_CHECK_ONLY_INSPECT_BROKER = False + +CANTALOUPE_DIR = os.path.join(ROOT_DIR, UPLOADED_FILES_DIR) +CANTALOUPE_HTTP_ENDPOINT = "http://localhost:8182/" + +ACCESSIBILITY_MODE = False + +RENDERERS = [ + { + "name": "imagereader", + "title": "Image Reader", + "description": "Displays most image file types", + "id": "5e05aa2e-5db0-4922-8938-b4d2b7919733", + "iconclass": "fa fa-camera", + "component": "views/components/cards/file-renderers/imagereader", + "ext": "", + "type": "image/*", + "exclude": "tif,tiff,psd", + }, + { + "name": "pdfreader", + "title": "PDF Reader", + "description": "Displays pdf files", + "id": "09dec059-1ee8-4fbd-85dd-c0ab0428aa94", + "iconclass": "fa fa-file", + "component": "views/components/cards/file-renderers/pdfreader", + "ext": "pdf", + "type": "application/pdf", + "exclude": "tif,tiff,psd", + }, +] + +# By setting RESTRICT_MEDIA_ACCESS to True, media file requests outside of Arches will checked against nodegroup permissions. +RESTRICT_MEDIA_ACCESS = False + +# By setting RESTRICT_CELERY_EXPORT_FOR_ANONYMOUS_USER to True, if the user is attempting +# to export search results above the SEARCH_EXPORT_IMMEDIATE_DOWNLOAD_THRESHOLD +# value and is not signed in with a user account then the request will not be allowed. +RESTRICT_CELERY_EXPORT_FOR_ANONYMOUS_USER = False + +# Dictionary containing any additional context items for customising email templates +EXTRA_EMAIL_CONTEXT = { + "salutation": _("Hi"), + "expiration": ( + datetime.now() + timedelta(seconds=CELERY_SEARCH_EXPORT_EXPIRES) + ).strftime("%A, %d %B %Y"), +} + +# see https://docs.djangoproject.com/en/1.9/topics/i18n/translation/#how-django-discovers-language-preference +# to see how LocaleMiddleware tries to determine the user's language preference +# (make sure to check your accept headers as they will override the LANGUAGE_CODE setting!) +# also see get_language_from_request in django.utils.translation.trans_real.py +# to see how the language code is derived in the actual code + +####### TO GENERATE .PO FILES DO THE FOLLOWING ######## +# run the following commands +# language codes used in the command should be in the form (which is slightly different +# form the form used in the LANGUAGE_CODE and LANGUAGES settings below): +# --local={countrycode}_{REGIONCODE} <-- countrycode is lowercase, regioncode is uppercase, also notice the underscore instead of hyphen +# commands to run (to generate files for "British English, German, and Spanish"): +# django-admin.py makemessages --ignore=env/* --local=de --local=en --local=en_GB --local=es --extension=htm,py +# django-admin.py compilemessages + + +# default language of the application +# language code needs to be all lower case with the form: +# {langcode}-{regioncode} eg: en, en-gb .... +# a list of language codes can be found here http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = "en" + +# list of languages to display in the language switcher, +# if left empty or with a single entry then the switch won't be displayed +# language codes need to be all lower case with the form: +# {langcode}-{regioncode} eg: en, en-gb .... +# a list of language codes can be found here http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGES = [ + # ('de', _('German')), + ("en", _("English")), + # ('en-gb', _('British English')), + # ('es', _('Spanish')), +] + +# override this to permenantly display/hide the language switcher +SHOW_LANGUAGE_SWITCH = len(LANGUAGES) > 1 + +try: + from .package_settings import * +except ImportError: + try: + from package_settings import * + except ImportError as e: + pass + +try: + from .settings_local import * +except ImportError as e: + try: + from settings_local import * + except ImportError as e: + pass diff --git a/arches_vue_utils/src/arches_vue_utils/declarations.d.ts b/arches_vue_utils/src/arches_vue_utils/declarations.d.ts new file mode 100644 index 0000000..6e9a067 --- /dev/null +++ b/arches_vue_utils/src/arches_vue_utils/declarations.d.ts @@ -0,0 +1,4 @@ +// declare untyped modules that have been added to your project in `package.json` +// Module homepage on npmjs.com uses logos "TS" or "DT" to indicate if typed + +import("@/arches/declarations.d.ts"); diff --git a/arches_vue_utils/src/arches_vue_utils/declarations.test.ts b/arches_vue_utils/src/arches_vue_utils/declarations.test.ts new file mode 100644 index 0000000..d351a7d --- /dev/null +++ b/arches_vue_utils/src/arches_vue_utils/declarations.test.ts @@ -0,0 +1 @@ +// empty test file to register coverage of `declarations.d.ts` diff --git a/arches_vue_utils/system_settings/readme.txt b/arches_vue_utils/system_settings/readme.txt new file mode 100644 index 0000000..eb9b884 --- /dev/null +++ b/arches_vue_utils/system_settings/readme.txt @@ -0,0 +1,8 @@ +This directory is used as the default directory for loading package system +settings data. This is also the default directory that will be used when exporting +system settings. Do not edit settings in this directory unless you are doing so for +development purposes. Instead, use the system settings manager in the Arches UI. +If you want to export your system settings from Arches, you can do so with the +following command: + +> python manage.py packages -o save_system_settings diff --git a/arches_vue_utils/templates/custom_email_css.htm b/arches_vue_utils/templates/custom_email_css.htm new file mode 100644 index 0000000..29f2b95 --- /dev/null +++ b/arches_vue_utils/templates/custom_email_css.htm @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/arches_vue_utils/templates/custom_email_footer.htm b/arches_vue_utils/templates/custom_email_footer.htm new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/templates/custom_email_header.htm b/arches_vue_utils/templates/custom_email_header.htm new file mode 100644 index 0000000..e69de29 diff --git a/arches_vue_utils/templates/email/download_ready_email_notification.htm b/arches_vue_utils/templates/email/download_ready_email_notification.htm new file mode 100644 index 0000000..afb54ea --- /dev/null +++ b/arches_vue_utils/templates/email/download_ready_email_notification.htm @@ -0,0 +1,35 @@ + + + + + {% include 'custom_email_css.htm' %} + + + + {% include 'custom_email_header.htm' %} + +

{{greeting}}

+ {% if files %} + +
+ + + +
+ + + {% endif %} + + {% if link != "" %} + + {% endif %} + +

{{closing}}

+ + {% include 'custom_email_footer.htm' %} + + + \ No newline at end of file diff --git a/arches_vue_utils/templates/email/general_notification.htm b/arches_vue_utils/templates/email/general_notification.htm new file mode 100644 index 0000000..e307760 --- /dev/null +++ b/arches_vue_utils/templates/email/general_notification.htm @@ -0,0 +1,56 @@ + + + + + + {% include 'custom_email_css.htm' %} + + + + + {% include 'custom_email_header.htm' %} + + {% if username != "" %} +

{{salutation}} {{username}},

+ {% endif %} +

+ {{greeting}} +

+ {% if link != "" %} +

{{button_text}}

+ {% endif %} + + {% include 'custom_email_footer.htm' %} + + + + \ No newline at end of file diff --git a/arches_vue_utils/templates/email/package_load_complete_email_notification.htm b/arches_vue_utils/templates/email/package_load_complete_email_notification.htm new file mode 100644 index 0000000..0632ade --- /dev/null +++ b/arches_vue_utils/templates/email/package_load_complete_email_notification.htm @@ -0,0 +1,31 @@ + + + + + {% include 'custom_email_css.htm' %} + + + + {% include 'custom_email_header.htm' %} + + {% if username != "" %} +

+ {{salutation}} {{username}}, +

+ {% endif %} +

+ {{greeting}} +

+ {% if link != "" %} +

+ + {{link_text}} + +

+ {% endif %} + + {% include 'custom_email_footer.htm' %} + + + + \ No newline at end of file diff --git a/arches_vue_utils/templates/html_export/example-000000-0000-0000-0000-0000001.htm b/arches_vue_utils/templates/html_export/example-000000-0000-0000-0000-0000001.htm new file mode 100644 index 0000000..9ee759b --- /dev/null +++ b/arches_vue_utils/templates/html_export/example-000000-0000-0000-0000-0000001.htm @@ -0,0 +1,90 @@ +{% load template_tags %} + + + + + + + Report + +
+

Heritage Assets

+
+
+ {% for resource in resources %} + {% with resource_data=resource_data %} +
+
+

{{ resource.displayname }}

+
+
+
+
+

Description

+
+

+ {{ resource.displayname }} +

+ + {% comment "Example of adding a description from an array of Description cards based on the type" %} + + {% if resource_data|has_key:"Descriptions" %} +
+ {% for desc in resource_data|val_from_key:"Descriptions" %} + {% if desc|val_from_key:"Description Type"|val_from_key:"@value" == "Summary" %} +

Summary

+

{{ desc|val_from_key:"Description" }}

+ {% endif %} + {% endfor %} + {% for desc in resource_data|val_from_key:"Descriptions" %} + {% if desc|val_from_key:"Description Type"|val_from_key:"@value" == "Full" %} +

Full

+

{{ desc|val_from_key:"Description" }}

+ {% endif %} + {% endfor %} +
+ {% endif %} + + {% endcomment %} + + {% comment "Example of creating a responsive table from a list of card values" %} + + {% if resource_data|has_key:"External Cross References" %} +
+

External Cross References

+
+
+
Number
+
Description
+
Source
+
+ {% for src in resource_data|val_from_key:"External Cross References" %} +
+
{{ src|val_from_key:"External Cross Reference Number" }}
+
+ {% if src|has_key:"External Cross Reference Notes" %} + {{ src|val_from_key:"External Cross Reference Notes"|val_from_key:"External Cross Reference Description" }} + {% endif %} +
+
{{ src|val_from_key:"External Cross Reference Source" }}
+
+ {% endfor %} +
+
+ {% endif %} + + {% endcomment %} +
+
+ {% endwith%} + {% endfor %} +
+ + \ No newline at end of file diff --git a/arches_vue_utils/templates/index.htm b/arches_vue_utils/templates/index.htm new file mode 100644 index 0000000..94ab102 --- /dev/null +++ b/arches_vue_utils/templates/index.htm @@ -0,0 +1,547 @@ + +{% load static %} +{% load template_tags %} +{% load i18n %} +{% load render_bundle from webpack_loader %} +{% load webpack_static from webpack_loader %} + + + + + + + + + + {{app_title}} + + + + + + + + + + + + + + + {% block css %} + + + + + + {% render_bundle 'css/index' 'css' %} + {% render_bundle 'css/index-slider' 'css' %} + + {% if app_settings.ACCESSIBILITY_MODE %} + {% render_bundle 'css/accessibility' 'css' %} + {% endif %} + {% endblock css%} + + + + + {% include 'javascript.htm' %} + + +
+ +
+ + +
+
+ +
+ + + + +
+
+ +
+

{% blocktrans %}Arches {{version}}{% endblocktrans %}

+

{% trans "A web and mobile platform for" %}

+

{% trans "managing your most important resource information" %}

+
+
{% trans "Image courtesy of Luis Alfonso Orellana" %}
+
+
+ +
+

{% blocktrans %}Arches {{version}}{% endblocktrans %}

+

{% trans "A web and mobile platform for" %}

+

{% trans "managing your most important resource information" %}

+
+
{% trans "Taktsang Palphug Monastery (also known as Paro Takstang or Tiger's Nest Monastery), Bhutan" %}
+
+
+ +
+

{% blocktrans %}Arches {{version}}{% endblocktrans %}

+

{% trans "A web and mobile platform for" %}

+

{% trans "managing your most important resource information" %}

+
+
{% trans "Potala Palace in Lhasa, Tibet" %}
+
+
+ + + + + +
+ + + +
+
+ + +
+
+
+

{% trans "Fast" %}

+

{% trans "Deploy Applications Rapidly" %}

+

+ {% trans "Design custom information management applications in hours. Build your databases with Arches Designer, then configure your interface all without having to write any code." %} +

+
+
+
+ + +
+ {% trans 'Arches Designer' %} +
+ + +
+ + +
+
+

{% trans "Interface Manager" %}

+

+ {% trans "Arches automatically creates data entry forms based on your data models. Use Arches' Card Manager to configure the look and feel of your data entry UI." %} +

+ {% trans 'Card Manager' %} +
+
+ + +
+
+

{% trans "Data Security" %}

+

+ {% trans "Use Arches' Permissions Manager to set up data access rules for all your user groups and individual accounts. You can define read/write/delete and no-access permissions." %} +

+ {% trans 'Permissions Manager' %} +
+
+ +
+ + +
+
+ + + +
+
+ + +
+
+
+

{% trans "Workflows" %}

+

{% trans "Orchestrate your data entry" %}

+

+ {% trans "Design step-wise data management interfaces that simplify complex editing tasks. Ensure that everyone enters data completely and consistently" %} +

+
+
+
+ + +
+ {% trans 'Arches Workflows' %} +
+ +
+
+ + + +
+
+ + +
+
+
+

{% trans "Arches Search Tools" %}

+

{% trans "Find what you're looking for" %}

+

+ {% trans "Arches comes with powerful built-in search tools. Quickly filter large databases with term, geospatial, and time-based search components" %} +

+
+
+
+ +
+ {% trans 'Arches Search' %} +
+ + +
+
+

{% trans "Search Options" %}

+

+ {% trans "Arches gives you many ways to find precisely the information you need, even if your Arches application contains 10's of millions of records. In addition to term, thesaurus, geospatial, and temporal filters, Arches provides you with advanced filtering options that support boolean logic, inverses, and many other filtering options." %} +

+
+

+ {% trans "Arches' search capabilities also provide for sophisticated data visualizations, including interactive displays of the connections between your data objects using a Force Directed Graph." %} +

+
+

+ {% trans "If you're a software developer, you can build on Arches modular search services and create your own filters, reports, and visualizations to best show off your particular dataset." %} +

+ +
+
+ +
+
+ +
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/arches_vue_utils/templates/registration/password_reset_subject.txt b/arches_vue_utils/templates/registration/password_reset_subject.txt new file mode 100644 index 0000000..47ce34c --- /dev/null +++ b/arches_vue_utils/templates/registration/password_reset_subject.txt @@ -0,0 +1 @@ +Password reset for \ No newline at end of file diff --git a/arches_vue_utils/urls.py b/arches_vue_utils/urls.py new file mode 100644 index 0000000..4f9c69b --- /dev/null +++ b/arches_vue_utils/urls.py @@ -0,0 +1,22 @@ +from django.conf import settings +from django.conf.urls.static import static +from django.conf.urls.i18n import i18n_patterns +from django.urls import include, path + +urlpatterns = [ + # project-level urls +] + +# Ensure Arches core urls are superseded by project-level urls +urlpatterns.append(path("", include("arches.urls"))) + +# Adds URL pattern to serve media files during development +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + +# Only handle i18n routing in active project. This will still handle the routes provided by Arches core and Arches applications, +# but handling i18n routes in multiple places causes application errors. +if settings.ROOT_URLCONF == __name__: + if settings.SHOW_LANGUAGE_SWITCH is True: + urlpatterns = i18n_patterns(*urlpatterns) + + urlpatterns.append(path("i18n/", include("django.conf.urls.i18n"))) diff --git a/arches_vue_utils/wsgi.py b/arches_vue_utils/wsgi.py new file mode 100644 index 0000000..083c4fc --- /dev/null +++ b/arches_vue_utils/wsgi.py @@ -0,0 +1,39 @@ +""" +ARCHES - a program developed to inventory and manage immovable cultural heritage. +Copyright (C) 2013 J. Paul Getty Trust and World Monuments Fund + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +""" + +import os +import sys +import inspect + +path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) + +if path not in sys.path: + sys.path.append(path) + +# reverting back to the old style of setting the DJANGO_SETTINGS_MODULE env variable +# refer to the following blog post under the heading "Leaking of process environment variables." +# http://blog.dscpl.com.au/2012/10/requests-running-in-wrong-django.html +os.environ["DJANGO_SETTINGS_MODULE"] = "arches_vue_utils.settings" + +from django.core.wsgi import get_wsgi_application + +application = get_wsgi_application() + +from arches.app.models.system_settings import settings + +settings.update_from_db() diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..ab51240 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,43 @@ + +import js from "@eslint/js"; +import pluginVue from 'eslint-plugin-vue'; +import tseslint from 'typescript-eslint'; +import eslintConfigPrettier from "eslint-config-prettier"; + +import vueESLintParser from 'vue-eslint-parser'; + +export default [ + js.configs.recommended, + ...pluginVue.configs['flat/recommended'], + ...tseslint.configs.recommended, + eslintConfigPrettier, + { + "languageOptions": { + "globals": { + "define": false, + "require": false, + "window": false, + "console": false, + "history": false, + "location": false, + "Promise": false, + "setTimeout": false, + "URL": false, + "URLSearchParams": false, + "fetch": false + }, + "parser": vueESLintParser, + "parserOptions": { + "ecmaVersion": 11, + "sourceType": "module", + "requireConfigFile": false, + "parser": { + "ts": "@typescript-eslint/parser" + } + }, + }, + "rules": { + "semi": ["error", "always"], + }, + }, +]; \ No newline at end of file diff --git a/gettext.config.js b/gettext.config.js new file mode 100644 index 0000000..bde10aa --- /dev/null +++ b/gettext.config.js @@ -0,0 +1,43 @@ + +module.exports = { + input: { + path: "./arches_vue_utils/src", // only files in this directory are considered for extraction + include: ["**/*.vue", "**/*.ts"], // glob patterns to select files for extraction + exclude: [], // glob patterns to exclude files from extraction + jsExtractorOpts: [ // custom extractor keyword. default empty. + { + keyword: "__", // only extractor default keyword such as $gettext,use keyword to custom + options: { // see https://github.com/lukasgeiter/gettext-extractor + content: { + replaceNewLines: "\n", + }, + arguments: { + text: 0, + }, + }, + }, + { + keyword: "_n", // $ngettext + options: { + content: { + replaceNewLines: "\n", + }, + arguments: { + text: 0, + textPlural: 1, + }, + }, + }, + ], + compileTemplate: false, // do not compile