mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Platform UI - React integration (#5011)
* Add SPA views for react #2789 * split up frontend urls * Add settings for frontend url loading * add new UI scaffold * remove tracking insert * add platform app * ensure static indexes work too * add lingui * add lingui config * add mgmt tasks * add base locales * settings for frontend dev * fix typo * update deps * add pre-commit * add eslint * add testing scaffold * fix paths * remove error - tests trip correctly * merge workflow * cleanup samples * use name inline with other tests * Add real worl frontend tests * setup env * tun migrations first * optimize setup time * setup demo dataset * optimize run setup * add test for class ui * rename * fix typo * and another typo * do install * run migrations first * fix name * cleanup * use other credentials * use other credentials * fix qc * move envs to qc * remove create_site * reduce testing env * fix test * fix test call * allaccess user * add ui plattform check * add better check * remove unneeded env * enable debug * reduce wait time * also build frontend on static * add sort plugin * fix order * run pre-commit fixes * add node min version * Docker container (#129) * Fix allocation check for completing build order (#5199) - Allocation check only applies to untracked line items * docker dev Install required node packages to docker development image * add import order settings * cleanout built ui * remove default arg from build * remove eslint * optimize svg * add build step for plattform UI * fix install command * use alpine commands * do not use cache when creating image --------- Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
parent
b717011f06
commit
3e37469350
@ -7,7 +7,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
|
|||||||
ARG WORKSPACE="/workspaces/InvenTree"
|
ARG WORKSPACE="/workspaces/InvenTree"
|
||||||
|
|
||||||
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
|
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
|
||||||
ARG NODE_VERSION="none"
|
ARG NODE_VERSION="18"
|
||||||
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
||||||
|
|
||||||
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
||||||
|
@ -16,6 +16,7 @@ python3 -m venv dev/venv
|
|||||||
pip install invoke
|
pip install invoke
|
||||||
invoke update
|
invoke update
|
||||||
invoke setup-dev
|
invoke setup-dev
|
||||||
|
invoke frontend-install
|
||||||
|
|
||||||
# remove existing gitconfig created by "Avoiding Dubious Ownership" step
|
# remove existing gitconfig created by "Avoiding Dubious Ownership" step
|
||||||
# so that it gets copied from host to the container to have your global
|
# so that it gets copied from host to the container to have your global
|
||||||
|
38
.github/workflows/qc_checks.yaml
vendored
38
.github/workflows/qc_checks.yaml
vendored
@ -29,6 +29,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
server: ${{ steps.filter.outputs.server }}
|
server: ${{ steps.filter.outputs.server }}
|
||||||
migrations: ${{ steps.filter.outputs.migrations }}
|
migrations: ${{ steps.filter.outputs.migrations }}
|
||||||
|
frontend: ${{ steps.filter.outputs.frontend }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # pin@v3.1.0
|
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # pin@v3.1.0
|
||||||
@ -43,6 +44,8 @@ jobs:
|
|||||||
migrations:
|
migrations:
|
||||||
- '**/migrations/**'
|
- '**/migrations/**'
|
||||||
- '.github/workflows**'
|
- '.github/workflows**'
|
||||||
|
frontend:
|
||||||
|
- 'src/frontend/**'
|
||||||
|
|
||||||
pep_style:
|
pep_style:
|
||||||
name: Style [Python]
|
name: Style [Python]
|
||||||
@ -387,3 +390,38 @@ jobs:
|
|||||||
cp test-db/stable_0.12.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
|
cp test-db/stable_0.12.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
|
||||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||||
invoke migrate
|
invoke migrate
|
||||||
|
|
||||||
|
plattform_ui:
|
||||||
|
name: Tests - UI Platform
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 60
|
||||||
|
needs: paths-filter
|
||||||
|
if: needs.paths-filter.outputs.frontend == 'true'
|
||||||
|
env:
|
||||||
|
INVENTREE_DB_ENGINE: sqlite3
|
||||||
|
INVENTREE_DB_NAME: /home/runner/work/InvenTree/db.sqlite3
|
||||||
|
INVENTREE_DEBUG: True
|
||||||
|
INVENTREE_PLUGINS_ENABLED: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # pin@v3.1.0
|
||||||
|
- name: Environment Setup
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
npm: true
|
||||||
|
install: true
|
||||||
|
update: true
|
||||||
|
- name: Set up test data
|
||||||
|
run: invoke setup-test -i
|
||||||
|
- name: Install dependencies
|
||||||
|
run: cd src/frontend && yarn install
|
||||||
|
- name: Install Playwright Browsers
|
||||||
|
run: cd src/frontend && npx playwright install --with-deps
|
||||||
|
- name: Run Playwright tests
|
||||||
|
run: cd src/frontend && npx playwright test
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: playwright-report
|
||||||
|
path: src/frontend/playwright-report/
|
||||||
|
retention-days: 30
|
||||||
|
@ -54,3 +54,23 @@ repos:
|
|||||||
docs/docs/javascripts/.*|
|
docs/docs/javascripts/.*|
|
||||||
docs/docs/webfonts/.*
|
docs/docs/webfonts/.*
|
||||||
)$
|
)$
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
|
rev: "v3.0.0-alpha.9-for-vscode"
|
||||||
|
hooks:
|
||||||
|
- id: prettier
|
||||||
|
files: ^src/frontend/.*\.(js|jsx|ts|tsx)$
|
||||||
|
additional_dependencies:
|
||||||
|
- "prettier@^2.4.1"
|
||||||
|
- "@trivago/prettier-plugin-sort-imports"
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-eslint
|
||||||
|
rev: "v8.42.0"
|
||||||
|
hooks:
|
||||||
|
- id: eslint
|
||||||
|
additional_dependencies:
|
||||||
|
- eslint@^8.41.0
|
||||||
|
- eslint-config-google@^0.14.0
|
||||||
|
- eslint-plugin-react@6.10.3
|
||||||
|
- babel-eslint@6.1.2
|
||||||
|
- "@typescript-eslint/eslint-plugin@latest"
|
||||||
|
- "@typescript-eslint/parser"
|
||||||
|
files: ^src/frontend/.*\.(js|jsx|ts|tsx)$
|
||||||
|
@ -82,10 +82,11 @@ The HEAD of the "stable" branch represents the latest stable release code.
|
|||||||
## Environment
|
## Environment
|
||||||
### Target version
|
### Target version
|
||||||
We are currently targeting:
|
We are currently targeting:
|
||||||
| Name | Minimum version |
|
| Name | Minimum version | Note |
|
||||||
|---|---|
|
|---|---| --- |
|
||||||
| Python | 3.9 |
|
| Python | 3.9 | |
|
||||||
| Django | 3.2 |
|
| Django | 3.2 | |
|
||||||
|
| Node | 18 | Only needed for frontend development |
|
||||||
|
|
||||||
### Auto creating updates
|
### Auto creating updates
|
||||||
The following tools can be used to auto-upgrade syntax that was depreciated in new versions:
|
The following tools can be used to auto-upgrade syntax that was depreciated in new versions:
|
||||||
|
13
Dockerfile
13
Dockerfile
@ -98,6 +98,15 @@ RUN chmod +x init.sh
|
|||||||
|
|
||||||
ENTRYPOINT ["/bin/sh", "./init.sh"]
|
ENTRYPOINT ["/bin/sh", "./init.sh"]
|
||||||
|
|
||||||
|
# Frontend builder image:
|
||||||
|
FROM inventree_base as frontend
|
||||||
|
|
||||||
|
RUN apk add --no-cache --update nodejs npm && npm install -g yarn
|
||||||
|
COPY InvenTree ${INVENTREE_HOME}/InvenTree
|
||||||
|
COPY src ${INVENTREE_HOME}/src
|
||||||
|
COPY tasks.py ${INVENTREE_HOME}/tasks.py
|
||||||
|
RUN cd ${INVENTREE_HOME}/InvenTree && inv frontend-compile
|
||||||
|
|
||||||
# InvenTree production image:
|
# InvenTree production image:
|
||||||
# - Copies required files from local directory
|
# - Copies required files from local directory
|
||||||
# - Starts a gunicorn webserver
|
# - Starts a gunicorn webserver
|
||||||
@ -111,6 +120,7 @@ ENV INVENTREE_COMMIT_DATE="${commit_date}"
|
|||||||
|
|
||||||
# Copy source code
|
# Copy source code
|
||||||
COPY InvenTree ./InvenTree
|
COPY InvenTree ./InvenTree
|
||||||
|
COPY --from=frontend ${INVENTREE_HOME}/InvenTree/web/static/web ./InvenTree/web/static/web
|
||||||
|
|
||||||
# Launch the production server
|
# Launch the production server
|
||||||
# TODO: Work out why environment variables cannot be interpolated in this command
|
# TODO: Work out why environment variables cannot be interpolated in this command
|
||||||
@ -120,6 +130,9 @@ CMD gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 --chdir ./Inve
|
|||||||
|
|
||||||
FROM inventree_base as dev
|
FROM inventree_base as dev
|
||||||
|
|
||||||
|
# Install nodejs / npm / yarn
|
||||||
|
RUN apk add --no-cache --update nodejs npm && npm cache clean -f && npm install -g n && n stable && npm install -g yarn
|
||||||
|
|
||||||
# The development image requires the source code to be mounted to /home/inventree/
|
# The development image requires the source code to be mounted to /home/inventree/
|
||||||
# So from here, we don't actually "do" anything, apart from some file management
|
# So from here, we don't actually "do" anything, apart from some file management
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ from . import config
|
|||||||
INVENTREE_NEWS_URL = 'https://inventree.org/news/feed.atom'
|
INVENTREE_NEWS_URL = 'https://inventree.org/news/feed.atom'
|
||||||
|
|
||||||
# Determine if we are running in "test" mode e.g. "manage.py test"
|
# Determine if we are running in "test" mode e.g. "manage.py test"
|
||||||
TESTING = 'test' in sys.argv
|
TESTING = 'test' in sys.argv or 'TESTING' in os.environ
|
||||||
|
|
||||||
if TESTING:
|
if TESTING:
|
||||||
|
|
||||||
@ -76,6 +76,9 @@ if version_file.exists():
|
|||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = get_boolean_setting('INVENTREE_DEBUG', 'debug', True)
|
DEBUG = get_boolean_setting('INVENTREE_DEBUG', 'debug', True)
|
||||||
|
|
||||||
|
ENABLE_CLASSIC_FRONTEND = get_boolean_setting('INVENTREE_CLASSIC_FRONTEND', 'classic_frontend', True)
|
||||||
|
ENABLE_PLATFORM_FRONTEND = get_boolean_setting('INVENTREE_PLATFORM_FRONTEND', 'platform_frontend', True)
|
||||||
|
|
||||||
# Configure logging settings
|
# Configure logging settings
|
||||||
log_level = get_setting('INVENTREE_LOG_LEVEL', 'log_level', 'WARNING')
|
log_level = get_setting('INVENTREE_LOG_LEVEL', 'log_level', 'WARNING')
|
||||||
|
|
||||||
@ -203,6 +206,7 @@ INSTALLED_APPS = [
|
|||||||
'stock.apps.StockConfig',
|
'stock.apps.StockConfig',
|
||||||
'users.apps.UsersConfig',
|
'users.apps.UsersConfig',
|
||||||
'plugin.apps.PluginAppConfig',
|
'plugin.apps.PluginAppConfig',
|
||||||
|
'web',
|
||||||
'generic',
|
'generic',
|
||||||
'InvenTree.apps.InvenTreeConfig', # InvenTree app runs last
|
'InvenTree.apps.InvenTreeConfig', # InvenTree app runs last
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ from report.api import report_api_urls
|
|||||||
from stock.api import stock_api_urls
|
from stock.api import stock_api_urls
|
||||||
from stock.urls import stock_urls
|
from stock.urls import stock_urls
|
||||||
from users.api import user_urls
|
from users.api import user_urls
|
||||||
|
from web.urls import urlpatterns as platform_urls
|
||||||
|
|
||||||
from .api import APISearchView, InfoView, NotFoundView
|
from .api import APISearchView, InfoView, NotFoundView
|
||||||
from .magic_login import GetSimpleLoginView
|
from .magic_login import GetSimpleLoginView
|
||||||
@ -162,7 +163,7 @@ backendpatterns = [
|
|||||||
re_path(r'^api-doc/', SpectacularRedocView.as_view(url_name='schema'), name='api-doc'),
|
re_path(r'^api-doc/', SpectacularRedocView.as_view(url_name='schema'), name='api-doc'),
|
||||||
]
|
]
|
||||||
|
|
||||||
frontendpatterns = [
|
classic_frontendpatterns = [
|
||||||
|
|
||||||
# Apps
|
# Apps
|
||||||
re_path(r'^build/', include(build_urls)),
|
re_path(r'^build/', include(build_urls)),
|
||||||
@ -205,6 +206,21 @@ frontendpatterns = [
|
|||||||
re_path(r'^accounts/', include('allauth.urls')), # included urlpatterns
|
re_path(r'^accounts/', include('allauth.urls')), # included urlpatterns
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
new_frontendpatterns = [
|
||||||
|
# Platform urls
|
||||||
|
re_path(r'^platform/', include(platform_urls)),
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
# Load patterns for frontend according to settings
|
||||||
|
frontendpatterns = []
|
||||||
|
if settings.ENABLE_CLASSIC_FRONTEND:
|
||||||
|
frontendpatterns.append(re_path('', include(classic_frontendpatterns)))
|
||||||
|
if settings.ENABLE_PLATFORM_FRONTEND:
|
||||||
|
frontendpatterns.append(re_path('', include(new_frontendpatterns)))
|
||||||
|
|
||||||
|
|
||||||
# Append custom plugin URLs (if plugin support is enabled)
|
# Append custom plugin URLs (if plugin support is enabled)
|
||||||
if settings.PLUGINS_ENABLED:
|
if settings.PLUGINS_ENABLED:
|
||||||
frontendpatterns.append(get_plugin_urls())
|
frontendpatterns.append(get_plugin_urls())
|
||||||
|
@ -58,6 +58,12 @@ database:
|
|||||||
# Use the environment variable INVENTREE_DEBUG
|
# Use the environment variable INVENTREE_DEBUG
|
||||||
debug: True
|
debug: True
|
||||||
|
|
||||||
|
# Set enabled frontends
|
||||||
|
# Use the environment variable INVENTREE_CLASSIC_FRONTEND
|
||||||
|
# classic_frontend: True
|
||||||
|
# Use the environment variable INVENTREE_PLATFORM_FRONTEND
|
||||||
|
# platform_frontend: True
|
||||||
|
|
||||||
# Configure the system logging level
|
# Configure the system logging level
|
||||||
# Use environment variable INVENTREE_LOG_LEVEL
|
# Use environment variable INVENTREE_LOG_LEVEL
|
||||||
# Options: DEBUG / INFO / WARNING / ERROR / CRITICAL
|
# Options: DEBUG / INFO / WARNING / ERROR / CRITICAL
|
||||||
|
18
InvenTree/web/templates/web/index.html
Normal file
18
InvenTree/web/templates/web/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% load spa_helper %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>{% inventree_instance_name %}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
{% spa_bundle %}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
36
InvenTree/web/templatetags/spa_helper.py
Normal file
36
InvenTree/web/templatetags/spa_helper.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
"""Template tag to render SPA imports."""
|
||||||
|
import json
|
||||||
|
from logging import getLogger
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
logger = getLogger("gwaesser_backend")
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def spa_bundle():
|
||||||
|
"""Render SPA bundle."""
|
||||||
|
manifest = Path(__file__).parent.parent.joinpath("static/web/manifest.json")
|
||||||
|
|
||||||
|
if not manifest.exists():
|
||||||
|
logger.error("Manifest file not found")
|
||||||
|
return
|
||||||
|
|
||||||
|
manifest_data = json.load(manifest.open())
|
||||||
|
index = manifest_data.get("index.html")
|
||||||
|
|
||||||
|
dynmanic_files = index.get("dynamicImports", [])
|
||||||
|
imports_files = "".join(
|
||||||
|
[
|
||||||
|
f'<script type="module" src="{settings.STATIC_URL}web/{manifest_data[file]["file"]}"></script>'
|
||||||
|
for file in dynmanic_files
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
return mark_safe(
|
||||||
|
f"""<script type="module" src="{settings.STATIC_URL}web/{index['file']}"></script>{imports_files}"""
|
||||||
|
)
|
26
InvenTree/web/urls.py
Normal file
26
InvenTree/web/urls.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
"""URLs for web app."""
|
||||||
|
from django.conf import settings
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.urls import path, re_path
|
||||||
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
|
||||||
|
class RedirectAssetView(TemplateView):
|
||||||
|
"""View to redirect to static asset."""
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
"""Redirect to static asset."""
|
||||||
|
return redirect(
|
||||||
|
f"{settings.STATIC_URL}web/assets/{kwargs['path']}", permanent=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
spa_view = ensure_csrf_cookie(TemplateView.as_view(template_name="web/index.html"))
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("assets/<path:path>", RedirectAssetView.as_view()),
|
||||||
|
re_path(r"^(?P<path>.*)/$", spa_view),
|
||||||
|
path("", spa_view),
|
||||||
|
]
|
8
src/frontend/.babelrc
Normal file
8
src/frontend/.babelrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
"@babel/preset-react"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"macros"
|
||||||
|
]
|
||||||
|
}
|
7
src/frontend/.eslintrc.cjs
Normal file
7
src/frontend/.eslintrc.cjs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/* eslint-env node */
|
||||||
|
module.exports = {
|
||||||
|
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
root: true,
|
||||||
|
};
|
29
src/frontend/.gitignore
vendored
Normal file
29
src/frontend/.gitignore
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/playwright/.cache/
|
19
src/frontend/.linguirc
Normal file
19
src/frontend/.linguirc
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"locales": ["en", "de", "hu", "pseudo-LOCALE"],
|
||||||
|
"catalogs": [{
|
||||||
|
"path": "src/locales/{locale}/messages",
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["**/node_modules/**"]
|
||||||
|
}],
|
||||||
|
"format": "po",
|
||||||
|
"orderBy": "origin",
|
||||||
|
"sourceLocale": "en",
|
||||||
|
"pseudoLocale": "pseudo-LOCALE",
|
||||||
|
"fallbackLocales": {
|
||||||
|
"default": "en",
|
||||||
|
"pseudo-LOCALE": "en"
|
||||||
|
},
|
||||||
|
"extractBabelOptions": {
|
||||||
|
"presets": ["@babel/preset-typescript"]
|
||||||
|
}
|
||||||
|
}
|
9
src/frontend/.prettierrc
Normal file
9
src/frontend/.prettierrc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 80,
|
||||||
|
"importOrder": ["<THIRD_PARTY_MODULES>", "^[./]"],
|
||||||
|
"importOrderSeparation": true,
|
||||||
|
"importOrderSortSpecifiers": true
|
||||||
|
}
|
16
src/frontend/index.html
Normal file
16
src/frontend/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/inventree.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>InvenTree</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
36
src/frontend/package.json
Normal file
36
src/frontend/package.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "InvenTreeUI",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"extract": "lingui extract",
|
||||||
|
"compile": "lingui compile --typescript"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@lingui/core": "^4.2.1",
|
||||||
|
"@lingui/react": "^4.2.1",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.20.5",
|
||||||
|
"@babel/preset-react": "^7.18.6",
|
||||||
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
|
"@lingui/cli": "^4.2.1",
|
||||||
|
"@lingui/macro": "^4.2.1",
|
||||||
|
"@playwright/test": "^1.35.0",
|
||||||
|
"@types/node": "^20.3.0",
|
||||||
|
"@types/react": "^18.0.24",
|
||||||
|
"@types/react-dom": "^18.0.8",
|
||||||
|
"@types/react-router-dom": "^5.3.3",
|
||||||
|
"@vitejs/plugin-react": "^4.0.0",
|
||||||
|
"babel-plugin-macros": "^3.1.0",
|
||||||
|
"typescript": "^5.1.3",
|
||||||
|
"vite": "^4.0.3",
|
||||||
|
"vite-plugin-babel-macros": "^1.0.6"
|
||||||
|
}
|
||||||
|
}
|
40
src/frontend/playwright.config.ts
Normal file
40
src/frontend/playwright.config.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
fullyParallel: true,
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 1 : 0,
|
||||||
|
workers: process.env.CI ? 2 : undefined,
|
||||||
|
reporter: 'html',
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Chrome']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'firefox',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Firefox']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: {
|
||||||
|
command: 'invoke server -a 127.0.0.1:8000',
|
||||||
|
url: 'http://127.0.0.1:8000/api/',
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
stdout: 'pipe',
|
||||||
|
stderr: 'pipe',
|
||||||
|
timeout: 120 * 1000
|
||||||
|
},
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://127.0.0.1:8000',
|
||||||
|
trace: 'on-first-retry'
|
||||||
|
}
|
||||||
|
});
|
291
src/frontend/public/inventree.svg
Normal file
291
src/frontend/public/inventree.svg
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
<?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:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
sodipodi:docname="inventree.svg"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
version="1.1"
|
||||||
|
id="svg2"
|
||||||
|
viewBox="0 0 400 400.00001"
|
||||||
|
height="400"
|
||||||
|
width="400"
|
||||||
|
inkscape:export-filename="C:\inventree\images\logo\inventree.png"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001">
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:current-layer="g2907"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:cy="426.62472"
|
||||||
|
inkscape:cx="-960.58794"
|
||||||
|
inkscape:zoom="0.31819805"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
id="base"
|
||||||
|
units="px" />
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="skeletal"
|
||||||
|
id="path-effect4158"
|
||||||
|
is_visible="true"
|
||||||
|
pattern="m 446.48742,503.05596 1,0"
|
||||||
|
copytype="single_stretched"
|
||||||
|
prop_scale="1"
|
||||||
|
scale_y_rel="false"
|
||||||
|
spacing="0"
|
||||||
|
normal_offset="0"
|
||||||
|
tang_offset="0"
|
||||||
|
prop_units="false"
|
||||||
|
vertical_pattern="false"
|
||||||
|
fuse_tolerance="0"
|
||||||
|
pattern-nodetypes="cc" />
|
||||||
|
</defs>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<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 />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-652.36216)">
|
||||||
|
<g
|
||||||
|
id="g2907"
|
||||||
|
transform="matrix(1.7132796,0,0,1.7132796,460.05136,236.12365)">
|
||||||
|
<g
|
||||||
|
id="g5713">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4896"
|
||||||
|
d="m -151.78571,359.62883 v 112.76373 l 97.068507,-56.04253 V 303.14815 Z"
|
||||||
|
style="fill:#ddbc91;fill-opacity:1;stroke:#000000;stroke-width:1.5622561;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="fill:#d9b383;fill-opacity:1;stroke:#000000;stroke-width:1.5622561;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m -151.78571,359.62883 v 112.76373 l -97.0685,-56.04253 V 303.14815 Z"
|
||||||
|
id="path4898"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4900"
|
||||||
|
d="m -54.717203,303.14815 -97.068507,56.48068 -97.0685,-56.48068 97.0685,-56.17354 z"
|
||||||
|
style="fill:#ddbc91;fill-opacity:1;stroke:#000000;stroke-width:1.5622561;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<g
|
||||||
|
id="g4916"
|
||||||
|
transform="matrix(1.4761476,0,0,1.4761476,-218.87903,128.54472)"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#f3f4e4;fill-opacity:1;stroke:#000000;stroke-width:1.05833328;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1">
|
||||||
|
<path
|
||||||
|
id="path4910"
|
||||||
|
transform="matrix(0.40703466,0,0,0.40703466,-35.955294,75.175547)"
|
||||||
|
d="M 78.833984,129.19141 V 270.49609 L 200,340.45117 321.16602,270.49609 V 129.19141 L 200,199.69336 Z"
|
||||||
|
style="vector-effect:none;fill:#f3f4e4;fill-opacity:1;stroke:#000000;stroke-width:2.600106;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="vector-effect:none;fill:#f3f4e4;fill-opacity:1;stroke:#000000;stroke-width:1.05833328;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="M 94.770135,127.76116 45.451638,156.45782 -3.8668589,127.76116 45.451638,99.220548 Z"
|
||||||
|
id="path4914"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#d9dbbc;fill-opacity:1;stroke:#000000;stroke-width:1.56225622;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m -151.7857,275.0089 v 84.49065 l -72.80137,42.54091 v -84.90142 z"
|
||||||
|
id="path4918"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4920"
|
||||||
|
d="m -151.7857,275.0089 v 84.49065 l 72.801373,42.54091 v -84.90142 z"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#eaeccf;fill-opacity:1;stroke:#000000;stroke-width:1.56225622;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<g
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
transform="matrix(0.9840984,0,0,0.9840984,-196.5146,205.65597)"
|
||||||
|
id="g4928">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4922"
|
||||||
|
d="m 45.451638,156.45782 v 57.29292 l 49.318497,-28.47405 v -57.51553 z"
|
||||||
|
style="vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 45.451638,156.45782 v 57.29292 L -3.866859,185.27669 v -57.51553 z"
|
||||||
|
id="path4924"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4926"
|
||||||
|
d="M 94.770135,127.76116 45.451638,156.45782 -3.8668589,127.76116 45.451638,99.220548 Z"
|
||||||
|
style="vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="translate(0,102.8232)"
|
||||||
|
id="g5856"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001">
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m -587.59709,399.25327 v 126.38928 l 108.79755,-62.8143 V 335.94789 Z"
|
||||||
|
id="path5850"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5852"
|
||||||
|
d="m -587.59709,399.25327 v 126.38928 l -108.79754,-62.8143 V 335.94789 Z"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m -478.79954,335.94789 -108.79755,63.30538 -108.79754,-63.30538 108.79754,-62.96113 z"
|
||||||
|
id="path5854"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g5848"
|
||||||
|
transform="translate(0,-23.56608)"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5803"
|
||||||
|
d="m -587.59709,399.25327 v 126.38928 l 108.79755,-62.8143 V 335.94789 Z"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m -587.59709,399.25327 v 126.38928 l -108.79754,-62.8143 V 335.94789 Z"
|
||||||
|
id="path5805"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5807"
|
||||||
|
d="m -478.79954,335.94789 -108.79755,63.30538 -108.79754,-63.30538 108.79754,-62.96113 z"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4649"
|
||||||
|
d="m -587.59709,249.29791 v 126.38928 l 108.79755,-62.8143 V 185.99253 Z"
|
||||||
|
style="fill:#ddbc91;fill-opacity:1;stroke:#000000;stroke-width:1.75102758;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#d9b383;fill-opacity:1;stroke:#000000;stroke-width:1.5622561;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m -587.59709,249.29791 v 126.38928 l -108.79754,-62.8143 V 185.99253 Z"
|
||||||
|
id="path4651"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4653"
|
||||||
|
d="m -478.79954,185.99253 -108.79755,63.30538 -108.79754,-63.30538 108.79754,-62.96113 z"
|
||||||
|
style="fill:#ddbc91;fill-opacity:1;stroke:#000000;stroke-width:1.75102758;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001" />
|
||||||
|
<g
|
||||||
|
id="g4703"
|
||||||
|
transform="matrix(1.6545144,0,0,1.6545144,-662.79747,-9.7087)"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#f3f4e4;fill-opacity:1;stroke:#000000;stroke-width:1.05833328;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="vector-effect:none;fill:#f3f4e4;fill-opacity:1;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m -713.3418,130.54492 v 163.03516 l 139.79883,80.71484 139.80078,-80.71484 V 130.54492 l -139.80078,81.3457 z"
|
||||||
|
transform="matrix(0.35277777,0,0,0.35277777,247.78456,81.707826)"
|
||||||
|
id="path4697" />
|
||||||
|
<path
|
||||||
|
style="vector-effect:none;fill:#f3f4e4;fill-opacity:1;stroke:#000000;stroke-width:1.05833328;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="M 94.770135,127.76116 45.451638,156.45782 -3.8668589,127.76116 45.451638,99.220548 Z"
|
||||||
|
id="path4701"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="opacity:1;vector-effect:none;fill:#d9dbbc;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m -587.59709,154.45314 v 94.69988 l -81.59816,47.68125 v -95.1603 z"
|
||||||
|
id="path4788"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4830"
|
||||||
|
d="m -587.59709,154.45314 v 94.69988 l 81.59817,47.68125 v -95.1603 z"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#eaeccf;fill-opacity:1;stroke:#000000;stroke-width:1.7510277;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001" />
|
||||||
|
<g
|
||||||
|
style="opacity:1;vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
transform="matrix(1.1030096,0,0,1.1030096,-637.73068,76.7201)"
|
||||||
|
id="g4695"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4689"
|
||||||
|
d="m 45.451638,156.45782 v 57.29292 l 49.318497,-28.47405 v -57.51553 z"
|
||||||
|
style="vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 45.451638,156.45782 v 57.29292 L -3.866859,185.27669 v -57.51553 z"
|
||||||
|
id="path4691"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4693"
|
||||||
|
d="M 94.770135,127.76116 45.451638,156.45782 -3.8668589,127.76116 45.451638,99.220548 Z"
|
||||||
|
style="vector-effect:none;fill:#90a8d8;fill-opacity:1;stroke:#000000;stroke-width:1.58749998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:none;stroke-width:1.41293824;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect5777"
|
||||||
|
width="281.65912"
|
||||||
|
height="552.58508"
|
||||||
|
x="-728.42657"
|
||||||
|
y="95.064545"
|
||||||
|
inkscape:export-xdpi="499.92001"
|
||||||
|
inkscape:export-ydpi="499.92001" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 16 KiB |
10
src/frontend/src/App.tsx
Normal file
10
src/frontend/src/App.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Main App
|
||||||
|
export default function App() {
|
||||||
|
// Main App component
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Welcome to the new frontend!</h1>
|
||||||
|
<p>This is a placeholder site</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
1
src/frontend/src/assets/inventree.svg
Normal file
1
src/frontend/src/assets/inventree.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400"><g stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.676"><path fill="#ddbc91" d="M200 199.906v193.196l166.305-96.016V103.139Z"/><path fill="#d9b383" d="M200 199.906v193.196L33.695 297.086V103.139Z"/><path fill="#ddbc91" d="M366.305 103.139 200 199.906 33.695 103.14 200 6.899z"/><g fill="#f3f4e4"><path d="M75.27 127.109v145.46L200 344.583l124.73-72.012V127.109L200 199.684Z"/><path d="M324.73 127.11 200 199.684 75.27 127.109 200 54.93Z"/></g><path fill="#d9dbbc" d="M200 54.929v144.756L75.27 272.569V127.11z"/><path fill="#eaeccf" d="M200 54.929v144.756l124.73 72.884V127.11z"/><path fill="#90a8d8" d="M200 199.901V296.5l83.153-48.008v-96.973zm0 0V296.5l-83.153-48.008v-96.973zm83.153-48.383L200 199.9l-83.153-48.383L200 103.398Z"/></g><g fill="#90a8d8" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"><path d="M-546.667 443.959v216.54l186.4-107.618V335.499Zm0 0v216.54l-186.4-107.618V335.499Z"/><path d="m-360.266 335.499-186.4 108.46-186.401-108.46 186.4-107.87z"/></g><g fill="#90a8d8" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"><path d="M-546.667 227.419v216.54l186.4-107.619V118.96Zm0 0v216.54l-186.4-107.619V118.96Z"/><path d="m-360.266 118.959-186.4 108.46-186.401-108.46 186.4-107.87z"/></g><path fill="#ddbc91" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M-546.667 10.879v216.54l186.4-107.619V-97.58Z"/><path fill="#d9b383" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.676" d="M-546.667 10.879v216.54l-186.4-107.619V-97.58Z"/><path fill="#ddbc91" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="m-360.266-97.581-186.4 108.46-186.401-108.46 186.4-107.87z"/><g fill="#f3f4e4" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.058"><path stroke-width="3" d="M-686.466-70.715V92.321l139.798 80.714 139.801-80.714V-70.715l-139.8 81.346z"/><path stroke-width="2.999" d="m-406.866-70.715-139.8 81.345-139.801-81.345 139.8-80.902Z"/></g><path fill="#d9dbbc" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M-546.667-151.617V10.63l-139.8 81.692V-70.715z"/><path fill="#eaeccf" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M-546.667-151.617V10.63l139.8 81.692V-70.715z"/><g fill="#90a8d8" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.999"><path d="M-546.667 10.873v108.27l93.2-53.81v-108.69zm0 0v108.27l-93.2-53.81v-108.69z"/><path d="m-453.466-43.357-93.2 54.23-93.201-54.23 93.2-53.935Z"/></g><path fill="none" d="M-787.948-253.366h482.56v946.733h-482.56z"/></svg>
|
After Width: | Height: | Size: 2.7 KiB |
4
src/frontend/src/locales/de/messages.d.ts
vendored
Normal file
4
src/frontend/src/locales/de/messages.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Messages } from '@lingui/core';
|
||||||
|
|
||||||
|
declare const messages: Messages;
|
||||||
|
export { messages };
|
14
src/frontend/src/locales/de/messages.po
Normal file
14
src/frontend/src/locales/de/messages.po
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"POT-Creation-Date: 2023-06-09 22:10+0200\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: @lingui/cli\n"
|
||||||
|
"Language: de\n"
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Plural-Forms: \n"
|
1
src/frontend/src/locales/de/messages.ts
Normal file
1
src/frontend/src/locales/de/messages.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
/*eslint-disable*/ export const messages = JSON.parse('{}');
|
4
src/frontend/src/locales/en/messages.d.ts
vendored
Normal file
4
src/frontend/src/locales/en/messages.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Messages } from '@lingui/core';
|
||||||
|
|
||||||
|
declare const messages: Messages;
|
||||||
|
export { messages };
|
14
src/frontend/src/locales/en/messages.po
Normal file
14
src/frontend/src/locales/en/messages.po
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"POT-Creation-Date: 2023-06-09 22:10+0200\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: @lingui/cli\n"
|
||||||
|
"Language: en\n"
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Plural-Forms: \n"
|
1
src/frontend/src/locales/en/messages.ts
Normal file
1
src/frontend/src/locales/en/messages.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
/*eslint-disable*/ export const messages = JSON.parse('{}');
|
4
src/frontend/src/locales/hu/messages.d.ts
vendored
Normal file
4
src/frontend/src/locales/hu/messages.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Messages } from '@lingui/core';
|
||||||
|
|
||||||
|
declare const messages: Messages;
|
||||||
|
export { messages };
|
14
src/frontend/src/locales/hu/messages.po
Normal file
14
src/frontend/src/locales/hu/messages.po
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"POT-Creation-Date: 2023-06-09 22:10+0200\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: @lingui/cli\n"
|
||||||
|
"Language: hu\n"
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Plural-Forms: \n"
|
1
src/frontend/src/locales/hu/messages.ts
Normal file
1
src/frontend/src/locales/hu/messages.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
/*eslint-disable*/ export const messages = JSON.parse('{}');
|
4
src/frontend/src/locales/pseudo-LOCALE/messages.d.ts
vendored
Normal file
4
src/frontend/src/locales/pseudo-LOCALE/messages.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Messages } from '@lingui/core';
|
||||||
|
|
||||||
|
declare const messages: Messages;
|
||||||
|
export { messages };
|
14
src/frontend/src/locales/pseudo-LOCALE/messages.po
Normal file
14
src/frontend/src/locales/pseudo-LOCALE/messages.po
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"POT-Creation-Date: 2023-06-09 22:10+0200\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: @lingui/cli\n"
|
||||||
|
"Language: pseudo-LOCALE\n"
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Plural-Forms: \n"
|
1
src/frontend/src/locales/pseudo-LOCALE/messages.ts
Normal file
1
src/frontend/src/locales/pseudo-LOCALE/messages.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
/*eslint-disable*/ export const messages = JSON.parse('{}');
|
10
src/frontend/src/main.tsx
Normal file
10
src/frontend/src/main.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
1
src/frontend/src/vite-env.d.ts
vendored
Normal file
1
src/frontend/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
31
src/frontend/tests/classic.spec.ts
Normal file
31
src/frontend/tests/classic.spec.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
import exp from 'constants';
|
||||||
|
|
||||||
|
test('Check classic index site', async ({ page }) => {
|
||||||
|
await page.goto('./api/');
|
||||||
|
await page.goto('./index/');
|
||||||
|
await expect(page).toHaveTitle('InvenTree Demo Server | Sign In');
|
||||||
|
await expect(
|
||||||
|
page.getByRole('heading', { name: 'InvenTree Demo Server' })
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByLabel('username').fill('allaccess');
|
||||||
|
await page.getByLabel('password').fill('nolimits');
|
||||||
|
await page.click('button', { text: 'Sign In' });
|
||||||
|
await page.waitForURL('**/index/');
|
||||||
|
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
await expect(page).toHaveTitle('InvenTree Demo Server | Index');
|
||||||
|
await expect(page.getByRole('button', { name: 'allaccess' })).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Parts', exact: true })
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Stock', exact: true })
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Build', exact: true })
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(page.getByRole('button', { name: 'Buy' })).toBeVisible();
|
||||||
|
await expect(page.getByRole('button', { name: 'Sell' })).toBeVisible();
|
||||||
|
});
|
20
src/frontend/tests/ui_plattform.spec.ts
Normal file
20
src/frontend/tests/ui_plattform.spec.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
test('Basic Platform UI test', async ({ page }) => {
|
||||||
|
await page.goto('./index/');
|
||||||
|
await expect(page).toHaveTitle('InvenTree Demo Server | Sign In');
|
||||||
|
await expect(
|
||||||
|
page.getByRole('heading', { name: 'InvenTree Demo Server' })
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByLabel('username').fill('allaccess');
|
||||||
|
await page.getByLabel('password').fill('nolimits');
|
||||||
|
await page.click('button', { text: 'Sign In' });
|
||||||
|
|
||||||
|
await page.goto('./platform/');
|
||||||
|
|
||||||
|
await expect(page).toHaveTitle('InvenTree Demo Server');
|
||||||
|
await expect(
|
||||||
|
page.getByRole('heading', { name: 'Welcome to the new frontend!' })
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
21
src/frontend/tsconfig.json
Normal file
21
src/frontend/tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": false,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
9
src/frontend/tsconfig.node.json
Normal file
9
src/frontend/tsconfig.node.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
17
src/frontend/vite.config.ts
Normal file
17
src/frontend/vite.config.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
react({
|
||||||
|
babel: {
|
||||||
|
plugins: ['macros']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
build: {
|
||||||
|
manifest: true,
|
||||||
|
outDir: '../../InvenTree/web/static/web'
|
||||||
|
}
|
||||||
|
});
|
1916
src/frontend/yarn.lock
Normal file
1916
src/frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
64
tasks.py
64
tasks.py
@ -89,6 +89,19 @@ def manage(c, cmd, pty: bool = False):
|
|||||||
), pty=pty)
|
), pty=pty)
|
||||||
|
|
||||||
|
|
||||||
|
def yarn(c, cmd, pty: bool = False):
|
||||||
|
"""Runs a given command against the yarn package manager.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
c: Command line context.
|
||||||
|
cmd: Yarn command to run.
|
||||||
|
pty (bool, optional): Run an interactive session. Defaults to False.
|
||||||
|
"""
|
||||||
|
|
||||||
|
path = managePyDir().parent.joinpath('src').joinpath('frontend')
|
||||||
|
c.run(f'cd "{path}" && {cmd}', pty=pty)
|
||||||
|
|
||||||
|
|
||||||
def check_file_existance(filename: str, overwrite: bool = False):
|
def check_file_existance(filename: str, overwrite: bool = False):
|
||||||
"""Checks if a file exists and asks the user if it should be overwritten.
|
"""Checks if a file exists and asks the user if it should be overwritten.
|
||||||
|
|
||||||
@ -188,6 +201,7 @@ def remove_mfa(c, mail=''):
|
|||||||
def static(c):
|
def static(c):
|
||||||
"""Copies required static files to the STATIC_ROOT directory, as per Django requirements."""
|
"""Copies required static files to the STATIC_ROOT directory, as per Django requirements."""
|
||||||
manage(c, "prerender")
|
manage(c, "prerender")
|
||||||
|
frontend_build(c)
|
||||||
manage(c, "collectstatic --no-input")
|
manage(c, "collectstatic --no-input")
|
||||||
|
|
||||||
|
|
||||||
@ -290,6 +304,9 @@ def update(c, skip_backup=False):
|
|||||||
# Perform database migrations
|
# Perform database migrations
|
||||||
migrate(c)
|
migrate(c)
|
||||||
|
|
||||||
|
# Compile frontend
|
||||||
|
frontend_compile(c)
|
||||||
|
|
||||||
|
|
||||||
# Data tasks
|
# Data tasks
|
||||||
@task(help={
|
@task(help={
|
||||||
@ -697,3 +714,50 @@ You are probably running the package installer / single-line installer. Please m
|
|||||||
|
|
||||||
Use '--list' for a list of available commands
|
Use '--list' for a list of available commands
|
||||||
Use '--help' for help on a specific command""")
|
Use '--help' for help on a specific command""")
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def frontend_compile(c):
|
||||||
|
"""Generate react frontend.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
c: Context variable
|
||||||
|
"""
|
||||||
|
|
||||||
|
frontend_install(c)
|
||||||
|
frontend_trans(c)
|
||||||
|
frontend_build(c)
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def frontend_install(c):
|
||||||
|
"""Install frontend requirements.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
c: Context variable
|
||||||
|
"""
|
||||||
|
print("Installing frontend dependencies")
|
||||||
|
yarn(c, "yarn install")
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def frontend_trans(c):
|
||||||
|
"""Compile frontend translations.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
c: Context variable
|
||||||
|
"""
|
||||||
|
print("Compiling frontend translations")
|
||||||
|
yarn(c, "yarn run extract")
|
||||||
|
yarn(c, "yarn run compile")
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def frontend_build(c):
|
||||||
|
"""Build frontend.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
c: Context variable
|
||||||
|
"""
|
||||||
|
print("Building frontend")
|
||||||
|
yarn(c, "yarn run build --emptyOutDir")
|
||||||
|
Loading…
Reference in New Issue
Block a user