From 39ba25c5ed6e0651385895931c047e4541783f77 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 2 Mar 2024 11:28:37 +1100 Subject: [PATCH] Render API docs (#6463) * Render API docs * Cleanup broken links * Re-enable strict mode * Change json to yaml * Update docs/docs/api/schema.md Co-authored-by: Matthias Mair * Update docs/docs/api/schema.md Co-authored-by: Matthias Mair * Use neoteroi-mkdocs instead - seems to render more reliably * Fix SERVERS section for SPECTACTULAR_SETTINGS * Script for splitting schema into smaller sections * Generate an index file for the schema pages * Move schema.md up one directory * Fix formatting * Remove tracked file * Add hook for rebuilding API schema as part of RTD build * Extract schema as RTD build step * install invoke * export env vars * remove argparse * Fix order of operations * Compress env vars * Remove custom env vars - Now configured as part of RTD project * Migrate db * Revert "remove argparse" This reverts commit 4665805340d068a5e17bd7f60addac930383acf5. * Post-process generated schema file * Fix file formatting * Add note about schema repo * no message * Reduce schema overhead * Ignore generated files * Delete generated file * Update .gitignore * Add extra split for machine integration * Remove schema files - These will be auto-generated too * Generate individual schema .md files * Re-add .md files - Need git commit log to work * Update .gitignore * Fix for CI test * patch machine.api * Revert previous change * Formatting fix * Adjust export step * Bump API version --------- Co-authored-by: Matthias Mair --- .github/workflows/qc_checks.yaml | 4 +- .gitignore | 4 + InvenTree/InvenTree/api_version.py | 5 +- InvenTree/InvenTree/settings.py | 35 +- InvenTree/machine/api.py | 4 +- docs/.gitignore | 3 + docs/docs/api/api.md | 11 + docs/docs/api/schema.md | 40 + docs/docs/api/schema/auth.md | 7 + docs/docs/api/schema/background-task.md | 7 + docs/docs/api/schema/barcode.md | 7 + docs/docs/api/schema/bom.md | 7 + docs/docs/api/schema/build.md | 7 + docs/docs/api/schema/company.md | 7 + docs/docs/api/schema/general.md | 7 + docs/docs/api/schema/label.md | 7 + docs/docs/api/schema/machine.md | 7 + docs/docs/api/schema/order.md | 7 + docs/docs/api/schema/part.md | 7 + docs/docs/api/schema/plugins.md | 7 + docs/docs/api/schema/report.md | 7 + docs/docs/api/schema/settings.md | 7 + docs/docs/api/schema/stock.md | 7 + docs/docs/api/schema/user.md | 7 + docs/docs/concepts/units.md | 2 +- docs/docs/extend/plugins/tags.md | 2 +- docs/docs/part/create.md | 6 +- docs/docs/part/notification.md | 4 +- docs/docs/part/trackable.md | 2 +- docs/docs/releases/0.1.5.md | 2 +- docs/docs/releases/0.2.1.md | 2 +- docs/docs/releases/0.6.0.md | 4 +- docs/docs/stock/owner.md | 4 +- docs/docs/stylesheets/neoteroi-mkdocs.css | 1399 +++++++++++++++++++++ docs/extract_schema.py | 232 ++++ docs/mkdocs.yml | 6 + docs/requirements.txt | 1 + readthedocs.yml | 8 + tasks.py | 8 + 39 files changed, 1867 insertions(+), 33 deletions(-) create mode 100644 docs/docs/api/schema.md create mode 100644 docs/docs/api/schema/auth.md create mode 100644 docs/docs/api/schema/background-task.md create mode 100644 docs/docs/api/schema/barcode.md create mode 100644 docs/docs/api/schema/bom.md create mode 100644 docs/docs/api/schema/build.md create mode 100644 docs/docs/api/schema/company.md create mode 100644 docs/docs/api/schema/general.md create mode 100644 docs/docs/api/schema/label.md create mode 100644 docs/docs/api/schema/machine.md create mode 100644 docs/docs/api/schema/order.md create mode 100644 docs/docs/api/schema/part.md create mode 100644 docs/docs/api/schema/plugins.md create mode 100644 docs/docs/api/schema/report.md create mode 100644 docs/docs/api/schema/settings.md create mode 100644 docs/docs/api/schema/stock.md create mode 100644 docs/docs/api/schema/user.md create mode 100644 docs/docs/stylesheets/neoteroi-mkdocs.css create mode 100644 docs/extract_schema.py diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index db11adc07f..4509b3783b 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -144,7 +144,7 @@ jobs: dev-install: true update: true - name: Export API Documentation - run: invoke schema --ignore-warnings + run: invoke schema --ignore-warnings --filename InvenTree/schema.yml - name: Upload schema uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # pin@v3.1.3 with: @@ -160,7 +160,7 @@ jobs: echo "URL: $url" curl -s -o api.yaml $url echo "Downloaded api.yaml" - - name: Check for differences in schemas + - name: Check for differences in API Schema if: needs.paths-filter.outputs.api == 'false' run: | diff --color -u InvenTree/schema.yml api.yaml diff --git a/.gitignore b/.gitignore index 5f2b31d170..bcc2f2ac5d 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,7 @@ api.yaml # web frontend (static files) InvenTree/web/static + +# Generated docs files +docs/docs/api/*.yml +docs/docs/api/schema/*.yml diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index c99f1d2faf..28e10bde2c 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -1,11 +1,14 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 179 +INVENTREE_API_VERSION = 180 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v180 - 2024-3-02 : https://github.com/inventree/InvenTree/pull/6463 + - Tweaks to API documentation to allow automatic documentation generation + v179 - 2024-03-01 : https://github.com/inventree/InvenTree/pull/6605 - Adds "subcategories" count to PartCategory serializer - Adds "sublocations" count to StockLocation serializer diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index f08b85e2e7..83947e6d52 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -469,21 +469,6 @@ if USE_JWT: INSTALLED_APPS.append('rest_framework_simplejwt') # WSGI default setting -SPECTACULAR_SETTINGS = { - 'TITLE': 'InvenTree API', - 'DESCRIPTION': 'API for InvenTree - the intuitive open source inventory management system', - 'LICENSE': { - 'name': 'MIT', - 'url': 'https://github.com/inventree/InvenTree/blob/master/LICENSE', - }, - 'EXTERNAL_DOCS': { - 'description': 'More information about InvenTree in the official docs', - 'url': 'https://docs.inventree.org', - }, - 'VERSION': str(inventreeApiVersion()), - 'SERVE_INCLUDE_SCHEMA': False, -} - WSGI_APPLICATION = 'InvenTree.wsgi.application' """ @@ -1208,3 +1193,23 @@ if CUSTOM_FLAGS: # Magic login django-sesame SESAME_MAX_AGE = 300 LOGIN_REDIRECT_URL = '/api/auth/login-redirect/' + +# Configuratino for API schema generation +SPECTACULAR_SETTINGS = { + 'TITLE': 'InvenTree API', + 'DESCRIPTION': 'API for InvenTree - the intuitive open source inventory management system', + 'LICENSE': { + 'name': 'MIT', + 'url': 'https://github.com/inventree/InvenTree/blob/master/LICENSE', + }, + 'EXTERNAL_DOCS': { + 'description': 'More information about InvenTree in the official docs', + 'url': 'https://docs.inventree.org', + }, + 'VERSION': str(inventreeApiVersion()), + 'SERVE_INCLUDE_SCHEMA': False, + 'SCHEMA_PATH_PREFIX': '/api/', +} + +if SITE_URL: + SPECTACULAR_SETTINGS['SERVERS'] = [{'url': SITE_URL}] diff --git a/InvenTree/machine/api.py b/InvenTree/machine/api.py index 9448d2ea99..3bd2853467 100644 --- a/InvenTree/machine/api.py +++ b/InvenTree/machine/api.py @@ -144,7 +144,9 @@ class MachineRestart(APIView): permission_classes = [permissions.IsAuthenticated] - @extend_schema(responses={200: MachineSerializers.MachineRestartSerializer()}) + @extend_schema( + request=None, responses={200: MachineSerializers.MachineRestartSerializer()} + ) def post(self, request, pk): """Restart machine by pk.""" machine = get_machine(pk) diff --git a/docs/.gitignore b/docs/.gitignore index ecbeb1b0ab..ea8649cfa3 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -10,6 +10,9 @@ env/ _build/ site/ +# Generated API schema files +docs/api/schema/*.yml + # Temp files releases.json versions.json diff --git a/docs/docs/api/api.md b/docs/docs/api/api.md index 0d8b24b128..7f2c9328d0 100644 --- a/docs/docs/api/api.md +++ b/docs/docs/api/api.md @@ -17,6 +17,17 @@ The API is self-documenting, and the documentation is provided alongside any Inv {% include 'img.html' %} {% endwith %} +### Schema Description + The API schema is also documented in the [API Schema](./schema.md) page. + +### Generating Schema File + +If you want to generate the API schema file yourself (for example to use with an external client, use the `invoke schema` command. Run with the `-help` command to see available options. + +``` +invoke schema -help +``` + ## Authentication Users must be authenticated to gain access to the InvenTree API. The API accepts either basic username:password authentication, or token authentication. Token authentication is recommended as it provides much faster API access. diff --git a/docs/docs/api/schema.md b/docs/docs/api/schema.md new file mode 100644 index 0000000000..441e977e2e --- /dev/null +++ b/docs/docs/api/schema.md @@ -0,0 +1,40 @@ +--- +title: InvenTree API Schema +--- + +The InvenTree API is implemented using the [Django REST framework](https://www.django-rest-framework.org). +The API schema as documented below is generated using the [drf-spectactular](https://github.com/tfranzel/drf-spectacular/) extension. + +## API Version + +This documentation is for API version: `171` + +!!! tip "API Schema History" + We track API schema changes, and provide a snapshot of each API schema version in the [API schema repository](https://github.com/inventree/schema/). + +## API Schema File + +The API schema file is available for download, and can be used for generating client libraries, or for testing API endpoints. + +## API Schema Documentation + +API schema documentation is split into the following categories: + +| Category | Description | +| --- | --- | +| [Authorization and Authentication](./schema/auth.md) | Authorization and Authentication | +| [Background Task Management](./schema/background-task.md) | Background Task Management | +| [Barcode Scanning](./schema/barcode.md) | Barcode Scanning | +| [Bill of Materials](./schema/bom.md) | Bill of Materials | +| [Build Order Management](./schema/build.md) | Build Order Management | +| [Company Management](./schema/company.md) | Company Management | +| [Label Printing](./schema/label.md) | Label Printing | +| [External Machine Management](./schema/machine.md) | External Machine Management | +| [External Order Management](./schema/order.md) | External Order Management | +| [Parts and Part Categories](./schema/part.md) | Parts and Part Categories | +| [Plugin Functionality](./schema/plugins.md) | Plugin Functionality | +| [Report Generation](./schema/report.md) | Report Generation | +| [Settings Management](./schema/settings.md) | Settings Management | +| [Stock and Stock Locations](./schema/stock.md) | Stock and Stock Locations | +| [User Management](./schema/user.md) | User Management | +| [General](./schema/general.md) | General API endpoints | diff --git a/docs/docs/api/schema/auth.md b/docs/docs/api/schema/auth.md new file mode 100644 index 0000000000..62c8b50103 --- /dev/null +++ b/docs/docs/api/schema/auth.md @@ -0,0 +1,7 @@ +--- +title: Authorization and Authentication +--- + +The *Authorization and Authentication* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/auth.yml)] diff --git a/docs/docs/api/schema/background-task.md b/docs/docs/api/schema/background-task.md new file mode 100644 index 0000000000..b1d5ad0b92 --- /dev/null +++ b/docs/docs/api/schema/background-task.md @@ -0,0 +1,7 @@ +--- +title: Background Task Management +--- + +The *Background Task Management* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/background-task.yml)] diff --git a/docs/docs/api/schema/barcode.md b/docs/docs/api/schema/barcode.md new file mode 100644 index 0000000000..c0f5cab2bf --- /dev/null +++ b/docs/docs/api/schema/barcode.md @@ -0,0 +1,7 @@ +--- +title: Barcode Scanning +--- + +The *Barcode Scanning* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/barcode.yml)] diff --git a/docs/docs/api/schema/bom.md b/docs/docs/api/schema/bom.md new file mode 100644 index 0000000000..cdfd1ff9c2 --- /dev/null +++ b/docs/docs/api/schema/bom.md @@ -0,0 +1,7 @@ +--- +title: Bill of Materials +--- + +The *Bill of Materials* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/bom.yml)] diff --git a/docs/docs/api/schema/build.md b/docs/docs/api/schema/build.md new file mode 100644 index 0000000000..3de0e521c6 --- /dev/null +++ b/docs/docs/api/schema/build.md @@ -0,0 +1,7 @@ +--- +title: Build Order Management +--- + +The *Build Order Management* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/build.yml)] diff --git a/docs/docs/api/schema/company.md b/docs/docs/api/schema/company.md new file mode 100644 index 0000000000..924d899ad4 --- /dev/null +++ b/docs/docs/api/schema/company.md @@ -0,0 +1,7 @@ +--- +title: Company Management +--- + +The *Company Management* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/company.yml)] diff --git a/docs/docs/api/schema/general.md b/docs/docs/api/schema/general.md new file mode 100644 index 0000000000..5da17b815d --- /dev/null +++ b/docs/docs/api/schema/general.md @@ -0,0 +1,7 @@ +--- +title: General API Endpoints +--- + +The *General API Endpoints* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/general.yml)] diff --git a/docs/docs/api/schema/label.md b/docs/docs/api/schema/label.md new file mode 100644 index 0000000000..d4bc47e57c --- /dev/null +++ b/docs/docs/api/schema/label.md @@ -0,0 +1,7 @@ +--- +title: Label Printing +--- + +The *Label Printing* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/label.yml)] diff --git a/docs/docs/api/schema/machine.md b/docs/docs/api/schema/machine.md new file mode 100644 index 0000000000..2fbadd41e6 --- /dev/null +++ b/docs/docs/api/schema/machine.md @@ -0,0 +1,7 @@ +--- +title: External Machine Management +--- + +The *External Machine Management* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/machine.yml)] diff --git a/docs/docs/api/schema/order.md b/docs/docs/api/schema/order.md new file mode 100644 index 0000000000..7f6c8fdfd7 --- /dev/null +++ b/docs/docs/api/schema/order.md @@ -0,0 +1,7 @@ +--- +title: External Order Management +--- + +The *External Order Management* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/order.yml)] diff --git a/docs/docs/api/schema/part.md b/docs/docs/api/schema/part.md new file mode 100644 index 0000000000..67c73eb0fb --- /dev/null +++ b/docs/docs/api/schema/part.md @@ -0,0 +1,7 @@ +--- +title: Parts and Part Categories +--- + +The *Parts and Part Categories* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/part.yml)] diff --git a/docs/docs/api/schema/plugins.md b/docs/docs/api/schema/plugins.md new file mode 100644 index 0000000000..ee0263cffa --- /dev/null +++ b/docs/docs/api/schema/plugins.md @@ -0,0 +1,7 @@ +--- +title: Plugin Functionality +--- + +The *Plugin Functionality* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/plugins.yml)] diff --git a/docs/docs/api/schema/report.md b/docs/docs/api/schema/report.md new file mode 100644 index 0000000000..dfad6d74be --- /dev/null +++ b/docs/docs/api/schema/report.md @@ -0,0 +1,7 @@ +--- +title: Report Generation +--- + +The *Report Generation* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/report.yml)] diff --git a/docs/docs/api/schema/settings.md b/docs/docs/api/schema/settings.md new file mode 100644 index 0000000000..4a6d4f4337 --- /dev/null +++ b/docs/docs/api/schema/settings.md @@ -0,0 +1,7 @@ +--- +title: Settings Management +--- + +The *Settings Management* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/settings.yml)] diff --git a/docs/docs/api/schema/stock.md b/docs/docs/api/schema/stock.md new file mode 100644 index 0000000000..7b961e4b5b --- /dev/null +++ b/docs/docs/api/schema/stock.md @@ -0,0 +1,7 @@ +--- +title: Stock and Stock Locations +--- + +The *Stock and Stock Locations* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/stock.yml)] diff --git a/docs/docs/api/schema/user.md b/docs/docs/api/schema/user.md new file mode 100644 index 0000000000..e0ebba2770 --- /dev/null +++ b/docs/docs/api/schema/user.md @@ -0,0 +1,7 @@ +--- +title: User Management +--- + +The *User Management* section of the InvenTree API schema is documented below. + +[OAD(./docs/docs/api/schema/user.yml)] diff --git a/docs/docs/concepts/units.md b/docs/docs/concepts/units.md index d65d122bc5..b15d4e40f1 100644 --- a/docs/docs/concepts/units.md +++ b/docs/docs/concepts/units.md @@ -48,7 +48,7 @@ The [unit of measure](../part/part.md#units-of-measure) field for the [Part](../ ### Supplier Part -The [supplier part](../part/part/#supplier-parts) model uses real-world units to convert between supplier part quantities and internal stock quantities. Unit conversion rules ensure that only compatible unit types can be supplied +The [supplier part](../part/part.md/#supplier-parts) model uses real-world units to convert between supplier part quantities and internal stock quantities. Unit conversion rules ensure that only compatible unit types can be supplied ### Part Parameter diff --git a/docs/docs/extend/plugins/tags.md b/docs/docs/extend/plugins/tags.md index ebcfdc3502..c7853e0baa 100644 --- a/docs/docs/extend/plugins/tags.md +++ b/docs/docs/extend/plugins/tags.md @@ -8,7 +8,7 @@ Several models in InvenTree can be tagged with arbitrary tags. Tags are useful f Tags are shared between all models that can be tagged. The following models can be tagged: -- [Parts](../../part/part.md) and [Supplier Parts](../../order/company#supplier-parts)/[Manufacturer Part](../../order/company#manufacturer-parts) +- [Parts](../../part/part.md) and [Supplier Parts](../../order/company.md#supplier-parts)/[Manufacturer Part](../../order/company.md#manufacturer-parts) - [Stock Items](../../stock/stock.md#stock-item) / [Stock Location](../../stock/stock.md#stock-location) diff --git a/docs/docs/part/create.md b/docs/docs/part/create.md index 0eab451789..46750fbd67 100644 --- a/docs/docs/part/create.md +++ b/docs/docs/part/create.md @@ -64,6 +64,6 @@ If the *Add Supplier Data* option is checked, then supplier part and manufacture The following alternative methods for creating parts are supported: -- [Via the REST API](../../api/api) -- [Using the Python library](../../api/python) -- [Within the Admin interface](../../settings/admin) +- [Via the REST API](../api/api.md) +- [Using the Python library](../api/python/python.md) +- [Within the Admin interface](../settings/admin.md) diff --git a/docs/docs/part/notification.md b/docs/docs/part/notification.md index 48d0bffde9..27aed5a9cd 100644 --- a/docs/docs/part/notification.md +++ b/docs/docs/part/notification.md @@ -7,7 +7,7 @@ title: Part Notifications Users can select to receive notifications when certain events occur. !!! warning "Email Configuration Required" - External notifications require correct [email configuration](../../start/config/#email-settings). They also need to be enabled in the settings under notifications`. + External notifications require correct [email configuration](../start/config.md#email-settings). They also need to be enabled in the settings under notifications`. !!! warning "Valid Email Address" Each user must have a valid email address associated with their account to receive email notifications @@ -50,7 +50,7 @@ Any users who are subscribed to notifications for the part in question will rece ### Build Order Notification -When a new [Build Order](../../build/build/) is created, the InvenTree software checks to see if any of the parts required to complete the order are low on stock. +When a new [Build Order](../build/build.md) is created, the InvenTree software checks to see if any of the parts required to complete the order are low on stock. If there are any parts with low stock, a notification is generated for any users subscribed to notifications for the part being built. diff --git a/docs/docs/part/trackable.md b/docs/docs/part/trackable.md index 55aba96f89..4810c0a94c 100644 --- a/docs/docs/part/trackable.md +++ b/docs/docs/part/trackable.md @@ -2,7 +2,7 @@ title: Trackable Parts --- -Denoting a part as *Trackble* changes the way that [stock items](../../stock/stock) associated with the particular part are handled in the database. A trackable part also has more restrictions imposed by the database scheme. +Denoting a part as *Trackble* changes the way that [stock items](../stock/stock.md) associated with the particular part are handled in the database. A trackable part also has more restrictions imposed by the database scheme. ## Stock Tracking diff --git a/docs/docs/releases/0.1.5.md b/docs/docs/releases/0.1.5.md index 593c68cc39..1199a8e317 100644 --- a/docs/docs/releases/0.1.5.md +++ b/docs/docs/releases/0.1.5.md @@ -24,7 +24,7 @@ Refer to the [build documentation](../build/build.md#overdue-builds) for more in ### Stock Item Expiry -[#1202](https://github.com/inventree/InvenTree/pull/1202) introduces the concept of an *Expiry Date* for Stock Items. For further information, refer to the [expiry documentation](../../stock/expiry). +[#1202](https://github.com/inventree/InvenTree/pull/1202) introduces the concept of an *Expiry Date* for Stock Items. For further information, refer to the [expiry documentation](../stock/expiry.md). ### Stock Ownership diff --git a/docs/docs/releases/0.2.1.md b/docs/docs/releases/0.2.1.md index 036e03ec7b..c992bd7db6 100644 --- a/docs/docs/releases/0.2.1.md +++ b/docs/docs/releases/0.2.1.md @@ -14,7 +14,7 @@ title: Release 0.2.1 !!! warning "Configuration Required" Refer to the [email configuration - options](../../start/config/#email-settings). + options](../start/config.md#email-settings). ### Manufacturer Parts diff --git a/docs/docs/releases/0.6.0.md b/docs/docs/releases/0.6.0.md index 90a0971499..5edd0d2d97 100644 --- a/docs/docs/releases/0.6.0.md +++ b/docs/docs/releases/0.6.0.md @@ -54,7 +54,7 @@ PR [#2119](https://github.com/inventree/InvenTree/pull/2119) adds the ability to ### SSO Support -PR [#2017](https://github.com/inventree/InvenTree/pull/2017) adds support for SSO (single sign on) authentication. SSO integration requires configuration by the system administrator. Refer to the [SSO documentation](../settings/sso) for further information. +PR [#2017](https://github.com/inventree/InvenTree/pull/2017) adds support for SSO (single sign on) authentication. SSO integration requires configuration by the system administrator. Refer to the [SSO documentation](../settings/SSO.md) for further information. ### BOM Substitution @@ -74,7 +74,7 @@ PR [#2208](https://github.com/inventree/InvenTree/pull/2208) provides notificati ### MFA Support -PR [#2221](https://github.com/inventree/InvenTree/pull/2221) adds support for MFA (multi factor authentication). This enables admins to require all users to enable MFA as a second auth step. Refer to the [documentation](../settings/mfa) for further information. +PR [#2221](https://github.com/inventree/InvenTree/pull/2221) adds support for MFA (multi factor authentication). This enables admins to require all users to enable MFA as a second auth step. Refer to the [documentation](../settings/MFA.md) for further information. ### Stock Item Forms PR [#2198](https://github.com/inventree/InvenTree/pull/2198) provides a major refactor of stock item forms, for creating and editing stock items. These forms have been migrated to the REST API, providing a much more responsive user experience. diff --git a/docs/docs/stock/owner.md b/docs/docs/stock/owner.md index 9fe96abb31..e782fe4fda 100644 --- a/docs/docs/stock/owner.md +++ b/docs/docs/stock/owner.md @@ -33,7 +33,7 @@ When selecting an owner, in the drop-down list, groups are annotated with the icon under the location's name then click on "Edit Location". !!! warning - If you cannot see the icon, it means that you do **not** have permissions to edit stock locations. Refer to [the permissions documentation](../../settings/permissions/#roles) and/or contact your InvenTree administrator. + If you cannot see the icon, it means that you do **not** have permissions to edit stock locations. Refer to [the permissions documentation](../settings/permissions.md#roles) and/or contact your InvenTree administrator. In the "Edit Stock Location" form, select the owner and click the "Submit" button: @@ -54,7 +54,7 @@ Setting the owner of stock location will automatically: To specify the owner of a stock item, navigate to the stock item detail page. Click on the icon under the item's name then click on "Edit stock item". !!! warning - If you cannot see the icon, it means that you do **not** have permissions to edit stock items. Refer to [the permissions documentation](../../settings/permissions/#roles) and/or contact your InvenTree administrator. + If you cannot see the icon, it means that you do **not** have permissions to edit stock items. Refer to [the permissions documentation](../settings/permissions.md/#roles) and/or contact your InvenTree administrator. In the "Edit Stock Item" form, select the owner and click the "Save" button: diff --git a/docs/docs/stylesheets/neoteroi-mkdocs.css b/docs/docs/stylesheets/neoteroi-mkdocs.css new file mode 100644 index 0000000000..ee7d53a554 --- /dev/null +++ b/docs/docs/stylesheets/neoteroi-mkdocs.css @@ -0,0 +1,1399 @@ +/** + * All CSS for the neoteroi.projects.gantt extension. + * + * https://github.com/Neoteroi/mkdocs-plugins +**/ +:root { + --nt-color-0: #CD853F; + --nt-color-1: #B22222; + --nt-color-2: #000080; + --nt-color-3: #4B0082; + --nt-color-4: #3CB371; + --nt-color-5: #D2B48C; + --nt-color-6: #FF00FF; + --nt-color-7: #98FB98; + --nt-color-8: #FFEBCD; + --nt-color-9: #2E8B57; + --nt-color-10: #6A5ACD; + --nt-color-11: #48D1CC; + --nt-color-12: #FFA500; + --nt-color-13: #F4A460; + --nt-color-14: #A52A2A; + --nt-color-15: #FFE4C4; + --nt-color-16: #FF4500; + --nt-color-17: #AFEEEE; + --nt-color-18: #FA8072; + --nt-color-19: #2F4F4F; + --nt-color-20: #FFDAB9; + --nt-color-21: #BC8F8F; + --nt-color-22: #FFC0CB; + --nt-color-23: #00FA9A; + --nt-color-24: #F0FFF0; + --nt-color-25: #FFFACD; + --nt-color-26: #F5F5F5; + --nt-color-27: #FF6347; + --nt-color-28: #FFFFF0; + --nt-color-29: #7FFFD4; + --nt-color-30: #E9967A; + --nt-color-31: #7B68EE; + --nt-color-32: #FFF8DC; + --nt-color-33: #0000CD; + --nt-color-34: #D2691E; + --nt-color-35: #708090; + --nt-color-36: #5F9EA0; + --nt-color-37: #008080; + --nt-color-38: #008000; + --nt-color-39: #FFE4E1; + --nt-color-40: #FFFF00; + --nt-color-41: #FFFAF0; + --nt-color-42: #DCDCDC; + --nt-color-43: #ADFF2F; + --nt-color-44: #ADD8E6; + --nt-color-45: #8B008B; + --nt-color-46: #7FFF00; + --nt-color-47: #800000; + --nt-color-48: #20B2AA; + --nt-color-49: #556B2F; + --nt-color-50: #778899; + --nt-color-51: #E6E6FA; + --nt-color-52: #FFFAFA; + --nt-color-53: #FF7F50; + --nt-color-54: #FF0000; + --nt-color-55: #F5DEB3; + --nt-color-56: #008B8B; + --nt-color-57: #66CDAA; + --nt-color-58: #808000; + --nt-color-59: #FAF0E6; + --nt-color-60: #00BFFF; + --nt-color-61: #C71585; + --nt-color-62: #00FFFF; + --nt-color-63: #8B4513; + --nt-color-64: #F0F8FF; + --nt-color-65: #FAEBD7; + --nt-color-66: #8B0000; + --nt-color-67: #4682B4; + --nt-color-68: #F0E68C; + --nt-color-69: #BDB76B; + --nt-color-70: #A0522D; + --nt-color-71: #FAFAD2; + --nt-color-72: #FFD700; + --nt-color-73: #DEB887; + --nt-color-74: #E0FFFF; + --nt-color-75: #8A2BE2; + --nt-color-76: #32CD32; + --nt-color-77: #87CEFA; + --nt-color-78: #00CED1; + --nt-color-79: #696969; + --nt-color-80: #DDA0DD; + --nt-color-81: #EE82EE; + --nt-color-82: #FFB6C1; + --nt-color-83: #8FBC8F; + --nt-color-84: #D8BFD8; + --nt-color-85: #9400D3; + --nt-color-86: #A9A9A9; + --nt-color-87: #FFFFE0; + --nt-color-88: #FFF5EE; + --nt-color-89: #FFF0F5; + --nt-color-90: #FFDEAD; + --nt-color-91: #800080; + --nt-color-92: #B0E0E6; + --nt-color-93: #9932CC; + --nt-color-94: #DAA520; + --nt-color-95: #F0FFFF; + --nt-color-96: #40E0D0; + --nt-color-97: #00FF7F; + --nt-color-98: #006400; + --nt-color-99: #808080; + --nt-color-100: #87CEEB; + --nt-color-101: #0000FF; + --nt-color-102: #6495ED; + --nt-color-103: #FDF5E6; + --nt-color-104: #B8860B; + --nt-color-105: #BA55D3; + --nt-color-106: #C0C0C0; + --nt-color-107: #000000; + --nt-color-108: #F08080; + --nt-color-109: #B0C4DE; + --nt-color-110: #00008B; + --nt-color-111: #6B8E23; + --nt-color-112: #FFE4B5; + --nt-color-113: #FFA07A; + --nt-color-114: #9ACD32; + --nt-color-115: #FFFFFF; + --nt-color-116: #F5F5DC; + --nt-color-117: #90EE90; + --nt-color-118: #1E90FF; + --nt-color-119: #7CFC00; + --nt-color-120: #FF69B4; + --nt-color-121: #F8F8FF; + --nt-color-122: #F5FFFA; + --nt-color-123: #00FF00; + --nt-color-124: #D3D3D3; + --nt-color-125: #DB7093; + --nt-color-126: #DA70D6; + --nt-color-127: #FF1493; + --nt-color-128: #228B22; + --nt-color-129: #FFEFD5; + --nt-color-130: #4169E1; + --nt-color-131: #191970; + --nt-color-132: #9370DB; + --nt-color-133: #483D8B; + --nt-color-134: #FF8C00; + --nt-color-135: #EEE8AA; + --nt-color-136: #CD5C5C; + --nt-color-137: #DC143C; +} + +:root { + --nt-group-0-main: #000000; + --nt-group-0-dark: #FFFFFF; + --nt-group-0-light: #000000; + --nt-group-0-main-bg: #F44336; + --nt-group-0-dark-bg: #BA000D; + --nt-group-0-light-bg: #FF7961; + --nt-group-1-main: #000000; + --nt-group-1-dark: #FFFFFF; + --nt-group-1-light: #000000; + --nt-group-1-main-bg: #E91E63; + --nt-group-1-dark-bg: #B0003A; + --nt-group-1-light-bg: #FF6090; + --nt-group-2-main: #FFFFFF; + --nt-group-2-dark: #FFFFFF; + --nt-group-2-light: #000000; + --nt-group-2-main-bg: #9C27B0; + --nt-group-2-dark-bg: #6A0080; + --nt-group-2-light-bg: #D05CE3; + --nt-group-3-main: #FFFFFF; + --nt-group-3-dark: #FFFFFF; + --nt-group-3-light: #000000; + --nt-group-3-main-bg: #673AB7; + --nt-group-3-dark-bg: #320B86; + --nt-group-3-light-bg: #9A67EA; + --nt-group-4-main: #FFFFFF; + --nt-group-4-dark: #FFFFFF; + --nt-group-4-light: #000000; + --nt-group-4-main-bg: #3F51B5; + --nt-group-4-dark-bg: #002984; + --nt-group-4-light-bg: #757DE8; + --nt-group-5-main: #000000; + --nt-group-5-dark: #FFFFFF; + --nt-group-5-light: #000000; + --nt-group-5-main-bg: #2196F3; + --nt-group-5-dark-bg: #0069C0; + --nt-group-5-light-bg: #6EC6FF; + --nt-group-6-main: #000000; + --nt-group-6-dark: #FFFFFF; + --nt-group-6-light: #000000; + --nt-group-6-main-bg: #03A9F4; + --nt-group-6-dark-bg: #007AC1; + --nt-group-6-light-bg: #67DAFF; + --nt-group-7-main: #000000; + --nt-group-7-dark: #000000; + --nt-group-7-light: #000000; + --nt-group-7-main-bg: #00BCD4; + --nt-group-7-dark-bg: #008BA3; + --nt-group-7-light-bg: #62EFFF; + --nt-group-8-main: #000000; + --nt-group-8-dark: #FFFFFF; + --nt-group-8-light: #000000; + --nt-group-8-main-bg: #009688; + --nt-group-8-dark-bg: #00675B; + --nt-group-8-light-bg: #52C7B8; + --nt-group-9-main: #000000; + --nt-group-9-dark: #FFFFFF; + --nt-group-9-light: #000000; + --nt-group-9-main-bg: #4CAF50; + --nt-group-9-dark-bg: #087F23; + --nt-group-9-light-bg: #80E27E; + --nt-group-10-main: #000000; + --nt-group-10-dark: #000000; + --nt-group-10-light: #000000; + --nt-group-10-main-bg: #8BC34A; + --nt-group-10-dark-bg: #5A9216; + --nt-group-10-light-bg: #BEF67A; + --nt-group-11-main: #000000; + --nt-group-11-dark: #000000; + --nt-group-11-light: #000000; + --nt-group-11-main-bg: #CDDC39; + --nt-group-11-dark-bg: #99AA00; + --nt-group-11-light-bg: #FFFF6E; + --nt-group-12-main: #000000; + --nt-group-12-dark: #000000; + --nt-group-12-light: #000000; + --nt-group-12-main-bg: #FFEB3B; + --nt-group-12-dark-bg: #C8B900; + --nt-group-12-light-bg: #FFFF72; + --nt-group-13-main: #000000; + --nt-group-13-dark: #000000; + --nt-group-13-light: #000000; + --nt-group-13-main-bg: #FFC107; + --nt-group-13-dark-bg: #C79100; + --nt-group-13-light-bg: #FFF350; + --nt-group-14-main: #000000; + --nt-group-14-dark: #000000; + --nt-group-14-light: #000000; + --nt-group-14-main-bg: #FF9800; + --nt-group-14-dark-bg: #C66900; + --nt-group-14-light-bg: #FFC947; + --nt-group-15-main: #000000; + --nt-group-15-dark: #FFFFFF; + --nt-group-15-light: #000000; + --nt-group-15-main-bg: #FF5722; + --nt-group-15-dark-bg: #C41C00; + --nt-group-15-light-bg: #FF8A50; + --nt-group-16-main: #FFFFFF; + --nt-group-16-dark: #FFFFFF; + --nt-group-16-light: #000000; + --nt-group-16-main-bg: #795548; + --nt-group-16-dark-bg: #4B2C20; + --nt-group-16-light-bg: #A98274; + --nt-group-17-main: #000000; + --nt-group-17-dark: #FFFFFF; + --nt-group-17-light: #000000; + --nt-group-17-main-bg: #9E9E9E; + --nt-group-17-dark-bg: #707070; + --nt-group-17-light-bg: #CFCFCF; + --nt-group-18-main: #000000; + --nt-group-18-dark: #FFFFFF; + --nt-group-18-light: #000000; + --nt-group-18-main-bg: #607D8B; + --nt-group-18-dark-bg: #34515E; + --nt-group-18-light-bg: #8EACBB; +} + +.nt-pastello { + --nt-group-0-main: #000000; + --nt-group-0-dark: #000000; + --nt-group-0-light: #000000; + --nt-group-0-main-bg: #EF9A9A; + --nt-group-0-dark-bg: #BA6B6C; + --nt-group-0-light-bg: #FFCCCB; + --nt-group-1-main: #000000; + --nt-group-1-dark: #000000; + --nt-group-1-light: #000000; + --nt-group-1-main-bg: #F48FB1; + --nt-group-1-dark-bg: #BF5F82; + --nt-group-1-light-bg: #FFC1E3; + --nt-group-2-main: #000000; + --nt-group-2-dark: #000000; + --nt-group-2-light: #000000; + --nt-group-2-main-bg: #CE93D8; + --nt-group-2-dark-bg: #9C64A6; + --nt-group-2-light-bg: #FFC4FF; + --nt-group-3-main: #000000; + --nt-group-3-dark: #000000; + --nt-group-3-light: #000000; + --nt-group-3-main-bg: #B39DDB; + --nt-group-3-dark-bg: #836FA9; + --nt-group-3-light-bg: #E6CEFF; + --nt-group-4-main: #000000; + --nt-group-4-dark: #000000; + --nt-group-4-light: #000000; + --nt-group-4-main-bg: #9FA8DA; + --nt-group-4-dark-bg: #6F79A8; + --nt-group-4-light-bg: #D1D9FF; + --nt-group-5-main: #000000; + --nt-group-5-dark: #000000; + --nt-group-5-light: #000000; + --nt-group-5-main-bg: #90CAF9; + --nt-group-5-dark-bg: #5D99C6; + --nt-group-5-light-bg: #C3FDFF; + --nt-group-6-main: #000000; + --nt-group-6-dark: #000000; + --nt-group-6-light: #000000; + --nt-group-6-main-bg: #81D4FA; + --nt-group-6-dark-bg: #4BA3C7; + --nt-group-6-light-bg: #B6FFFF; + --nt-group-7-main: #000000; + --nt-group-7-dark: #000000; + --nt-group-7-light: #000000; + --nt-group-7-main-bg: #80DEEA; + --nt-group-7-dark-bg: #4BACB8; + --nt-group-7-light-bg: #B4FFFF; + --nt-group-8-main: #000000; + --nt-group-8-dark: #000000; + --nt-group-8-light: #000000; + --nt-group-8-main-bg: #80CBC4; + --nt-group-8-dark-bg: #4F9A94; + --nt-group-8-light-bg: #B2FEF7; + --nt-group-9-main: #000000; + --nt-group-9-dark: #000000; + --nt-group-9-light: #000000; + --nt-group-9-main-bg: #A5D6A7; + --nt-group-9-dark-bg: #75A478; + --nt-group-9-light-bg: #D7FFD9; + --nt-group-10-main: #000000; + --nt-group-10-dark: #000000; + --nt-group-10-light: #000000; + --nt-group-10-main-bg: #C5E1A5; + --nt-group-10-dark-bg: #94AF76; + --nt-group-10-light-bg: #F8FFD7; + --nt-group-11-main: #000000; + --nt-group-11-dark: #000000; + --nt-group-11-light: #000000; + --nt-group-11-main-bg: #E6EE9C; + --nt-group-11-dark-bg: #B3BC6D; + --nt-group-11-light-bg: #FFFFCE; + --nt-group-12-main: #000000; + --nt-group-12-dark: #000000; + --nt-group-12-light: #000000; + --nt-group-12-main-bg: #FFF59D; + --nt-group-12-dark-bg: #CBC26D; + --nt-group-12-light-bg: #FFFFCF; + --nt-group-13-main: #000000; + --nt-group-13-dark: #000000; + --nt-group-13-light: #000000; + --nt-group-13-main-bg: #FFE082; + --nt-group-13-dark-bg: #CAAE53; + --nt-group-13-light-bg: #FFFFB3; + --nt-group-14-main: #000000; + --nt-group-14-dark: #000000; + --nt-group-14-light: #000000; + --nt-group-14-main-bg: #FFCC80; + --nt-group-14-dark-bg: #CA9B52; + --nt-group-14-light-bg: #FFFFB0; + --nt-group-15-main: #000000; + --nt-group-15-dark: #000000; + --nt-group-15-light: #000000; + --nt-group-15-main-bg: #FFAB91; + --nt-group-15-dark-bg: #C97B63; + --nt-group-15-light-bg: #FFDDC1; + --nt-group-16-main: #000000; + --nt-group-16-dark: #000000; + --nt-group-16-light: #000000; + --nt-group-16-main-bg: #BCAAA4; + --nt-group-16-dark-bg: #8C7B75; + --nt-group-16-light-bg: #EFDCD5; + --nt-group-17-main: #000000; + --nt-group-17-dark: #000000; + --nt-group-17-light: #000000; + --nt-group-17-main-bg: #EEEEEE; + --nt-group-17-dark-bg: #BCBCBC; + --nt-group-17-light-bg: #FFFFFF; + --nt-group-18-main: #000000; + --nt-group-18-dark: #000000; + --nt-group-18-light: #000000; + --nt-group-18-main-bg: #B0BEC5; + --nt-group-18-dark-bg: #808E95; + --nt-group-18-light-bg: #E2F1F8; +} + +.nt-group-0 .nt-plan-group-summary, +.nt-group-0 .nt-timeline-dot { + color: var(--nt-group-0-dark); + background-color: var(--nt-group-0-dark-bg); +} +.nt-group-0 .period { + color: var(--nt-group-0-main); + background-color: var(--nt-group-0-main-bg); +} + +.nt-group-1 .nt-plan-group-summary, +.nt-group-1 .nt-timeline-dot { + color: var(--nt-group-1-dark); + background-color: var(--nt-group-1-dark-bg); +} +.nt-group-1 .period { + color: var(--nt-group-1-main); + background-color: var(--nt-group-1-main-bg); +} + +.nt-group-2 .nt-plan-group-summary, +.nt-group-2 .nt-timeline-dot { + color: var(--nt-group-2-dark); + background-color: var(--nt-group-2-dark-bg); +} +.nt-group-2 .period { + color: var(--nt-group-2-main); + background-color: var(--nt-group-2-main-bg); +} + +.nt-group-3 .nt-plan-group-summary, +.nt-group-3 .nt-timeline-dot { + color: var(--nt-group-3-dark); + background-color: var(--nt-group-3-dark-bg); +} +.nt-group-3 .period { + color: var(--nt-group-3-main); + background-color: var(--nt-group-3-main-bg); +} + +.nt-group-4 .nt-plan-group-summary, +.nt-group-4 .nt-timeline-dot { + color: var(--nt-group-4-dark); + background-color: var(--nt-group-4-dark-bg); +} +.nt-group-4 .period { + color: var(--nt-group-4-main); + background-color: var(--nt-group-4-main-bg); +} + +.nt-group-5 .nt-plan-group-summary, +.nt-group-5 .nt-timeline-dot { + color: var(--nt-group-5-dark); + background-color: var(--nt-group-5-dark-bg); +} +.nt-group-5 .period { + color: var(--nt-group-5-main); + background-color: var(--nt-group-5-main-bg); +} + +.nt-group-6 .nt-plan-group-summary, +.nt-group-6 .nt-timeline-dot { + color: var(--nt-group-6-dark); + background-color: var(--nt-group-6-dark-bg); +} +.nt-group-6 .period { + color: var(--nt-group-6-main); + background-color: var(--nt-group-6-main-bg); +} + +.nt-group-7 .nt-plan-group-summary, +.nt-group-7 .nt-timeline-dot { + color: var(--nt-group-7-dark); + background-color: var(--nt-group-7-dark-bg); +} +.nt-group-7 .period { + color: var(--nt-group-7-main); + background-color: var(--nt-group-7-main-bg); +} + +.nt-group-8 .nt-plan-group-summary, +.nt-group-8 .nt-timeline-dot { + color: var(--nt-group-8-dark); + background-color: var(--nt-group-8-dark-bg); +} +.nt-group-8 .period { + color: var(--nt-group-8-main); + background-color: var(--nt-group-8-main-bg); +} + +.nt-group-9 .nt-plan-group-summary, +.nt-group-9 .nt-timeline-dot { + color: var(--nt-group-9-dark); + background-color: var(--nt-group-9-dark-bg); +} +.nt-group-9 .period { + color: var(--nt-group-9-main); + background-color: var(--nt-group-9-main-bg); +} + +.nt-group-10 .nt-plan-group-summary, +.nt-group-10 .nt-timeline-dot { + color: var(--nt-group-10-dark); + background-color: var(--nt-group-10-dark-bg); +} +.nt-group-10 .period { + color: var(--nt-group-10-main); + background-color: var(--nt-group-10-main-bg); +} + +.nt-group-11 .nt-plan-group-summary, +.nt-group-11 .nt-timeline-dot { + color: var(--nt-group-11-dark); + background-color: var(--nt-group-11-dark-bg); +} +.nt-group-11 .period { + color: var(--nt-group-11-main); + background-color: var(--nt-group-11-main-bg); +} + +.nt-group-12 .nt-plan-group-summary, +.nt-group-12 .nt-timeline-dot { + color: var(--nt-group-12-dark); + background-color: var(--nt-group-12-dark-bg); +} +.nt-group-12 .period { + color: var(--nt-group-12-main); + background-color: var(--nt-group-12-main-bg); +} + +.nt-group-13 .nt-plan-group-summary, +.nt-group-13 .nt-timeline-dot { + color: var(--nt-group-13-dark); + background-color: var(--nt-group-13-dark-bg); +} +.nt-group-13 .period { + color: var(--nt-group-13-main); + background-color: var(--nt-group-13-main-bg); +} + +.nt-group-14 .nt-plan-group-summary, +.nt-group-14 .nt-timeline-dot { + color: var(--nt-group-14-dark); + background-color: var(--nt-group-14-dark-bg); +} +.nt-group-14 .period { + color: var(--nt-group-14-main); + background-color: var(--nt-group-14-main-bg); +} + +.nt-group-15 .nt-plan-group-summary, +.nt-group-15 .nt-timeline-dot { + color: var(--nt-group-15-dark); + background-color: var(--nt-group-15-dark-bg); +} +.nt-group-15 .period { + color: var(--nt-group-15-main); + background-color: var(--nt-group-15-main-bg); +} + +.nt-group-16 .nt-plan-group-summary, +.nt-group-16 .nt-timeline-dot { + color: var(--nt-group-16-dark); + background-color: var(--nt-group-16-dark-bg); +} +.nt-group-16 .period { + color: var(--nt-group-16-main); + background-color: var(--nt-group-16-main-bg); +} + +.nt-group-17 .nt-plan-group-summary, +.nt-group-17 .nt-timeline-dot { + color: var(--nt-group-17-dark); + background-color: var(--nt-group-17-dark-bg); +} +.nt-group-17 .period { + color: var(--nt-group-17-main); + background-color: var(--nt-group-17-main-bg); +} + +.nt-group-18 .nt-plan-group-summary, +.nt-group-18 .nt-timeline-dot { + color: var(--nt-group-18-dark); + background-color: var(--nt-group-18-dark-bg); +} +.nt-group-18 .period { + color: var(--nt-group-18-main); + background-color: var(--nt-group-18-main-bg); +} + +/** + * Extra CSS file for MkDocs and the neoteroi.timeline extension. + * + * https://github.com/Neoteroi/mkdocs-plugins +**/ +.nt-error { + border: 2px dashed darkred; + padding: 0 1rem; + background: #faf9ba; + color: darkred; +} + +.nt-timeline { + margin-top: 30px; +} +.nt-timeline .nt-timeline-title { + font-size: 1.1rem; + margin-top: 0; +} +.nt-timeline .nt-timeline-sub-title { + margin-top: 0; +} +.nt-timeline .nt-timeline-content { + font-size: 0.8rem; + border-bottom: 2px dashed #ccc; + padding-bottom: 1.2rem; +} +.nt-timeline.horizontal .nt-timeline-items { + flex-direction: row; + overflow-x: scroll; +} +.nt-timeline.horizontal .nt-timeline-items > div { + min-width: 400px; + margin-right: 50px; +} +.nt-timeline.horizontal.reverse .nt-timeline-items { + flex-direction: row-reverse; +} +.nt-timeline.horizontal.center .nt-timeline-before { + background-image: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%); + background-repeat: no-repeat; + background-size: 100% 2px; + background-position: 0 center; +} +.nt-timeline.horizontal.center .nt-timeline-after { + background-image: linear-gradient(180deg, rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%); + background-repeat: no-repeat; + background-size: 100% 2px; + background-position: 0 center; +} +.nt-timeline.horizontal.center .nt-timeline-items { + background-image: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%); + background-repeat: no-repeat; + background-size: 100% 2px; + background-position: 0 center; +} +.nt-timeline.horizontal .nt-timeline-dot { + left: 50%; +} +.nt-timeline.horizontal .nt-timeline-dot:not(.bigger) { + top: calc(50% - 4px); +} +.nt-timeline.horizontal .nt-timeline-dot.bigger { + top: calc(50% - 15px); +} +.nt-timeline.vertical .nt-timeline-items { + flex-direction: column; +} +.nt-timeline.vertical.reverse .nt-timeline-items { + flex-direction: column-reverse; +} +.nt-timeline.vertical.center .nt-timeline-before { + background: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%; +} +.nt-timeline.vertical.center .nt-timeline-after { + background: linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat center/2px 100%; +} +.nt-timeline.vertical.center .nt-timeline-items { + background: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat center/2px 100%; +} +.nt-timeline.vertical.center .nt-timeline-dot { + left: calc(50% - 10px); +} +.nt-timeline.vertical.center .nt-timeline-dot:not(.bigger) { + top: 10px; +} +.nt-timeline.vertical.center .nt-timeline-dot.bigger { + left: calc(50% - 20px); +} +.nt-timeline.vertical.left { + padding-left: 100px; +} +.nt-timeline.vertical.left .nt-timeline-item { + padding-left: 70px; +} +.nt-timeline.vertical.left .nt-timeline-sub-title { + left: -100px; + width: 100px; +} +.nt-timeline.vertical.left .nt-timeline-before { + background: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%; +} +.nt-timeline.vertical.left .nt-timeline-after { + background: linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat 30px/2px 100%; +} +.nt-timeline.vertical.left .nt-timeline-items { + background: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat 30px/2px 100%; +} +.nt-timeline.vertical.left .nt-timeline-dot { + left: 21px; + top: 8px; +} +.nt-timeline.vertical.left .nt-timeline-dot.bigger { + top: 0px; + left: 10px; +} +.nt-timeline.vertical.right { + padding-right: 100px; +} +.nt-timeline.vertical.right .nt-timeline-sub-title { + right: -100px; + text-align: left; + width: 100px; +} +.nt-timeline.vertical.right .nt-timeline-item { + padding-right: 70px; +} +.nt-timeline.vertical.right .nt-timeline-before { + background: linear-gradient(rgba(252, 70, 107, 0) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%; +} +.nt-timeline.vertical.right .nt-timeline-after { + background: linear-gradient(rgb(252, 70, 107) 0%, rgba(252, 70, 107, 0) 100%) no-repeat calc(100% - 30px)/2px 100%; +} +.nt-timeline.vertical.right .nt-timeline-items { + background: radial-gradient(circle, rgb(63, 94, 251) 0%, rgb(252, 70, 107) 100%) no-repeat calc(100% - 30px)/2px 100%; +} +.nt-timeline.vertical.right .nt-timeline-dot { + right: 21px; + top: 8px; +} +.nt-timeline.vertical.right .nt-timeline-dot.bigger { + top: 10px; + right: 10px; +} + +.nt-timeline-items { + display: flex; + position: relative; +} +.nt-timeline-items > div { + min-height: 100px; + padding-top: 2px; + padding-bottom: 20px; +} + +.nt-timeline-before { + content: ""; + height: 15px; +} + +.nt-timeline-after { + content: ""; + height: 60px; + margin-bottom: 20px; +} + +.nt-timeline-sub-title { + position: absolute; + width: 50%; + top: 4px; + font-size: 18px; + color: var(--nt-color-50); +} + +[data-md-color-scheme=slate] .nt-timeline-sub-title { + color: var(--nt-color-51); +} + +.nt-timeline-item { + position: relative; +} + +.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item { + padding-left: calc(50% + 40px); +} +.nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title { + left: 0; + padding-right: 40px; + text-align: right; +} +.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) { + padding-left: calc(50% + 40px); +} +.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title { + left: 0; + padding-right: 40px; + text-align: right; +} +.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) { + text-align: right; + padding-right: calc(50% + 40px); +} +.nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title { + right: 0; + padding-left: 40px; + text-align: left; +} + +.nt-timeline-dot { + position: relative; + width: 20px; + height: 20px; + border-radius: 100%; + background-color: #fc5b5b; + position: absolute; + top: 0px; + z-index: 2; + display: flex; + justify-content: center; + align-items: center; + box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12); + border: 3px solid white; +} +.nt-timeline-dot:not(.bigger) .icon { + font-size: 10px; +} +.nt-timeline-dot.bigger { + width: 40px; + height: 40px; + padding: 3px; +} +.nt-timeline-dot .icon { + color: white; +} + +/* Fix for webkit (Chrome, Safari) */ +@supports not (-moz-appearance: none) { + /* + This fix is necessary, for some reason, to render the timeline properly + inside `details` elements used by pymdownx. Firefox doesn't need this fix, + it renders elements properly. + */ + details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(odd) .nt-timeline-sub-title, +details .nt-timeline.vertical.center:not(.alternate) .nt-timeline-item .nt-timeline-sub-title { + left: -40px; + } + details .nt-timeline.vertical.center.alternate .nt-timeline-item:nth-child(even) .nt-timeline-sub-title { + right: -40px; + } + details .nt-timeline.vertical.center .nt-timeline-dot { + left: calc(50% - 12px); + } + details .nt-timeline-dot.bigger { + font-size: 1rem !important; + } +} +/* default colors */ +.nt-timeline-item:nth-child(0) .nt-timeline-dot { + background-color: var(--nt-color-0); +} + +.nt-timeline-item:nth-child(1) .nt-timeline-dot { + background-color: var(--nt-color-1); +} + +.nt-timeline-item:nth-child(2) .nt-timeline-dot { + background-color: var(--nt-color-2); +} + +.nt-timeline-item:nth-child(3) .nt-timeline-dot { + background-color: var(--nt-color-3); +} + +.nt-timeline-item:nth-child(4) .nt-timeline-dot { + background-color: var(--nt-color-4); +} + +.nt-timeline-item:nth-child(5) .nt-timeline-dot { + background-color: var(--nt-color-5); +} + +.nt-timeline-item:nth-child(6) .nt-timeline-dot { + background-color: var(--nt-color-6); +} + +.nt-timeline-item:nth-child(7) .nt-timeline-dot { + background-color: var(--nt-color-7); +} + +.nt-timeline-item:nth-child(8) .nt-timeline-dot { + background-color: var(--nt-color-8); +} + +.nt-timeline-item:nth-child(9) .nt-timeline-dot { + background-color: var(--nt-color-9); +} + +.nt-timeline-item:nth-child(10) .nt-timeline-dot { + background-color: var(--nt-color-10); +} + +.nt-timeline-item:nth-child(11) .nt-timeline-dot { + background-color: var(--nt-color-11); +} + +.nt-timeline-item:nth-child(12) .nt-timeline-dot { + background-color: var(--nt-color-12); +} + +.nt-timeline-item:nth-child(13) .nt-timeline-dot { + background-color: var(--nt-color-13); +} + +.nt-timeline-item:nth-child(14) .nt-timeline-dot { + background-color: var(--nt-color-14); +} + +.nt-timeline-item:nth-child(15) .nt-timeline-dot { + background-color: var(--nt-color-15); +} + +.nt-timeline-item:nth-child(16) .nt-timeline-dot { + background-color: var(--nt-color-16); +} + +.nt-timeline-item:nth-child(17) .nt-timeline-dot { + background-color: var(--nt-color-17); +} + +.nt-timeline-item:nth-child(18) .nt-timeline-dot { + background-color: var(--nt-color-18); +} + +.nt-timeline-item:nth-child(19) .nt-timeline-dot { + background-color: var(--nt-color-19); +} + +.nt-timeline-item:nth-child(20) .nt-timeline-dot { + background-color: var(--nt-color-20); +} + +/** + * Extra CSS for the neoteroi.projects.gantt extension. + * + * https://github.com/Neoteroi/mkdocs-plugins +**/ +:root { + --nt-scrollbar-color: #2751b0; + --nt-plan-actions-height: 24px; + --nt-units-background: #ff9800; + --nt-months-background: #2751b0; + --nt-plan-vertical-line-color: #a3a3a3ad; +} + +.nt-pastello { + --nt-scrollbar-color: #9fb8f4; + --nt-units-background: #f5dc82; + --nt-months-background: #5b7fd1; +} + +[data-md-color-scheme=slate] { + --nt-units-background: #003773; +} +[data-md-color-scheme=slate] .nt-pastello { + --nt-units-background: #3f4997; +} + +.nt-plan-root { + min-height: 200px; + scrollbar-width: 20px; + scrollbar-color: var(--nt-scrollbar-color); + display: flex; +} +.nt-plan-root ::-webkit-scrollbar { + width: 20px; +} +.nt-plan-root ::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px grey; + border-radius: 10px; +} +.nt-plan-root ::-webkit-scrollbar-thumb { + background: var(--nt-scrollbar-color); + border-radius: 10px; +} +.nt-plan-root .nt-plan { + flex: 80%; +} +.nt-plan-root.no-groups .nt-plan-periods { + padding-left: 0; +} +.nt-plan-root.no-groups .nt-plan-group-summary { + display: none; +} +.nt-plan-root .nt-timeline-dot.bigger { + top: -10px; +} +.nt-plan-root .nt-timeline-dot.bigger[title] { + cursor: help; +} + +.nt-plan { + white-space: nowrap; + overflow-x: auto; + display: flex; +} +.nt-plan .ug-timeline-dot { + left: 368px; + top: -8px; + cursor: help; +} + +.months { + display: flex; +} + +.month { + flex: auto; + display: inline-block; + box-shadow: rgba(0, 0, 0, 0.2) 0px 3px 1px -2px, rgba(0, 0, 0, 0.14) 0px 2px 2px 0px, rgba(0, 0, 0, 0.12) 0px 1px 5px 0px inset; + background-color: var(--nt-months-background); + color: white; + text-transform: uppercase; + font-family: Roboto, Helvetica, Arial, sans-serif; + padding: 2px 5px; + font-size: 12px; + border: 1px solid #000; + width: 150px; + border-radius: 8px; +} + +.nt-plan-group-activities { + flex: auto; + position: relative; +} + +.nt-vline { + border-left: 1px dashed var(--nt-plan-vertical-line-color); + height: 100%; + left: 0; + position: absolute; + margin-left: -0.5px; + top: 0; + -webkit-transition: all 0.5s linear !important; + -moz-transition: all 0.5s linear !important; + -ms-transition: all 0.5s linear !important; + -o-transition: all 0.5s linear !important; + transition: all 0.5s linear !important; + z-index: -2; +} + +.nt-plan-activity { + display: flex; + margin: 2px 0; + background-color: rgba(187, 187, 187, 0.2509803922); +} + +.actions { + height: var(--nt-plan-actions-height); +} + +.actions { + position: relative; +} + +.period { + display: inline-block; + height: var(--nt-plan-actions-height); + width: 120px; + position: absolute; + left: 0px; + background: #1da1f2; + border-radius: 5px; + transition: all 0.5s; + cursor: help; + -webkit-transition: width 1s ease-in-out; + -moz-transition: width 1s ease-in-out; + -o-transition: width 1s ease-in-out; + transition: width 1s ease-in-out; +} +.period .nt-tooltip { + display: none; + top: 30px; + position: relative; + padding: 1rem; + text-align: center; + font-size: 12px; +} +.period:hover .nt-tooltip { + display: inline-block; +} + +.period-0 { + left: 340px; + visibility: visible; + background-color: rgb(69, 97, 101); +} + +.period-1 { + left: 40px; + visibility: visible; + background-color: green; +} + +.period-2 { + left: 120px; + visibility: visible; + background-color: pink; + width: 80px; +} + +.period-3 { + left: 190px; + visibility: visible; + background-color: darkred; + width: 150px; +} + +.weeks > span, +.days > span { + height: 25px; +} + +.weeks > span { + display: inline-block; + margin: 0; + padding: 0; + font-weight: bold; +} +.weeks > span .week-text { + font-size: 10px; + position: absolute; + display: inline-block; + padding: 3px 4px; +} + +.days { + z-index: -2; + position: relative; +} + +.day-text { + font-size: 10px; + position: absolute; + display: inline-block; + padding: 3px 4px; +} + +.period span { + font-size: 12px; + vertical-align: top; + margin-left: 4px; + color: black; + background: rgba(255, 255, 255, 0.6588235294); + border-radius: 6px; + padding: 0 4px; +} + +.weeks, +.days { + height: 20px; + display: flex; + box-sizing: content-box; +} + +.months { + display: flex; +} + +.week, +.day { + height: 20px; + position: relative; + border: 1; + flex: auto; + border: 2px solid white; + border-radius: 4px; + background-color: var(--nt-units-background); + cursor: help; +} + +.years { + display: flex; +} + +.year { + text-align: center; + border-right: 1px solid var(--nt-plan-vertical-line-color); + font-weight: bold; +} +.year:first-child { + border-left: 1px solid var(--nt-plan-vertical-line-color); +} +.year:first-child:last-child { + width: 100%; +} + +.quarters { + display: flex; +} + +.quarter { + width: 12.5%; + text-align: center; + border-right: 1px solid var(--nt-plan-vertical-line-color); + font-weight: bold; +} +.quarter:first-child { + border-left: 1px solid var(--nt-plan-vertical-line-color); +} + +.nt-plan-group { + margin: 20px 0; + position: relative; +} + +.nt-plan-group { + display: flex; +} + +.nt-plan-group-summary { + background: #2751b0; + width: 150px; + white-space: normal; + padding: 0.1rem 0.5rem; + border-radius: 5px; + color: #fff; + z-index: 3; +} +.nt-plan-group-summary p { + margin: 0; + padding: 0; + font-size: 0.6rem; + color: #fff; +} + +.nt-plan-group-summary, +.month, +.period, +.week, +.day, +.nt-tooltip { + border: 3px solid white; + box-shadow: 0 2px 3px -1px rgba(0, 0, 0, 0.2), 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12); +} + +.nt-plan-periods { + padding-left: 150px; +} + +.months { + z-index: 2; + position: relative; +} + +.weeks { + position: relative; + top: -2px; + z-index: 0; +} + +.month, +.quarter, +.year, +.week, +.day, +.nt-tooltip { + font-family: Roboto, Helvetica, Arial, sans-serif; + box-sizing: border-box; +} + +.nt-cards.nt-grid { + display: grid; + grid-auto-columns: 1fr; + gap: 0.5rem; + max-width: 100vw; + overflow-x: auto; + padding: 1px; +} +.nt-cards.nt-grid.cols-1 { + grid-template-columns: repeat(1, 1fr); +} +.nt-cards.nt-grid.cols-2 { + grid-template-columns: repeat(2, 1fr); +} +.nt-cards.nt-grid.cols-3 { + grid-template-columns: repeat(3, 1fr); +} +.nt-cards.nt-grid.cols-4 { + grid-template-columns: repeat(4, 1fr); +} +.nt-cards.nt-grid.cols-5 { + grid-template-columns: repeat(5, 1fr); +} +.nt-cards.nt-grid.cols-6 { + grid-template-columns: repeat(6, 1fr); +} + +@media only screen and (max-width: 400px) { + .nt-cards.nt-grid { + grid-template-columns: repeat(1, 1fr) !important; + } +} +.nt-card { + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); +} +.nt-card:hover { + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 3px 1px -2px rgba(0, 0, 0, 0.3), 0 1px 5px 0 rgba(0, 0, 0, 0.22); +} + +[data-md-color-scheme=slate] .nt-card { + box-shadow: 0 2px 2px 0 rgba(4, 40, 33, 0.14), 0 3px 1px -2px rgba(40, 86, 94, 0.47), 0 1px 5px 0 rgba(139, 252, 255, 0.64); +} +[data-md-color-scheme=slate] .nt-card:hover { + box-shadow: 0 2px 2px 0 rgba(0, 255, 206, 0.14), 0 3px 1px -2px rgba(33, 156, 177, 0.47), 0 1px 5px 0 rgba(96, 251, 255, 0.64); +} + +.nt-card > a { + color: var(--md-default-fg-color); +} + +.nt-card > a > div { + cursor: pointer; +} + +.nt-card { + padding: 5px; + margin-bottom: 0.5rem; +} + +.nt-card-title { + font-size: 1rem; + font-weight: bold; + margin: 4px 0 8px 0; + line-height: 22px; +} + +.nt-card-content { + padding: 0.4rem 0.8rem 0.8rem 0.8rem; +} + +.nt-card-text { + font-size: 14px; + padding: 0; + margin: 0; +} + +.nt-card .nt-card-image { + text-align: center; + border-radius: 2px; + background-position: center center; + background-size: cover; + background-repeat: no-repeat; + min-height: 120px; +} + +.nt-card .nt-card-image.tags img { + margin-top: 12px; +} + +.nt-card .nt-card-image img { + height: 105px; + margin-top: 5px; +} + +.nt-card a:hover, +.nt-card a:focus { + color: var(--md-accent-fg-color); +} + +.nt-card h2 { + margin: 0; +} + +/** + * Extra CSS file recommended for MkDocs and neoteroi.spantable extension. + * + * https://github.com/Neoteroi/mkdocs-plugins +**/ +.span-table-wrapper table { + border-collapse: collapse; + margin-bottom: 2rem; + border-radius: 0.1rem; +} + +.span-table td, +.span-table th { + padding: 0.2rem; + background-color: var(--md-default-bg-color); + font-size: 0.64rem; + max-width: 100%; + overflow: auto; + touch-action: auto; + border-top: 0.05rem solid var(--md-typeset-table-color); + padding: 0.9375em 1.25em; + vertical-align: top; +} + +.span-table tr:first-child td { + font-weight: 700; + min-width: 5rem; + padding: 0.9375em 1.25em; + vertical-align: top; +} + +.span-table td:first-child { + border-left: 0.05rem solid var(--md-typeset-table-color); +} + +.span-table td:last-child { + border-right: 0.05rem solid var(--md-typeset-table-color); +} + +.span-table tr:last-child { + border-bottom: 0.05rem solid var(--md-typeset-table-color); +} + +.span-table [colspan], +.span-table [rowspan] { + font-weight: bold; + border: 0.05rem solid var(--md-typeset-table-color); +} + +.span-table tr:not(:first-child):hover td:not([colspan]):not([rowspan]), +.span-table td[colspan]:hover, +.span-table td[rowspan]:hover { + background-color: rgba(0, 0, 0, 0.035); + box-shadow: 0 0.05rem 0 var(--md-default-bg-color) inset; + transition: background-color 125ms; +} diff --git a/docs/extract_schema.py b/docs/extract_schema.py new file mode 100644 index 0000000000..95f99d0c66 --- /dev/null +++ b/docs/extract_schema.py @@ -0,0 +1,232 @@ +"""Extract API schema and split into smaller subsections.""" + +import argparse +import os +import re +import textwrap + +import yaml + +OUTPUT_DIR = './docs/api/schema/' + +# General path +GENERAL_PATH = 'general' + +# List of special paths we want to split out +SPECIAL_PATHS = { + 'auth': 'Authorization and Authentication', + 'background-task': 'Background Task Management', + 'barcode': 'Barcode Scanning', + 'bom': 'Bill of Materials', + 'build': 'Build Order Management', + 'company': 'Company Management', + 'label': 'Label Printing', + 'machine': 'External Machine Management', + 'order': 'External Order Management', + 'part': 'Parts and Part Categories', + 'plugins': 'Plugin Functionality', + 'report': 'Report Generation', + 'settings': 'Settings Management', + 'stock': 'Stock and Stock Locations', + 'user': 'User Management', +} + + +def top_level_path(path: str) -> str: + """Return the top level path of the input path.""" + path = path.strip() + + if path.startswith('/'): + path = path[1:] + + if path.endswith('/'): + path = path[:-1] + + path = path.strip() + + key = path.split('/')[1] + + if key in SPECIAL_PATHS.keys(): + return key + + return GENERAL_PATH + + +def generate_schema_file(key: str) -> None: + """Generate a schema file for the provided key.""" + description = ( + SPECIAL_PATHS[key] if key in SPECIAL_PATHS else 'General API Endpoints' + ) + + output = f""" + --- + title: {description} + --- + + The *{description}* section of the InvenTree API schema is documented below. + + [OAD(./docs/docs/api/schema/{key}.yml)] + """ + + output = textwrap.dedent(output).strip() + '\n' + + output_file = os.path.join(os.path.dirname(__file__), OUTPUT_DIR, f'{key}.md') + output_file = os.path.abspath(output_file) + + print('Writing schema file to:', output_file) + + with open(output_file, 'w') as f: + f.write(output) + + +def generate_index_file(version: str): + """Generate the index file for the API schema.""" + output = f""" + --- + title: InvenTree API Schema + --- + + The InvenTree API is implemented using the [Django REST framework](https://www.django-rest-framework.org). + The API schema as documented below is generated using the [drf-spectactular](https://github.com/tfranzel/drf-spectacular/) extension. + + ## API Version + + This documentation is for API version: `{version}` + + !!! tip "API Schema History" + We track API schema changes, and provide a snapshot of each API schema version in the [API schema repository](https://github.com/inventree/schema/). + + ## API Schema File + + The API schema file is available for download, and can be used for generating client libraries, or for testing API endpoints. + + ## API Schema Documentation + + API schema documentation is split into the following categories: + + | Category | Description | + | --- | --- | + """ + + output = textwrap.dedent(output).strip() + '\n' + + for key, value in SPECIAL_PATHS.items(): + output += f'| [{value}](./schema/{key}.md) | {value} |\n' + + output += '| [General](./schema/general.md) | General API endpoints |\n' + + output += '\n' + + output_file = os.path.join(os.path.dirname(__file__), OUTPUT_DIR, '..', 'schema.md') + + print('Writing index file to:', output_file) + + with open(output_file, 'w') as f: + f.write(output) + + +def extract_refs(data: dict, components: dict) -> list: + """Extract a list of refs from the provided paths dict. + + The refs are located like so: + ::responses::content:application/json:schema:$ref + + Also, the referenced components might reference *sub* components, + so we need to do this step recursively. + + """ + pattern = r"'?\$ref'?: '#\/components\/schemas\/(\S+)'" + + # First, extract the results from the paths data dict + matches = re.findall(pattern, str(data)) + + refs = list(matches) + + # Next, extract additional refs from the components dict + # Note that the components dict may reference other components + + idx = 0 + + while idx < len(refs): + ref = refs[idx] + + schema = components.get('schemas', {}).get(ref, None) + + if schema: + # Search for additional refs + matches = re.findall(pattern, str(schema)) + + for match in matches: + if match not in refs: + refs.append(match) + + idx += 1 + + # Return a dict only of the extracted refs + schemas = {ref: components['schemas'][ref] for ref in refs} + + return schemas + + +def parse_api_file(filename: str): + """Parse the input API file, and split into smaller sections. + + The intent is to make the API schema easier to peruse on the documentation. + """ + with open(filename, 'r') as f: + data = yaml.safe_load(f) + + paths = data['paths'] + + top_level_paths = {} + + for path, methods in paths.items(): + tlp = top_level_path(path) + + if tlp not in top_level_paths: + top_level_paths[tlp] = {} + + top_level_paths[tlp][path] = methods + + # Generate output files + for key, value in top_level_paths.items(): + output_file = os.path.join(os.path.dirname(__file__), OUTPUT_DIR, f'{key}.yml') + + output = {} + + output['paths'] = value + + components = data.get('components', {}) + + # Extract only the schemas relating to the provided paths + path_schemas = extract_refs(value, components) + + for k, v in data.items(): + if k == 'components': + v = v.copy() + v['schemas'] = path_schemas + + if k != 'paths': + output[k] = v + + print(f'Writing schema file to {output_file}...') + + output_file = os.path.abspath(output_file) + + with open(output_file, 'w') as f: + yaml.dump(output, f) + + # Generate a markdown file for the schema + generate_schema_file(key) + + # Finally, generate an index file for the API schema + generate_index_file(data['info']['version']) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('input', help='Input API schema file (.yml)') + + args = parser.parse_args() + + parse_api_file(args.input) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 9de602d7ea..0ed500b342 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -57,6 +57,7 @@ extra_css: - stylesheets/bootstrap.css - stylesheets/splide.min.css - stylesheets/extra.css + - stylesheets/neoteroi-mkdocs.css extra_javascript: - javascripts/extra.js - javascripts/fontawesome.js @@ -182,6 +183,7 @@ nav: - Extend: - InvenTree API: - Overview: api/api.md + - API Schema: api/schema.md - Model Metadata: api/metadata.md - Download Data: api/download.md - Bulk Delete: api/bulk_delete.md @@ -225,6 +227,8 @@ nav: # Plugins plugins: + - neoteroi.mkdocsoad: + use_pymdownx: true - include-markdown: opening_tag: "{!" closing_tag: "!}" @@ -252,6 +256,8 @@ markdown_extensions: - meta - pymdownx.details - pymdownx.highlight + - pymdownx.tabbed: + alternate_style: true - pymdownx.superfences: custom_fences: - name: mermaid diff --git a/docs/requirements.txt b/docs/requirements.txt index b7290b79f2..6e85d3a92f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,4 +4,5 @@ mkdocs-material>=9.0,<10.0 mkdocs-git-revision-date-localized-plugin>=1.1,<2.0 mkdocs-simple-hooks>=0.1,<1.0 mkdocs-include-markdown-plugin +neoteroi-mkdocs mkdocstrings[python]>=0.24.0 diff --git a/readthedocs.yml b/readthedocs.yml index cd0eb5f01b..f9c578d243 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -6,8 +6,16 @@ mkdocs: python: install: - requirements: docs/requirements.txt + - requirements: requirements.txt build: os: "ubuntu-22.04" tools: python: "3.9" + jobs: + post_install: + - echo "Generating API schema file" + - pip install -U invoke + - invoke migrate + - invoke schema --filename docs/schema.yml --ignore-warnings + - python docs/extract_schema.py docs/schema.yml diff --git a/tasks.py b/tasks.py index dca41d4755..2c2b56089b 100644 --- a/tasks.py +++ b/tasks.py @@ -918,6 +918,10 @@ def schema(c, filename='schema.yml', overwrite=False, ignore_warnings=False): """Export current API schema.""" check_file_existance(filename, overwrite) + filename = os.path.abspath(filename) + + print(f"Exporting schema file to '{filename}'") + cmd = f'spectacular --file {filename} --validate --color' if not ignore_warnings: @@ -925,6 +929,10 @@ def schema(c, filename='schema.yml', overwrite=False, ignore_warnings=False): manage(c, cmd, pty=True) + assert os.path.exists(filename) + + print('Schema export completed:', filename) + @task(default=True) def version(c):