Compare commits

...

906 Commits

Author SHA1 Message Date
Oliver
950d185a82 Merge pull request #2712 from inventree/0.6.x
0.6.2 release
2022-03-10 16:31:59 +11:00
Oliver
2c8dbb8308 Merge pull request #2736 from SchrodingersGat/loc-del-bug
Fix behaviour when deleting a StockLocation

(cherry picked from commit ff9d48f1c0)
2022-03-10 16:07:51 +11:00
Oliver
78d277d3fc Merge pull request #2721 from SchrodingersGat/big-serial-fix
Big serial fix

(cherry picked from commit 6e82709a48)
2022-03-07 15:31:08 +11:00
Oliver
436a33c5de Merge pull request #2720 from SchrodingersGat/barcode-scan-fix
Barcode scan fix

(cherry picked from commit bcc4267827)
2022-03-07 12:27:18 +11:00
Oliver
718e729059 Merge pull request #2717 from SchrodingersGat/serial-number-fix
Bug fix for stock serial numbers:

(cherry picked from commit 5d5f13ab14)
2022-03-07 09:34:41 +11:00
Oliver
451702f018 Merge pull request #2711 from SchrodingersGat/link-fix
Fix broken URL

(cherry picked from commit 004ced8030)
2022-03-04 13:52:58 +11:00
Oliver
a8047921df Increment version number 2022-03-04 12:27:57 +11:00
Oliver
f237e7743d Merge pull request #2674 from inventree/0.6.x
[WIP] 0.6.1 Stable Release
2022-03-04 10:27:35 +11:00
Oliver
8426f403a6 Merge pull request #2698 from SchrodingersGat/delete-serialized-stock
Allows deletion of serialized stock

(cherry picked from commit 0d2bfa6839)
2022-03-02 00:33:16 +11:00
Oliver
8e01732a5a Merge pull request #2697 from SchrodingersGat/allocation-bug
Bug fix for BuildOrder.bom_items

(cherry picked from commit 35451be4f2)
2022-03-02 00:32:51 +11:00
Oliver
1ed2b47353 Merge pull request #2696 from SchrodingersGat/bom-table-fix
Fix some small template / JS errors on the "part" page

(cherry picked from commit f585ee6db7)
2022-03-02 00:08:49 +11:00
Oliver
1d04db14f2 Merge pull request #2682 from matmair/matmair/issue2672
Fix git version bug

(cherry picked from commit 010ce48ce0)
2022-02-28 14:17:12 +11:00
Oliver
7a18801d0a Bump version number to v0.6.1 2022-02-26 18:37:49 +11:00
Oliver
9841f47806 Merge pull request #2676 from SchrodingersGat/location-permission-fix
Stock location template fix

(cherry picked from commit c882d1f89b)
2022-02-26 18:36:41 +11:00
Oliver
801f7ff96e Merge pull request #2673 from SchrodingersGat/build-order-allocating-substitutes
Build order allocating substitutes

(cherry picked from commit cbb88806cd)
2022-02-25 17:48:05 +11:00
Oliver
84a168fc07 Merge pull request #2666 from matmair/matmair/issue2663
[BUG] Unable to create build output

(cherry picked from commit 50a45474da)
2022-02-25 14:30:51 +11:00
Oliver
37bd57313e Merge pull request #2656 from SchrodingersGat/actions-fix
Fix build-args in workflows

(cherry picked from commit 5045e8c066)
2022-02-21 13:57:12 +11:00
Oliver
8639febf79 0.6.0 stable (#2655)
* fix spelling

Thanks @Stephano120
Good catch!

* add migration

* I18n merge (#2582)

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Adds a warning if no build outputs are created

* Throw validation error if no build outputs have been started

* Prevent AttributeError from being thrown

Ref: https://github.com/inventree/InvenTree/issues/2587

* fix: use default storage backend for Maint Mode

* Experimenting with children models permissions

* Prevent build outputs being created with zero quantity

* PEP style fixes

* Reload build output table when an active build output is deleted

* Reload completed output table

* Fixes issue with BOM export

- Cascading BOM export was broken

* Boolean settings are now directly clickable

* Layout changes

* Display error if setting update failes

* Skips some specific steps when importing data

- We need to prevent certain operations from running when we are importing data
- This is to prevent unique database constraints from being violated

- Do not register plugins during data import
- Do not launch notification events

* PEP fixes

* Adds new setting to optionally display or hide part pricing information

* Hide pricing history tab if not enabled

* Only calculate pricing data if required

* Disable multi-level BOM requests

* Adds serializer for uploading a BOM file and extracting fields

* Fix existing bug with BomExport functionality - could not select BOM format

* POST request now returns extracted data rows (as an array of dicts)

* Attempt to auto-extract part information based on provided data

* Basic javascript function to construct BOM table from extracted data

* Initialize related field for "part" selection

* Add callback for "remove row" button

* Construct required form fields

- required some additional functionality in forms.js

* Add "clear input" callback function

* Add optional part lookup by "part" field

* Allow decimal values for BOM overage

* Adds a BomUpload endpoint to handle upload of complete BOM

* Check for duplicate BOM items as part of serializer validation

* bug fix

* Adds options to clear existing BOM data when uploading

* Update upload file template

* Remove old templates

* PEP fixes

* Handle errors when connecting to currency exchange

- Also adds timeout when connecting

* JS linting

* Only update rates on server launch if there are no rates available

* PEP fixes

* unit test fixes

* Do not hide the "submit order" button

* Remove incorrect validation routine

* Refactored and added permission check for children models

* Reverted print statement to logger

* Improved approach to permission check at runtime

* Fix logic for enabling "place order" button

* Update README.md

Add "follow on twitter" button

* Allow POST of files for unit testing

* Update README.md

Reorder sections

* Catch potential file processing errors

* Add unit testing for uploading invalid BOM files

* Raise error if imported dataset contains no data rows

* Return per-row error messages when extracting data

* PEP fixes

* Adds check for duplicate parts when importing

* Increased error checking when  uploading BOM data

* Catch potential error when posting invalid numbers via REST API

* Improve part "guess" algorithm

* Display initial errors when importing data

* Add button to display original row data

* Disable "submit" button to prevent multiple simultaneous uploads

* Add more unit testing for BOM file upload

- Test "levels" functionality
- Test part guessing / introspection

* Adds API endpoint to delete build outputs

* Remove old form code which is no longer used

* Cleanup

* js linting

* Update base django version

* fix quotes

* ignore the django import check

* ignore import error

* ignore migration

* ignore branches

* remove coverage from parts migrations

* fix migration coverage for orders

* fix migration coverage for company

* fix migration coverage for build

* simpler coverage ignore

* run test paralell

* ignore coverage on ruleset checks

* remove dead code

* move up comment so unneeded functions are not not covered

* remove dead code

* ignore database not ready

* imports are not tested

* no test for malformed paths

* ignore exception ref

* only run sqlite paralell

* fix import

* remove dead code

* PEP fix

* ignore wrong control view safeties

* ignore controls that should not be reached in coverage

* test wrong setting defaults

* remove paralell coverage

* fix setting coverage

* Remove settings mods

* Pep

* Allow BOM file to be "re-uploaded"

* ignore ci render_test

* add comment about function

* ignore debug toolbar

* app not ready can not be simulated by tests

* use same style for AppNotReady Exception

* database not ready events are hard to reproduce consistently

* remove dead test

* ignore not testable condition

* ignore coverage in exsisting migrations

* will never be true in testing

* add test for system healt checks

* test test mode

* test Isimporting

* ignore whole file

* ignore system exit conditions in coverage

* ignore testing coditions in coverage

* do not cover secret key

* ignore db optm in coverage

* ignore some default in coverage

* ignore currently dead code in coverage

* ignore wsgi

* remove dead code

* should not be reached - ignore in cov

* ignore sanity checks for coverage

* update system health check

* fix label tests

* omit coverage via setup.cfg

* fix reporting emition

* catch more explicit

* fix coverage

* except import errors

* add coverage for labels

* PEP fix

* do not count unreachable code

* ignore unreachable things

* user api tests

* PEP fix

* remove coverage that is not reachable

* remove cov from not used feature

* remove dead code

* make git log call simpler

* return cov from feature only used for debug

* should not be reached

* add more plugin coverage

* PEP fixes

* spellcheck

* add test for non existing token

* remove dead code -> permission class does that already

* add more user api tests

* disable broken test

* Enforce proper formatting for 'quantity' field when importing BOM data

* Adds unit tests for index page

Some fairly simple unit tests to ensure that the index page is being correctly loaded.

* Adds a new API endpoint for creating build outputs

* Adds query function to Part model to return trackable parts in the BOM

* Extract serial numbers from submitted form data

* Optionally auto-allocate stock items when creating a new build output

* remove code which is now unused

* PEP style fixes

* Form improvements

* Automatically select Bom Items with matching serial numbers when allocating stock to a build order output

* Adds generic API endpoint for extracting data from a tabulated file

* Adds model mixin for generically determining which fields can be imported on any particular model

* Adds functionality to map file columns to model fiels

* Refactoring API endpoints

- Improved URL naming scheme

* Adds generic javascript function for mapping file columns to model fields

* Adds a button to quickly "pass" a test

* js linting

* Fix field name

* unit test fixes

* Fix breadcrumb tree for stock item page

* Create FUNDING.yml

Add sponsor file

* Update FUNDING.yml

Add ko_fi username

* Spelling fix

* Implement unit test for missing columns

* Improve unit testing

* Further improvements to unit tests

* Adds information on test result being deleted

* Adds "refresh" button for stock test table

* Ensure unit tests are more resilient

* Adds API endpoint for installing stock items into other stock items

- Requires more filtering for the Part API
- Adds more BOM related functionality for Part model
- Removes old server-side form

* PEP fixes

* Critical bug fix: Check if serial numbers already exist when creating new StockItem

* Allow processing of "null" cells (caused by xls / xlsx import)

* Reintroduce option to clear (delete) BOM before uploading new data

* When uploading a report template, keep the existing filename (if it is the same report!)

* Improved error messages when report templates (or snippets) are missing!

* Delete template files from cache as they are uploaded

* Set default error message visibility in modal options

* remove unused code

* remove unneeded assignment

* merge satement

* merge statments

* remove unneeded continue

* PEP fix

* I18n merge (#2647)

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* fix caps

* fix string concat

* use f-string annotation

* I18n release merge (#2654)

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix conflict

* Removes outdated templates

Co-authored-by: Matthias Mair <66015116+matmair@users.noreply.github.com>
Co-authored-by: Matthias <matthias.mair@oewf.org>
Co-authored-by: Nigel <nigel.w@nosun.ca>
Co-authored-by: eeintech <eeintech@eeinte.ch>
2022-02-21 13:20:52 +11:00
Oliver
66a08fe910 Merge pull request #2203 from inventree/0.5.4
0.5.4
2021-11-03 14:19:43 +11:00
Oliver
f377e1c608 Bump version number 2021-10-26 21:29:34 +11:00
Oliver
544a983d48 Merge pull request #2202 from SchrodingersGat/decimal-validation-fix
Fix for supplier price breaks

(cherry picked from commit 5cd9be6845)
2021-10-26 21:16:52 +11:00
Oliver
5ec9989229 Merge pull request #2182 from inventree/0.5.3
0.5.3
2021-10-20 11:25:28 +11:00
Oliver
ca3b6e62cf Increment version number 2021-10-20 10:55:20 +11:00
Oliver
838f412c6b Merge pull request #2122 from SchrodingersGat/bom-speed-improvements
Temporary fix for BOM speed improvements

(cherry picked from commit 8dddb200c7)
2021-10-20 10:53:46 +11:00
Oliver
bfbd604d0a Merge pull request #2146 from SchrodingersGat/0.5.2
0.5.2
2021-10-19 10:05:54 +11:00
Oliver
a75535d336 Increment version number 2021-10-19 09:46:39 +11:00
Oliver
f333532a1f Bug fix: allow empty barcode field when receiving purchase orders 2021-10-19 09:40:19 +11:00
Oliver
36d6628eb6 Revert PR which allowed hiding of major UI functions 2021-10-13 09:57:19 +11:00
Oliver
f948290b21 Merge pull request #2091 from inventree/0.5.1
0.5.1
2021-10-11 21:20:15 +11:00
Oliver
e44446793d Merge remote-tracking branch 'inventree/l10_crowdin' into 0.5.1
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/el/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/locale/fr/LC_MESSAGES/django.po
#	InvenTree/locale/he/LC_MESSAGES/django.po
#	InvenTree/locale/id/LC_MESSAGES/django.po
#	InvenTree/locale/it/LC_MESSAGES/django.po
#	InvenTree/locale/ja/LC_MESSAGES/django.po
#	InvenTree/locale/ko/LC_MESSAGES/django.po
#	InvenTree/locale/nl/LC_MESSAGES/django.po
#	InvenTree/locale/no/LC_MESSAGES/django.po
#	InvenTree/locale/pl/LC_MESSAGES/django.po
#	InvenTree/locale/ru/LC_MESSAGES/django.po
#	InvenTree/locale/sv/LC_MESSAGES/django.po
#	InvenTree/locale/th/LC_MESSAGES/django.po
#	InvenTree/locale/tr/LC_MESSAGES/django.po
#	InvenTree/locale/vi/LC_MESSAGES/django.po
#	InvenTree/locale/zh/LC_MESSAGES/django.po
2021-10-11 21:02:06 +11:00
Oliver
cfde81d09f Merge remote-tracking branch 'inventree/l10' into 0.5.1
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/el/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/locale/fr/LC_MESSAGES/django.po
#	InvenTree/locale/he/LC_MESSAGES/django.po
#	InvenTree/locale/id/LC_MESSAGES/django.po
#	InvenTree/locale/it/LC_MESSAGES/django.po
#	InvenTree/locale/ja/LC_MESSAGES/django.po
#	InvenTree/locale/ko/LC_MESSAGES/django.po
#	InvenTree/locale/nl/LC_MESSAGES/django.po
#	InvenTree/locale/no/LC_MESSAGES/django.po
#	InvenTree/locale/pl/LC_MESSAGES/django.po
#	InvenTree/locale/ru/LC_MESSAGES/django.po
#	InvenTree/locale/sv/LC_MESSAGES/django.po
#	InvenTree/locale/th/LC_MESSAGES/django.po
#	InvenTree/locale/tr/LC_MESSAGES/django.po
#	InvenTree/locale/vi/LC_MESSAGES/django.po
#	InvenTree/locale/zh/LC_MESSAGES/django.po
2021-10-11 21:00:08 +11:00
Oliver
4628bb8f08 Simplify version numbering scheme 2021-10-11 18:56:38 +11:00
github-actions[bot]
dc17e3998a updated translation base 2021-10-11 07:56:21 +00:00
github-actions[bot]
5e8e900b04 updated translation base 2021-10-11 06:22:12 +00:00
github-actions[bot]
94c25c93d6 updated translation base 2021-10-11 01:01:51 +00:00
github-actions[bot]
9e41eb23ac updated translation base 2021-10-11 00:43:52 +00:00
github-actions[bot]
99352f8f84 updated translation base 2021-10-11 00:25:33 +00:00
Oliver
bfb162c688 Merge pull request #2130 from SchrodingersGat/links-fix
Fix various documentation links

(cherry picked from commit 49601d2b7e)
2021-10-11 11:24:16 +11:00
github-actions[bot]
12d3646da1 updated translation base 2021-10-11 00:00:43 +00:00
github-actions[bot]
a21e4560f1 updated translation base 2021-10-10 23:55:19 +00:00
Oliver
66c037b9f8 0.5 -> 0.5.1 2021-10-11 10:43:36 +11:00
Oliver
66d4b14ba4 Fix conflicts 2021-10-11 10:42:23 +11:00
github-actions[bot]
1c912088a2 updated translation base 2021-10-10 23:41:54 +00:00
github-actions[bot]
793fe39fe7 updated translation base 2021-10-08 02:10:20 +00:00
github-actions[bot]
a6f5a8107a updated translation base 2021-10-07 11:45:06 +00:00
github-actions[bot]
d3cdb34151 updated translation base 2021-10-07 02:55:56 +00:00
github-actions[bot]
638b478d1f updated translation base 2021-10-07 01:16:12 +00:00
Oliver
4efa8a5d3b Merge pull request #2118 from SchrodingersGat/bom-export-fix
Fix error on BOM export

(cherry picked from commit a69bcb9f18)
2021-10-07 12:15:11 +11:00
github-actions[bot]
1273d93c8c updated translation base 2021-10-07 00:01:36 +00:00
github-actions[bot]
db59f99f2d updated translation base 2021-10-06 11:41:52 +00:00
github-actions[bot]
7df5215404 updated translation base 2021-10-06 10:38:04 +00:00
github-actions[bot]
6e47a1feb6 updated translation base 2021-10-06 10:05:12 +00:00
github-actions[bot]
88464ad640 updated translation base 2021-10-06 09:54:20 +00:00
github-actions[bot]
32556d660e updated translation base 2021-10-06 09:53:08 +00:00
Oliver
ca0caa3d2b Merge pull request #2112 from SchrodingersGat/docs-link-fix
Fix docs link for release versions

(cherry picked from commit c2d33588d0)
2021-10-06 20:53:06 +11:00
Oliver
f6bcee06cb Merge pull request #2108 from SchrodingersGat/sales-order-table-fixes
Bug fixes for SalesOrderLineItem table

(cherry picked from commit 6706d6c768)
2021-10-06 17:27:47 +11:00
github-actions[bot]
08394574ce updated translation base 2021-10-06 06:23:34 +00:00
github-actions[bot]
4a74294123 updated translation base 2021-10-05 22:53:58 +00:00
github-actions[bot]
e84cad1660 updated translation base 2021-10-05 07:03:31 +00:00
github-actions[bot]
86c8d86b67 updated translation base 2021-10-05 02:21:40 +00:00
github-actions[bot]
c567b7a84c updated translation base 2021-10-05 01:54:15 +00:00
Oliver
1132b6c51a Fixes for build output tables
- Only show "completed" builds in the "completed builds" table (should be obvious)
- Display "serial number" appropriately in build output allocation table

(cherry picked from commit a3ba33cae8)
2021-10-05 12:53:17 +11:00
Oliver
10e3a5f5a9 Merge pull request #2100 from SchrodingersGat/barcode-field-fix
Fix for "barcode" field in purchase order receive serializer

(cherry picked from commit 5c26769999)
2021-10-05 12:34:46 +11:00
github-actions[bot]
95bf39c127 updated translation base 2021-10-05 01:33:19 +00:00
eeintech
f661a4f4ec Added migration file
(cherry picked from commit a735a3e15c)
2021-10-05 10:58:28 +11:00
eeintech
3d067b39b1 Fix plural name for Companies in Admin interface
(cherry picked from commit 6e31a8111b)
2021-10-05 10:58:22 +11:00
github-actions[bot]
d01686248b updated translation base 2021-10-04 23:41:41 +00:00
Oliver
094a63f751 Bump version number -> 0.5.1 2021-10-04 09:52:15 +11:00
github-actions[bot]
024552e4d0 updated translation base 2021-10-03 22:36:56 +00:00
github-actions[bot]
a5e26ceeac updated translation base 2021-10-02 15:35:10 +00:00
Oliver
2fedc1267c Merge pull request #2090 from SchrodingersGat/po-api-fix
Fix for purchase order API

(cherry picked from commit b7ff50ca87)
2021-10-03 01:33:54 +10:00
Oliver
7d3c0a7aa8 Merge pull request #2088 from inventree/0.5.0
Fixes for docker build steps
2021-10-01 13:46:34 +10:00
Oliver
018ab0cd05 Fixes for docker build steps 2021-10-01 13:26:43 +10:00
Oliver
0b5a4efef6 Merge pull request #2050 from inventree/0.5.0
0.5.0
2021-10-01 13:23:13 +10:00
Oliver
a3c2f8b36b Merge remote-tracking branch 'inventree/l10_crowdin' into 0.5.0 2021-10-01 09:18:45 +10:00
github-actions[bot]
4893cd527f updated translation base 2021-09-30 22:48:24 +00:00
Oliver
32e82488d3 Merge pull request #2084 from eeintech/show_part_delete
Show part delete button when part still active

(cherry picked from commit 16dcd8adf6)
2021-10-01 08:46:46 +10:00
github-actions[bot]
f2050f7cab updated translation base 2021-09-30 12:16:50 +00:00
Oliver
827534138b Merge pull request #2086 from SchrodingersGat/search-fix
Fix for search page

(cherry picked from commit 172d184a4d)
2021-09-30 22:14:09 +10:00
github-actions[bot]
1ef1fdc6e6 updated translation base 2021-09-30 00:47:58 +00:00
github-actions[bot]
7f93b37437 updated translation base 2021-09-29 23:44:17 +00:00
Oliver
9c2f4ce491 Merge pull request #2083 from SchrodingersGat/search-results
Display "full_name" rather than "name" in quick search bar

(cherry picked from commit 819934af7e)
2021-09-30 09:43:15 +10:00
github-actions[bot]
d56da99c0d updated translation base 2021-09-28 00:58:41 +00:00
Oliver
79686ebb2a Merge pull request #2082 from SchrodingersGat/stock-item-delete
Override the "delete" behaviour for StockItem API

(cherry picked from commit 344383d3d4)
2021-09-28 10:57:43 +10:00
github-actions[bot]
71b3dd3e76 updated translation base 2021-09-27 23:30:47 +00:00
github-actions[bot]
dcdb2add28 updated translation base 2021-09-27 04:34:36 +00:00
Oliver
d14b763ef9 Merge pull request #2079 from SchrodingersGat/url-fix
URL fixes

(cherry picked from commit b623f34881)
2021-09-27 14:34:28 +10:00
github-actions[bot]
7522a80f96 updated translation base 2021-09-24 02:37:15 +00:00
Oliver
fb27eb48c4 Merge remote-tracking branch 'inventree/master' into 0.5.0 2021-09-24 12:36:49 +10:00
Oliver
a1d54690c2 Merge pull request #2075 from SchrodingersGat/default-supplier-fix
Default supplier fix

(cherry picked from commit b3c8bd7779)
2021-09-24 12:36:19 +10:00
Oliver
b3c8bd7779 Merge pull request #2075 from SchrodingersGat/default-supplier-fix
Default supplier fix
2021-09-24 12:35:28 +10:00
Oliver
f53aac0784 Remove "default_supplier" field when duplicating a part 2021-09-24 12:04:36 +10:00
Oliver
d2b9993e96 Fix form filters for "default_supplier" 2021-09-24 12:04:25 +10:00
github-actions[bot]
5efba2dad0 updated translation base 2021-09-23 11:53:15 +00:00
Oliver
d7ac9978eb Merge pull request #2071 from inventree/dependabot/pip/django-3.2.5
Build(deps): Bump django from 3.2.4 to 3.2.5

(cherry picked from commit 39cab4690d)
2021-09-23 21:52:02 +10:00
Oliver
39cab4690d Merge pull request #2071 from inventree/dependabot/pip/django-3.2.5
Build(deps): Bump django from 3.2.4 to 3.2.5
2021-09-23 21:51:23 +10:00
dependabot[bot]
1d85ccd543 Build(deps): Bump django from 3.2.4 to 3.2.5
Bumps [django](https://github.com/django/django) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.2.4...3.2.5)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-22 17:46:34 +00:00
github-actions[bot]
d943020d56 updated translation base 2021-09-21 23:36:06 +00:00
Oliver
80d2fc4b9e Merge pull request #2068 from rocheparadox/master
css for part to occupy full height - fix for bug Inventree#1848

(cherry picked from commit b123135df6)
2021-09-22 09:34:37 +10:00
Oliver
2e1277839e Merge pull request #2067 from SchrodingersGat/warning-improvements
Improve 'health status' warnings
2021-09-22 09:34:23 +10:00
github-actions[bot]
a41db6ae28 updated translation base 2021-09-21 23:08:30 +00:00
Oliver
b123135df6 Merge pull request #2068 from rocheparadox/master
css for part to occupy full height - fix for bug Inventree#1848
2021-09-22 09:06:03 +10:00
Oliver
3b763e95fd Improve 'health status' warnings
- Don't show error message if only non-critical warnings present

(cherry picked from commit 5443beef65)
2021-09-21 09:27:46 +10:00
rocheparadox
c1a827819c css for part to occupy full height - fix for bug Inventree#1848 2021-09-20 17:00:45 +05:30
Oliver
5443beef65 Improve 'health status' warnings
- Don't show error message if only non-critical warnings present
2021-09-20 17:15:31 +10:00
github-actions[bot]
11d2d5588f updated translation base 2021-09-17 12:36:18 +00:00
Oliver
ae3c9817be Merge pull request #2062 from SchrodingersGat/app-issue-template
Add template for app issues
2021-09-17 22:34:45 +10:00
Oliver
8d6d16c07b Add template for app issues 2021-09-17 22:13:13 +10:00
github-actions[bot]
7f09ad2b38 updated translation base 2021-09-17 11:49:36 +00:00
Oliver
7b2b01c26f Merge pull request #2060 from SchrodingersGat/character-test
Adds a test for non-standard characters via API
2021-09-17 21:48:10 +10:00
Oliver
e7963f8a85 test fixes 2021-09-17 21:06:07 +10:00
Oliver
11cc0c7ced Adds a test for non-standard characters via API 2021-09-17 20:53:18 +10:00
github-actions[bot]
ebc95cb326 updated translation base 2021-09-14 01:00:20 +00:00
Oliver
d73a7176fd Merge pull request #2055 from SchrodingersGat/test-template-table-fix
Fix callback for test template table
2021-09-14 10:58:57 +10:00
Oliver
44e0fd1a68 Fix callback for test template table
(cherry picked from commit 5bd5c61b9d)
2021-09-14 10:57:55 +10:00
Oliver
5bd5c61b9d Fix callback for test template table 2021-09-14 10:43:40 +10:00
github-actions[bot]
2018229dc5 updated translation base 2021-09-14 00:01:42 +00:00
Oliver
1643a2ccb2 Merge pull request #2054 from matmair/fix-for-2004
Fix for 2004
2021-09-14 10:00:19 +10:00
Matthias
847fb62ab5 js style 2021-09-13 23:25:13 +02:00
Matthias
c890a4a6d0 only add button per name once 2021-09-13 23:18:44 +02:00
github-actions[bot]
224b372eae updated translation base 2021-09-13 10:30:31 +00:00
Oliver
95924852a4 Merge pull request #2053 from SchrodingersGat/contributing
Update contributing.md
2021-09-13 20:29:09 +10:00
github-actions[bot]
7d286cf4b8 updated translation base 2021-09-13 10:04:22 +00:00
Oliver
dfd500097e Update contributing.md
(cherry picked from commit 398842d6e5)
2021-09-13 20:03:31 +10:00
Oliver
7a7684b018 Merge branch 'l10'
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/el/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/locale/fr/LC_MESSAGES/django.po
#	InvenTree/locale/he/LC_MESSAGES/django.po
#	InvenTree/locale/id/LC_MESSAGES/django.po
#	InvenTree/locale/it/LC_MESSAGES/django.po
#	InvenTree/locale/ja/LC_MESSAGES/django.po
#	InvenTree/locale/ko/LC_MESSAGES/django.po
#	InvenTree/locale/nl/LC_MESSAGES/django.po
#	InvenTree/locale/no/LC_MESSAGES/django.po
#	InvenTree/locale/pl/LC_MESSAGES/django.po
#	InvenTree/locale/ru/LC_MESSAGES/django.po
#	InvenTree/locale/sv/LC_MESSAGES/django.po
#	InvenTree/locale/th/LC_MESSAGES/django.po
#	InvenTree/locale/tr/LC_MESSAGES/django.po
#	InvenTree/locale/vi/LC_MESSAGES/django.po
#	InvenTree/locale/zh/LC_MESSAGES/django.po
2021-09-13 10:15:08 +10:00
Oliver
de565c6e67 Merge branch 'l10' into 0.5.0
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/el/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/locale/fr/LC_MESSAGES/django.po
#	InvenTree/locale/he/LC_MESSAGES/django.po
#	InvenTree/locale/id/LC_MESSAGES/django.po
#	InvenTree/locale/it/LC_MESSAGES/django.po
#	InvenTree/locale/ja/LC_MESSAGES/django.po
#	InvenTree/locale/ko/LC_MESSAGES/django.po
#	InvenTree/locale/nl/LC_MESSAGES/django.po
#	InvenTree/locale/no/LC_MESSAGES/django.po
#	InvenTree/locale/pl/LC_MESSAGES/django.po
#	InvenTree/locale/ru/LC_MESSAGES/django.po
#	InvenTree/locale/sv/LC_MESSAGES/django.po
#	InvenTree/locale/th/LC_MESSAGES/django.po
#	InvenTree/locale/tr/LC_MESSAGES/django.po
#	InvenTree/locale/vi/LC_MESSAGES/django.po
#	InvenTree/locale/zh/LC_MESSAGES/django.po
2021-09-13 10:03:45 +10:00
Oliver
35dd50e94f Merge branch 'stable' into 0.5.0 2021-09-13 10:00:28 +10:00
Oliver
4b9fd13622 Set version number to 0.5.0 2021-09-13 09:56:53 +10:00
Oliver Walters
06c03039da Add version related tags
- Docs URL points to correct documentation version
- Display if we are in "development" version
2021-09-12 23:13:55 +10:00
Oliver
695370c8d7 Merge pull request #2048 from inventree/version-tags
Updates for docker workflows:
2021-09-12 22:28:26 +10:00
Oliver Walters
7b21270baf Bump version number 2021-09-12 22:08:51 +10:00
Oliver Walters
08397c5e5f different syntax 2021-09-12 22:06:06 +10:00
Oliver Walters
3d4a8bdd22 env prefix 2021-09-12 21:54:59 +10:00
Oliver Walters
06f323fe47 Use GITHUB_BASE_REF 2021-09-12 21:52:02 +10:00
Oliver Walters
6baaf98d7e fix environment variable 2021-09-12 21:49:13 +10:00
Oliver Walters
5770789ddb more fix 2021-09-12 21:40:56 +10:00
Oliver Walters
fd192b65bf workflow fix 2021-09-12 21:37:30 +10:00
Oliver Walters
5ee004eabd Add workflow to check version number 2021-09-12 21:36:14 +10:00
Oliver Walters
429add9000 Updates for docker workflows:
- check_version_number script now handles stable and development codes
2021-09-12 21:17:56 +10:00
Oliver
71ca60d679 Merge pull request #2044 from SchrodingersGat/new-line-item
Bug fix - "Add line item" button
2021-09-08 14:32:51 +10:00
Oliver
b9b23a3853 bug fix 2021-09-08 14:14:14 +10:00
Oliver
829dd0d637 Merge pull request #2043 from SchrodingersGat/received-stock-items
Fixes for purchase order stock table
2021-09-08 13:29:05 +10:00
Oliver
387680fbcd More linting 2021-09-08 13:13:40 +10:00
Oliver
20788bb559 Bump pillow version for security fix 2021-09-08 13:02:49 +10:00
Oliver
a32a30de52 javascript linting 2021-09-08 13:02:03 +10:00
Oliver
1a21576f28 Adds separate option for "prevent_new_stock" to stock_table 2021-09-08 12:57:42 +10:00
Oliver
ba787a0485 Merge pull request #2041 from SchrodingersGat/metadata-fixes
Fix OPTIONS request lookup time
2021-09-08 12:52:00 +10:00
Oliver
8368798280 Move po-line-item-table into javascript file
- for better linting
2021-09-08 12:51:49 +10:00
Oliver
6012855ec4 PEP fixes 2021-09-08 12:24:33 +10:00
Oliver
919b39515f Improve instance lookup for metadata layer
- Existing call to get_object() could take > 20 seconds in some cases
- Not really sure why, some issue with the DRF library
- Was probably parsing the entire queryset rather than doing a PK lookup
- Instead, directly use the provided pk to get the model
2021-09-08 12:18:07 +10:00
Oliver
22aa0a03c9 Merge pull request #2039 from SchrodingersGat/requirements
Re-add gunicorn to requirements file
2021-09-08 08:48:20 +10:00
Oliver
84528df6f8 Re-add gunicorn to requirements file 2021-09-08 08:01:05 +10:00
Oliver
a70f4c86eb Merge pull request #2013 from SchrodingersGat/receive-via-api
Receive via api
2021-09-07 23:56:44 +10:00
Oliver Walters
f349dc01ea JS lint 2021-09-07 23:41:13 +10:00
Oliver Walters
f38bf6e20a Adds unit testing for barcode field 2021-09-07 23:34:14 +10:00
Oliver Walters
bf05c9cfae Adds "barcode" field to POLineItem receive serializer 2021-09-07 23:06:36 +10:00
Oliver Walters
ccb191e5b1 Bump API version 2021-09-07 23:06:17 +10:00
Oliver
50ae331afd Merge pull request #2034 from SchrodingersGat/build-complete-scheduling
Build completion scheduling
2021-09-07 22:51:52 +10:00
Oliver Walters
125554c53f Merge remote-tracking branch 'upstream/master' into receive-via-api
# Conflicts:
#	InvenTree/templates/js/dynamic/inventree.js
#	InvenTree/templates/js/translated/forms.js
#	InvenTree/templates/js/translated/tables.js
2021-09-07 22:34:00 +10:00
Oliver Walters
ecc7bd2d5b Unit test fixes 2021-09-07 22:27:39 +10:00
Oliver
5ab4be7025 Unit test fixes 2021-09-07 17:36:53 +10:00
Oliver
918106c225 Adds a background task to remove StockItem objects which are scheduled for deletion 2021-09-07 16:45:58 +10:00
Oliver
7d3cd03d6c Add "scheduled_for_deletion" field to StockItem
- If set to True, this StockItem will be deleted (soon) by the background worker
- As deletion takes significant time, this prevents delete operations from blocking the UI
2021-09-07 16:28:57 +10:00
Oliver
4b1c2677c5 Update README.md 2021-09-06 09:42:51 +10:00
Oliver
8b6ebc092a Merge pull request #2033 from SchrodingersGat/clip.html-fix
Run HTML linting as .github action
2021-09-04 09:43:14 +10:00
Oliver
f363c0f084 Fix workflow file 2021-09-04 09:22:52 +10:00
Oliver
c7d6b985bd LINT ALL THE THINGS 2021-09-04 09:08:46 +10:00
Oliver
42637ddefa more linting 2021-09-04 08:59:02 +10:00
Oliver
9b001cd298 Another fix 2021-09-04 08:48:34 +10:00
Oliver
f0e5d1984c Fix for about.html 2021-09-04 08:46:30 +10:00
Oliver
0a8365e3bc Fix for clip.html 2021-09-04 08:45:06 +10:00
Oliver
514db57c0c Run HTML linting as .github actino 2021-09-04 08:31:47 +10:00
Oliver
c275bf8d98 Merge pull request #2026 from inventree/js-linting
Js linting
2021-09-03 23:35:14 +10:00
Oliver Walters
e5872f4b67 improve js debug comment 2021-09-03 23:16:35 +10:00
Oliver
888fa51cd7 lots of linting fixes for JS files 2021-09-03 22:54:17 +10:00
Oliver
3db830e7cd Merge pull request #2031 from SchrodingersGat/polineitem-destination
Fix on_delete for PurchaseOrderLineItem.destination
2021-09-02 11:37:54 +10:00
Oliver
5d703af932 Add migration file 2021-09-02 11:11:25 +10:00
Oliver
43c4e936a7 Fix on_delete for PurchaseOrderLineItem.destination
- Currently set to DO_NOTHING
- However when deleting a StockLocation which has a PurchaseOrderLineItem.destionation point to it, this will cause an IntegrityError
2021-09-02 10:41:23 +10:00
Oliver
c90f9b0447 Merge pull request #2030 from matmair/html-code-smells
Html code smells
2021-09-02 08:47:59 +10:00
Matthias
0ebc45e834 replace i html tags 2021-09-02 00:18:47 +02:00
Matthias
6a420fd95c replace bold tags 2021-09-02 00:17:12 +02:00
Oliver
edb1602c7c Merge pull request #2028 from matmair/fix-html-tag
fix html templates
2021-09-02 07:10:15 +10:00
Matthias Mair
2b1279e647 now with closing tags 2021-09-01 08:14:08 +02:00
Matthias Mair
5ad2eabab1 fix html templates 2021-08-31 13:17:38 +02:00
Oliver Walters
cb403a5b29 More work 2021-08-30 22:28:01 +10:00
Oliver Walters
a1b7239b7e indent error 2021-08-30 21:30:10 +10:00
Oliver Walters
6dde353646 Fix indent rule 2021-08-30 21:25:43 +10:00
Oliver Walters
4ffcf48ab3 4 spaces for indent 2021-08-30 21:21:26 +10:00
Oliver Walters
fc125ca20c Fix workflow file 2021-08-30 21:16:54 +10:00
Oliver Walters
9781d585b0 Install eslint-config-google 2021-08-30 21:08:46 +10:00
Oliver Walters
3d5144b9bc Simplify eslintrc file 2021-08-30 20:30:44 +10:00
Oliver Walters
4c39607e00 Brace style fixes 2021-08-30 20:30:26 +10:00
Oliver Walters
e1adef5010 typo fix 2021-08-30 20:08:18 +10:00
Oliver Walters
6177fe0c5a build.js 2021-08-30 19:52:28 +10:00
Oliver Walters
2112c6a9ad barcode.js 2021-08-30 19:33:43 +10:00
Oliver Walters
7d4945d302 company.js 2021-08-30 16:01:45 +10:00
Oliver Walters
0835fe92a0 bom.js 2021-08-30 15:54:31 +10:00
Oliver Walters
51eb40f3bc forms.js 2021-08-30 15:47:58 +10:00
Oliver Walters
bb3b6fdc4d label.js 2021-08-30 15:34:46 +10:00
Oliver Walters
e0e7788af6 More js fixes 2021-08-30 15:32:01 +10:00
Oliver Walters
50b54f0966 order.js 2021-08-30 14:57:17 +10:00
Oliver Walters
00f012311d inventree.js 2021-08-30 14:49:40 +10:00
Oliver Walters
90a75ac7cb nav.js 2021-08-30 14:44:44 +10:00
Oliver Walters
7d5b859233 part.js 2021-08-30 14:39:58 +10:00
Oliver Walters
3e03b1c31d report.js 2021-08-30 14:12:35 +10:00
Oliver Walters
c846aeb60f stock.js 2021-08-30 14:07:34 +10:00
Oliver Walters
65874447ed bug fix 2021-08-30 13:13:12 +10:00
Oliver Walters
5d45fce240 remove import / export calls 2021-08-30 13:10:58 +10:00
Oliver Walters
24ca1c5641 Add "helpers.js" for common functions 2021-08-30 13:06:02 +10:00
Oliver Walters
140a2092c8 fixes for table_filters.js 2021-08-28 22:18:20 +10:00
Oliver Walters
0620e656a0 Fix linting errors or tables.js 2021-08-28 22:12:41 +10:00
Oliver Walters
e85ddf3579 Add required env vars 2021-08-28 21:10:31 +10:00
Oliver Walters
f7c515b889 add "invoke static" step 2021-08-28 21:05:55 +10:00
Oliver Walters
09a7a7d2e4 Install required files 2021-08-28 21:03:09 +10:00
Oliver Walters
d0ccf8647d Add js linting to github workflow 2021-08-28 20:59:41 +10:00
Oliver Walters
f57a31c9b5 Add a test framework script to pull down rendered javascript files
- Use the testing framework so we don't need to spin up a server
2021-08-28 20:46:51 +10:00
Oliver Walters
880a701881 eslint configuration file 2021-08-28 16:55:59 +10:00
Oliver Walters
62d877ba54 Adds script to pull down "rendered" versions of javascript files 2021-08-28 16:40:06 +10:00
Oliver
e261fa6b29 Merge pull request #2024 from SchrodingersGat/category-param-fix
Simple fix for category parameter settings
2021-08-26 23:11:29 +10:00
Oliver Walters
3adf30a00c Simple fix for category parameter settings 2021-08-26 22:50:50 +10:00
Oliver
e5de69cd96 Update version.py
Actually bump the API version
2021-08-26 22:13:13 +10:00
Oliver
320ca451cc Merge pull request #2023 from inventree/units-in-api
Add "units" to PartBriefSerializer
2021-08-26 22:12:27 +10:00
Oliver
610c05384b Merge pull request #2020 from SchrodingersGat/mpn-sorting-fix
Mpn sorting fix
2021-08-26 22:06:06 +10:00
Oliver Walters
ec88415f3d Add "units" to PartBriefSerializer 2021-08-26 21:54:25 +10:00
Oliver
ac8a0be74a Enable sorting by total_price 2021-08-26 08:48:19 +10:00
Oliver
bad246bca6 Fixes for ordering of stock table 2021-08-26 08:24:31 +10:00
Oliver
212a7eeed1 Disable filtering for total_price (as this is not a database field!) 2021-08-26 07:59:47 +10:00
Oliver
8660f13ef5 Allow sorting by purchase price (unit price) 2021-08-26 07:50:19 +10:00
Oliver
9b6b5825f3 Merge pull request #2021 from SchrodingersGat/table-col-fix
Change name of purchaseorder line item table
2021-08-26 07:02:04 +10:00
Oliver
51992a92c1 Change name of purchaseorder line item table
- Was conflicting with purchaseorder table
- Saved column selections were being overridden
2021-08-25 18:00:32 +10:00
Oliver
4b8ef2ad62 Implements custom filtering back end 2021-08-25 17:46:42 +10:00
Oliver
75152fab0e Merge pull request #2018 from SchrodingersGat/file-upload-fix
Fix for file upload bug
2021-08-25 15:05:32 +10:00
Oliver
9c9407b1ab Add unit test for catching bug
- Turns out that in an image was uploaded with more than ~2000 vertical pixels it would crash
- Smaller images worked fine?
2021-08-25 14:48:45 +10:00
Oliver
dcc8acb49a Data must be copied in a particular way 2021-08-25 14:12:26 +10:00
Oliver
44ab487b62 Fix for file upload bug 2021-08-25 12:05:41 +10:00
Oliver
c9756d30bd Add a custom OrderingFilter class
Needs further work
2021-08-25 12:04:15 +10:00
Oliver
2923589c4a Fix sortName for purchase order line item table 2021-08-25 12:02:25 +10:00
Oliver Walters
f6b9d9e6d0 Revert "WIP"
This reverts commit 42af52ee51.
2021-08-24 22:33:29 +10:00
Oliver Walters
42af52ee51 WIP 2021-08-24 22:31:13 +10:00
Oliver
28878b4b0d Update feature_request.md
Slight tweaks
2021-08-24 22:30:01 +10:00
Oliver
18297cd2fb Update bug_report.md
Slight tweaks to bug report template
2021-08-24 22:28:42 +10:00
Oliver
bdcc66bac7 Merge pull request #2009 from matmair/templates
RFC: Issue Templates
2021-08-24 22:26:55 +10:00
Oliver Walters
0d7eb6b72c Style fixes 2021-08-24 22:25:25 +10:00
Oliver Walters
5275d3943b Adds option to hide labels and help text 2021-08-24 22:13:07 +10:00
Oliver Walters
d87ab0033a Add "afterRender" callback for modal forms 2021-08-24 22:05:00 +10:00
Oliver Walters
1360b1592d Some convenience functions 2021-08-24 22:04:43 +10:00
Oliver Walters
e3605001e4 Simple function to render a thumbnail 2021-08-24 22:04:06 +10:00
Oliver Walters
d5e58fd798 Fix for status code serializer 2021-08-24 22:03:52 +10:00
Oliver
86e3e26196 Merge remote-tracking branch 'inventree/master' into receive-via-api 2021-08-24 15:07:55 +10:00
Oliver
0073a77e16 Merge pull request #2008 from matmair/fix-for-1986
Fix for 1986
2021-08-24 14:13:50 +10:00
Oliver
7f75c610ef Merge pull request #2012 from SchrodingersGat/search-preview-click
Wrap search preview results in <a>
2021-08-24 13:47:55 +10:00
Oliver
36a0496dd7 Wrap search preview results in <a>
- Allows clicking with middle mouse (for e.g.) to open in new tab
2021-08-24 13:11:37 +10:00
Oliver
44ecd958a2 Merge pull request #2011 from SchrodingersGat/boolean-form-fixes
Fix for "part" form fields
2021-08-24 12:10:00 +10:00
Oliver
56f27aae23 Merge pull request #2010 from SchrodingersGat/sales-order-tab-fix
Hide "Sales Orders" tab if part is not salable
2021-08-24 12:03:09 +10:00
Oliver
8fc79f45a3 Fix for "part" form fields
- Specify "default" rather than overriding "value"
2021-08-24 11:55:58 +10:00
Oliver
7646535aaf Hide "Sales Orders" tab if part is not salable 2021-08-24 11:48:42 +10:00
Oliver
1b65fbad2c Update unit tests
- Found some bugs too, thanks unit tests!
2021-08-24 11:42:08 +10:00
Oliver
d30173132a Actually receive items 2021-08-24 08:49:23 +10:00
Matthias Mair
446243f2b5 Added templates 2021-08-24 00:29:50 +02:00
Oliver
2aa505b2cb Fix unit tests to match new API format 2021-08-24 08:18:59 +10:00
Oliver
5349addc06 Merge pull request #2005 from eeintech/ui_updates
Updated color of `new` and `add` UI buttons
2021-08-24 08:12:45 +10:00
Matthias
391bb0dbe4 disable ordering on loadStockTable 2021-08-23 22:14:51 +02:00
Matthias
4efcfbecaf refactor stock.js columns into a variable 2021-08-23 22:07:20 +02:00
eeintech
35738ce026 Updated all 'add' buttons to 'btn-success' CSS class 2021-08-23 14:52:35 -04:00
eeintech
6f742319e5 Corrected color of 'new' orders UI button 2021-08-23 12:48:47 -04:00
Oliver
6091f2ba33 Serializer improvements
- Pass the "order" down to the nested serializers for validation
2021-08-24 00:29:38 +10:00
Oliver
dc53a433a7 Fix serializer nesting
- Add new API endpoint to receive items
- Add unit testing
2021-08-23 23:35:22 +10:00
Oliver
28cc241354 Custom DRF serializers for receiving line items against a purchase order 2021-08-23 23:13:07 +10:00
Oliver
f136c974cf Merge pull request #2003 from SchrodingersGat/edit-purchase-prices
Edit purchase prices
2021-08-23 22:54:12 +10:00
Oliver
90d0b8b15d Bump API version 2021-08-23 21:45:40 +10:00
Oliver
5d4f35958d Point table at the new read-only field 2021-08-23 21:45:32 +10:00
Oliver
bb8b85c375 Separate purchase_price and purchase_price_currency for StockItem serializer
- Add "purchase_price_string" for a read-only stringified representation
- Unit testing
2021-08-23 21:44:12 +10:00
Oliver
d267d04bed Allow validation of empty money values 2021-08-23 21:43:31 +10:00
Oliver
f96051d863 Replace print statement with a logger warning 2021-08-23 21:39:54 +10:00
Oliver
8662e6a109 Fix a super annoying validation issue
- Was throwing opaque "too many values to unpack" error
- Simply needed the name of the field.
2021-08-23 21:39:00 +10:00
Oliver
1fb76b9987 Merge pull request #1999 from matmair/turn-of-functions
Disable functions in navbars
2021-08-23 20:29:28 +10:00
Matthias Mair
4c8fdab072 fixed descriptions 2021-08-23 09:44:52 +02:00
Oliver
fd1dd792c6 Merge pull request #1957 from matmair/bpm-purchase-price
BOM - show purchase price
2021-08-23 11:07:30 +10:00
Oliver
87a41c7e39 Merge pull request #2000 from SchrodingersGat/dev-conf-fix
Fix for docker development env file
2021-08-23 09:10:25 +10:00
Oliver
47524f6ea3 Fix for docker development env file 2021-08-23 08:39:09 +10:00
Oliver
a5f26c7f09 Merge pull request #1998 from bobek/patch-1
Fix for production docker environment
2021-08-23 08:38:04 +10:00
Matthias
9fd4b5cce3 use new setting for part-actions
PR complete for #1999
2021-08-22 23:36:49 +02:00
Matthias
b674d851f2 disable fucntions in master nav 2021-08-22 22:30:21 +02:00
Matthias
3682eaac14 disable links in navbar in company views 2021-08-22 22:27:53 +02:00
Matthias
d4efdf86e5 new settingsthe settings-page 2021-08-22 22:09:07 +02:00
Matthias
8edfada22a adding settings definitions for turning off features 2021-08-22 22:08:41 +02:00
Antonin Kral
7f126e58d2 Fix for production docker environment
Values are passed as written resulting in `"WARNING"` being passed to python logger, which will complain and panic. Fix is simply to remove `"` from the value.
2021-08-22 20:59:51 +02:00
Oliver
b6df623554 Merge pull request #1997 from SchrodingersGat/new-po-from-order
Refactor buttons in "order parts" wizard
2021-08-23 00:49:27 +10:00
Oliver Walters
174b7ba7f2 Fix for "new purchase order" button 2021-08-23 00:28:36 +10:00
Oliver Walters
449e0c0af2 Refactor button in first step of "order parts" wizard
- "new supplier part" button was broken
- Was linked to the old "launchModalForm" code
- Now calls createSupplierPart
2021-08-23 00:17:45 +10:00
Oliver
3cf06b4960 Merge pull request #1995 from SchrodingersGat/delete-unused-images
remove some unused images
2021-08-23 00:11:39 +10:00
Oliver Walters
f2e58ebbdd remove some unused images 2021-08-22 23:54:43 +10:00
Oliver
370fbea396 Merge pull request #1987 from matmair/fix-for-1986
Disable table sorting when order is fixed
2021-08-22 23:47:21 +10:00
Oliver
51de0a982a Merge pull request #1990 from matmair/fix-tooltip-linebreak
Fix tooltip linebreak
2021-08-22 08:19:54 +10:00
Matthias
38af66c0de fix linebreak in tooltip
found during fixing #1989
2021-08-21 00:07:45 +02:00
Matthias
8fad704d76 disable ordering on stock 2021-08-20 22:53:25 +02:00
Matthias
5a59a37a89 disable ordering on category 2021-08-20 22:52:57 +02:00
Matthias
109b8c943e disable ordering on part-name 2021-08-20 22:52:14 +02:00
Matthias
7533a9ac0c disable ordering on IPN if fixed ordering 2021-08-20 22:51:36 +02:00
Oliver
8646c73021 Merge pull request #1980 from matmair/housekeeping
Housekeeping
2021-08-20 09:02:33 +10:00
Oliver
5bd31f11eb Merge pull request #1978 from matmair/fix-translate
Fix translations stats - task
2021-08-20 09:01:50 +10:00
Oliver
831ccec399 Merge pull request #1981 from matmair/coverage-to-setup
Merge coverage settings
2021-08-20 09:01:12 +10:00
Matthias Mair
e24a158919 Merge branch 'inventree:master' into bpm-purchase-price 2021-08-20 00:42:50 +02:00
Matthias
c4700d0e10 move coverage settings into setup.cfg 2021-08-20 00:35:25 +02:00
Matthias
e17f15f403 updating year on license 2021-08-20 00:31:10 +02:00
Matthias
e34c27e360 removed translation part - is done now by action 2021-08-20 00:25:55 +02:00
Oliver
414d2dbc96 Merge pull request #1977 from eeintech/company_templates
Fixed company templates
2021-08-20 07:47:29 +10:00
Matthias
575cf87b98 also run static on update 2021-08-19 23:37:38 +02:00
Matthias
ee33de711a move translation stats into own task 2021-08-19 23:36:54 +02:00
Matthias
cb1e7a6cc5 only process purchase_price if prices present 2021-08-19 23:22:58 +02:00
eeintech
ec7392303d Fixed company templates 2021-08-19 10:47:46 -04:00
Oliver
c16ce925dd Merge pull request #1973 from SchrodingersGat/delete-expired-sessions
Run periodic (daily) task to clear out expired sessions
2021-08-19 16:53:19 +10:00
Oliver
f0415640d5 Run periodic (daily) task to clear out expired sessions 2021-08-19 16:34:57 +10:00
Oliver
c3048a1bf1 Merge pull request #1970 from SchrodingersGat/entrypoint
Entrypoint
2021-08-19 12:12:01 +10:00
Oliver
9ed2025021 Add a TODO for future reference 2021-08-19 11:14:13 +10:00
Oliver
52bdfe5465 Env interpolation doesn't seem to work in the CMD 2021-08-18 20:52:14 +10:00
Oliver
eeac561b9b typo fix 2021-08-18 17:07:23 +10:00
Oliver
2095d66677 Fix entrypoint / cmd for production server 2021-08-18 16:29:54 +10:00
Oliver
79d7a9f922 fix typo in dockerfile 2021-08-18 15:16:22 +10:00
Oliver
41db0ff60d Need to specify python3 2021-08-18 14:58:16 +10:00
Oliver
db477bceab typo fix 2021-08-18 14:47:34 +10:00
Oliver
d756579a06 Split production environment variables out into a .env file 2021-08-18 13:02:36 +10:00
Oliver
c1ea6dbb9b Remove commented out functionality from the entrypoint command 2021-08-18 12:28:09 +10:00
Oliver
c2af401854 Pin base python package requirements
- Require invoke to be installed before we can run "invoke update"
2021-08-18 12:03:24 +10:00
Oliver
8fea9bc645 Re-add docker file git version info 2021-08-18 11:25:19 +10:00
Oliver
7bfddd6d51 Simplify init scripts
Single script init.sh which performs the following tasks:
- Creates required directory structure
- Activates python venv (if required)
- Waits for database connection
- Runs command
2021-08-18 09:52:27 +10:00
Oliver
3b8ee48581 Fix env defines in dockerfile 2021-08-18 09:34:09 +10:00
Oliver
da834d8bcc Reduce cruft in logs 2021-08-18 00:04:38 +10:00
Oliver
b48db6f8fe Dockerfile fixes 2021-08-17 23:15:05 +10:00
Oliver
187c9b0971 Add server init script
- Taken (mostly) from https://github.com/inventree/InvenTree/pull/1949
2021-08-17 23:10:57 +10:00
Oliver
8b66babd49 Refactor dockerfile
- Ref: https://github.com/inventree/InvenTree/pull/1949
- Squash all apk commands into single line
- Drop to inventree user rather than running as root
- Separate entrypoint and cmd for each target
- Set the INVENTREE_PY_ENV variable in development mode
2021-08-17 22:58:44 +10:00
Oliver
b6e97f06dd Merge pull request #1968 from SchrodingersGat/docker-internal-vars
Cleanup docker vars for dev setup
2021-08-17 21:18:09 +10:00
Oliver
0294a1c323 Fix for staticfile collection
- Was generating a *lot* of warning messages
- Ref: https://github.com/django-compressor/django-compressor/issues/720
2021-08-17 21:02:45 +10:00
Oliver
895f9f3ce0 Pull debug level out into the .env file 2021-08-17 20:45:57 +10:00
Oliver
d5d89c67b1 Error out if the static or media directories are not properly defined 2021-08-17 20:42:19 +10:00
Oliver
a474000361 Fix critical error in dockerfile
- Don't' be putting no spaces in!
2021-08-17 20:29:48 +10:00
Oliver
7bf3229595 Add comment to docker-compose file 2021-08-17 20:00:54 +10:00
Oliver
07857c3088 Simplify dev-config.env file
- Don't need to re-specify the internal docker variables
- Add comments
2021-08-17 19:59:32 +10:00
Oliver
206743b58d Add a default value for INVENTREE_WEB_ADDR 2021-08-17 19:58:55 +10:00
Oliver
a5808d4360 Merge pull request #1967 from SchrodingersGat/always-translate
Run translation step as part of "update"
2021-08-17 19:52:58 +10:00
Oliver
92aace1278 Run translation step as part of "update" 2021-08-17 18:22:07 +10:00
Guusggg
d8eefec065 Print multi part label (#1963)
* Added description as list for StockLocation

* Merge pull request #1874 from SchrodingersGat/docker-dev-fix

Copy static files when starting dev server

(cherry picked from commit 50eb70f538)

* Merge pull request #1877 from eeintech/fix_search_js

Fixed missing comma propagating to translated JS files

(cherry picked from commit 2009773d9d)

* Merge pull request #1890 from matmair/fix-for-1888

catch connection errors in exchange update

(cherry picked from commit db57e9516b)

* Merge pull request #1887 from matmair/settings-safety

settings fixes

(cherry picked from commit d154ca08ea)

* 0.4.2

* Merge pull request #1894 from SchrodingersGat/non-int-serial-fix

Fix for non-integer serial numbers

(cherry picked from commit 529742b520)

* 0.4.4

Bump release version

* Bump version number -> 0.4.5

* Added a simple menu item to print multiple part labels. This does not follow the style of the Stock label functions but it works!

* Revert "Added description as list for StockLocation"

This reverts commit f5178e9fc3.

* Added the right version number

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2021-08-17 12:42:40 +10:00
Oliver
d6c9ff41ff Merge pull request #1964 from eeintech/import_part_nav
Added navbar on part import page
2021-08-17 09:59:35 +10:00
eeintech
99839e78fd Added navbar on part import page 2021-08-16 10:21:57 -04:00
Oliver
fa163b8866 Merge pull request #1962 from SchrodingersGat/attachment-edit
Attachment edit
2021-08-16 11:14:14 +10:00
Oliver
23b2b56de4 StockItemAttachment 2021-08-16 10:56:00 +10:00
Oliver
6141ddc3eb SalesOrderAttachment and PurchaseOrderAttachment 2021-08-16 10:53:28 +10:00
Oliver
f8b22bc7b7 Refactor BuildAttachment model 2021-08-16 10:49:31 +10:00
Oliver
d9f29b4a70 Updates for InvenTree serializer classes
- Catch and re-throw errors correctly
2021-08-16 10:41:26 +10:00
Oliver
3dcf1746e6 Functionality for renaming attached files 2021-08-16 10:41:02 +10:00
Oliver
ff8dcabb12 New custom serializer for handling attachments 2021-08-15 22:43:52 +10:00
Oliver
81a8aac623 Merge pull request #1961 from SchrodingersGat/tweaks
Small tweaks here and there
2021-08-15 22:10:09 +10:00
Oliver
1998dabe9b Small tweaks here and there 2021-08-15 21:47:37 +10:00
Oliver
4061693522 Merge pull request #1959 from SchrodingersGat/settings-context
Provide global_settings and user_settings as context objects
2021-08-15 12:57:15 +10:00
Oliver
8861ffad81 PEP fixes 2021-08-15 12:06:31 +10:00
Oliver
cef09acd54 Partial reversion of some stuff 2021-08-15 12:05:53 +10:00
Oliver
faab1f2464 Provide global_settings and user_settings as context objects
- Adds a new context middleware
- Refactor the way that settings are provided to the javascript layer
2021-08-15 11:57:05 +10:00
Oliver
6c17e330c4 Merge pull request #1958 from SchrodingersGat/better-form-errors
Better form errors
2021-08-14 13:56:33 +10:00
Oliver
28bccea57b Cleanup 2021-08-14 13:43:38 +10:00
Oliver
32fafc76d7 css tweaks 2021-08-14 13:42:50 +10:00
Oliver
f753e11f10 Improve error notification for modal forms
- Scroll to error
- Add red border and background to the form
2021-08-14 13:41:19 +10:00
Oliver
f72eb4266a remove old debug message 2021-08-14 12:31:22 +10:00
Oliver
1db654e990 Merge pull request #1956 from SchrodingersGat/supplier-part-from-form
Supplier part from form
2021-08-14 12:12:09 +10:00
Oliver
2b13512145 Check that supplier and manufacturer parts are created 2021-08-14 10:43:45 +10:00
Oliver
6fa4e33062 Unit testing for new API form features 2021-08-14 10:39:05 +10:00
Oliver
26c07961cb Bug fix for API 2021-08-14 10:23:57 +10:00
Oliver
6eb4709658 Adds initial stock quantity 2021-08-14 10:23:42 +10:00
Matthias
00d4efb920 PEP fix 2021-08-13 17:54:17 +02:00
Matthias
f0325fe30f view BOMpricing range
Closes #1889
2021-08-13 17:50:41 +02:00
Matthias
a2ffd06abf calculate purchase price for part 2021-08-13 17:49:58 +02:00
Oliver Walters
2be9399d2c CSS style fixes 2021-08-14 01:15:43 +10:00
Oliver Walters
ad844c4393 Simplify rendering of checkboxes in forms
- Display "inline" so they take up much less vertical space
2021-08-14 01:05:06 +10:00
Oliver Walters
ba1ba67f87 Only add company data if part is purchaseable 2021-08-14 00:46:30 +10:00
Oliver Walters
78340a71a9 Adds support for creation of ManufacturerPart and SupplierPart via the Part creation API 2021-08-14 00:38:08 +10:00
Oliver Walters
6218f1c7e6 Add form elements for initializing a part with supplier data 2021-08-14 00:26:22 +10:00
Oliver Walters
5cbb67b91c Add options to show / hide form groups 2021-08-14 00:20:34 +10:00
Oliver Walters
cb11df4dba Improve error checking for initial stock creation when creating a new part
- Use @transaction.atomic
- Raise proper field errors
2021-08-14 00:09:08 +10:00
Oliver Walters
1396c349c8 Refactor form field definition copying 2021-08-14 00:08:26 +10:00
Oliver Walters
5b42ab7332 Add "groups" to API forms 2021-08-13 21:48:48 +10:00
Oliver
cd4a797e71 Merge pull request #1954 from eeintech/upload_po_file
Improved creation of purchase order line items from file upload
2021-08-13 09:31:22 +10:00
Oliver
e8d47a4c76 Merge pull request #1953 from SchrodingersGat/bom-unit-tests
Add extra unit testing for BOM export
2021-08-13 09:06:29 +10:00
eeintech
9205d6d67c Improved creation of purchase order line items from file upload 2021-08-12 14:27:00 -04:00
Oliver
26ddd36666 PEP fixes 2021-08-12 23:47:42 +10:00
Oliver
537573d0e3 Add extra unit testing for BOM export 2021-08-12 23:40:07 +10:00
Oliver
1da004d30a Merge pull request #1952 from SchrodingersGat/dockerfile-fix
Dockerfile fix
2021-08-12 22:34:41 +10:00
Oliver
7df4451c08 Move some core pypi deps into requirements file 2021-08-12 22:06:47 +10:00
Oliver
a3ff90754d Specify tag when publishing release build to docker hub 2021-08-12 22:01:42 +10:00
Oliver
31bb7734ce Update dockerfile to allow downloading against a specific git tag 2021-08-12 22:01:14 +10:00
Oliver
fcff8d4825 Merge pull request #1944 from SchrodingersGat/report-unit-tests
Unit testing for report framework
2021-08-12 16:05:49 +10:00
Oliver
f59ed27cf9 Remove reliance on hard-coded PK values 2021-08-12 15:14:13 +10:00
Oliver
e36b1e6c70 PEP fixes 2021-08-12 14:51:18 +10:00
Oliver
6748f37405 Unit tests for report printing 2021-08-12 14:43:04 +10:00
Oliver
96ec8c4eb6 Copy report templates across as part of test setUp 2021-08-12 13:40:08 +10:00
Oliver
032057c93a PEP fixes 2021-08-12 13:18:10 +10:00
Oliver
7665e83001 Merge pull request #1947 from eeintech/supplier_part
Hook to connect ManufacturerPart to SupplierPart using name/MPN
2021-08-12 09:15:20 +10:00
eeintech
91e314ddb5 Only connect ManufacturerPart if a. it exists b. SupplierPart is not yet connected 2021-08-11 17:08:46 -04:00
eeintech
a2590f1a3b Merged master 2021-08-11 16:16:20 -04:00
Oliver
44818ca0c5 Some simple API unit tests 2021-08-11 17:40:00 +10:00
Oliver
3cdcdd0535 Create report templates when testing 2021-08-11 11:07:30 +10:00
Oliver
47c385cac2 Bump version number -> 0.4.5 2021-08-11 00:30:14 +10:00
Oliver
aea43924ae Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-11 00:29:36 +10:00
Oliver
2cf7592198 Merge pull request #1941 from SchrodingersGat/lazy-loading
Adds one-shot function when a panel is displayed
2021-08-11 00:29:06 +10:00
Oliver
46fa60953d Refactor part page 2021-08-11 00:12:55 +10:00
Oliver
68282c93f4 Start API calls before the panel has finished loading 2021-08-11 00:12:48 +10:00
Oliver
a1922bff81 Adds one-shot function when a panel is displayed 2021-08-11 00:09:01 +10:00
Oliver
b94104f7ab Merge pull request #1940 from SchrodingersGat/stock-table-fix
Bug fix for stock table
2021-08-10 23:52:55 +10:00
Oliver
bfc489a35b Merge pull request #1939 from SchrodingersGat/transfer-stock-bug
Bug fix for stock transfer form
2021-08-10 23:39:31 +10:00
Oliver
535c36b75e Bug fix for stock table
- Use the provided table name, rather than hard-coded value

(cherry picked from commit b3a52dd6c65a83f2f330c0275b443e9acbcbdf73)
2021-08-10 23:31:20 +10:00
Oliver
1bf2a3e23f Merge pull request #1938 from SchrodingersGat/auth-bug
Fix bug when using token based auth
2021-08-10 23:24:01 +10:00
Oliver
4c8eaf3942 Bug fix for stock transfer form 2021-08-10 23:23:02 +10:00
Oliver
799f17ef50 Bypass custom token auth for /api/ endpoint 2021-08-10 23:09:54 +10:00
Oliver
7ef5c0058e Fix bug when using token based auth 2021-08-10 22:50:49 +10:00
Oliver
b92ec751ef Merge pull request #1934 from markdedeuge/bugfix/timezone_heartbeat
use django timezone'd datetime to squash timezone warnings from worke…
2021-08-10 15:16:42 +10:00
markdedeugeQBE
641233b140 use django timezone'd datetime to squash timezone warnings from worker heartbeat 2021-08-10 14:37:05 +10:00
Oliver
0e0f490f8d Merge pull request #1932 from SchrodingersGat/supplier-part-bug-fix
Supplier part bug fix
2021-08-10 11:18:02 +10:00
Oliver
3df7299a61 Merge pull request #1931 from markdedeuge/patch-1
Update nginx.conf to use http_host rather than host fixes #1930
2021-08-10 11:04:56 +10:00
Oliver
c32b6b2272 Hide the "part" field when editing manufacturer part and supplier part objects 2021-08-10 11:01:17 +10:00
Oliver
e03afce335 Add "instance_filters" for SupplierPart model
- Restrict the "manufacturer_part" query based on the current part
2021-08-10 11:00:27 +10:00
Oliver
7117c33379 Raise validation error if the manufacturer part does not point to the correct part 2021-08-10 10:58:11 +10:00
Mark De Deuge
fc06bc7574 Update nginx.conf to use http_host rather than host fixes #1930
Using proxy_set_header Host $host; does not pass through the port. This causes the /api-doc/ route to miss the port when attempting to render routes. 
This fixes: #1930
2021-08-10 10:27:40 +10:00
Oliver
6620d34f25 Merge pull request #1913 from eeintech/bom_upload
BOM upload templates fixes
2021-08-10 09:11:25 +10:00
Oliver
0a1ce59dfc Merge pull request #1858 from eeintech/exchange_rate_task
Exchange rate as worker task
2021-08-10 08:23:46 +10:00
eeintech
69d1c3cea2 Improved task import to support global 2021-08-09 11:55:56 -04:00
eeintech
372d252333 Merge branch 'master' of github.com:inventree/InvenTree into exchange_rate_task 2021-08-09 10:47:35 -04:00
Oliver
98211f1ae1 Merge pull request #1928 from erkutalakus/hotfix/unlocalization-of-item-quantity
Localization of item.quantity removed
2021-08-09 21:42:07 +10:00
Erkut Alakuş
c564896355 Localization of item.quantity removed
Localization of quantity for different cultures(turkish in my case) using comma(,) instead of dot(.) leads syntax error in javascript code and prevents stock item history to load.
2021-08-09 12:11:53 +03:00
Oliver
50198c0f1e Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-09 16:19:47 +10:00
Oliver
970d2ac1f8 Merge pull request #1926 from SchrodingersGat/api-bump
Bump API version to from 8 -> 9
2021-08-09 16:19:26 +10:00
Oliver
bb8b9dfcec Bump API version to from 8 -> 9
(Also moved the API version info from version.py to
2021-08-09 14:54:07 +10:00
Oliver
90d753001f Merge pull request #1925 from matmair/fix-price-breaksfilters
Fix for missing part filter
2021-08-09 14:49:49 +10:00
Matthias
ad656b7ca7 extending API to supply price wihtout formatting 2021-08-09 01:49:55 +02:00
Oliver
a846334698 0.4.4
Bump release version
2021-08-09 09:45:56 +10:00
Oliver
e8d4e2a7e6 Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-09 09:45:13 +10:00
Oliver
9565b3004d L10 (#1924)
* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2021-08-09 09:44:32 +10:00
Matthias
c58ed5a07e Fixes #1915 2021-08-09 01:43:50 +02:00
Oliver
681f285aa3 Merge pull request #1923 from SchrodingersGat/secondary-modals
Secondary modals
2021-08-08 01:13:42 +10:00
Oliver Walters
e3efd12184 secondary for purcahse order 2021-08-08 00:50:59 +10:00
Oliver Walters
52ba2201b2 secondary for creating sales order customers 2021-08-08 00:49:16 +10:00
Oliver Walters
4e6c8c45ee secondary modal for part form 2021-08-08 00:44:46 +10:00
Oliver Walters
1dc5682767 bug fix 2021-08-08 00:44:30 +10:00
Oliver
0ad206d9eb Merge pull request #1922 from SchrodingersGat/secondary-modals
Secondary modals
2021-08-08 00:06:45 +10:00
Oliver Walters
720b332f71 Adds secondary to manufacturerpart form 2021-08-07 23:49:50 +10:00
Oliver Walters
94c1ed882f Add secondary field options for "Create Supplier Part" form
- Supplier
- Manufacturer Part
2021-08-07 23:42:42 +10:00
Oliver Walters
b960ce839a remove debug statement 2021-08-07 23:31:21 +10:00
Oliver Walters
fd917b2e41 Simple refactoring 2021-08-07 23:30:53 +10:00
Oliver Walters
25af8559ba Back-fill newly created model data into the parent modal form 2021-08-07 23:27:31 +10:00
Oliver Walters
759a3724b5 Add function to extract all data from a displayed form 2021-08-07 23:09:56 +10:00
Oliver
0d80ae9f93 Merge pull request #1921 from SchrodingersGat/label-print-options
Add inline option for reports, too
2021-08-07 22:49:55 +10:00
Oliver Walters
e583d1a159 Actually use the variable, I suppose 2021-08-07 22:30:51 +10:00
Oliver Walters
f405e4b701 Add inline option for reports, too 2021-08-07 22:28:48 +10:00
Oliver
5448165ef3 Merge pull request #1920 from SchrodingersGat/label-print-options
Label print options
2021-08-07 22:27:34 +10:00
Oliver Walters
ca9536f687 Implement option to display labels "inline" in the browser 2021-08-07 22:09:15 +10:00
Oliver
8e8696eda9 Merge pull request #1919 from SchrodingersGat/template-name-fix-2
Add model validator to prevent illegal names for PartParameterTemplate
2021-08-07 22:00:11 +10:00
Oliver Walters
d77b99c0ca Add user settings for report and labels 2021-08-07 21:57:41 +10:00
Oliver Walters
174ac64235 Allow downloaded files to be inline or attachments 2021-08-07 21:45:18 +10:00
Oliver Walters
24638a7229 Add migration file 2021-08-07 21:41:45 +10:00
Oliver
7629077deb Merge pull request #1918 from SchrodingersGat/version-number-check
Check release tag before publishing docker image
2021-08-07 21:35:03 +10:00
Oliver Walters
6d42cfab75 Add model validator to prevent illegal names for PartParameterTemplate
(cherry picked from commit 93805a87e0)
2021-08-07 21:23:52 +10:00
Oliver Walters
e72e34413d Check release tag before publishing docker image 2021-08-07 21:21:09 +10:00
Oliver
512eceb2a6 Merge pull request #1916 from SchrodingersGat/part-params-fix
Fix part settings page
2021-08-07 21:07:30 +10:00
Oliver Walters
2e5d5bcc84 Fix part settings page 2021-08-07 20:50:32 +10:00
Oliver
6234581fab Update README.md 2021-08-07 11:16:37 +10:00
eeintech
6280ed1ade Moved enableNavbar to part_base template 2021-08-06 11:15:16 -04:00
eeintech
1eb8a9f310 BOM upload templates fixes 2021-08-05 17:39:08 -04:00
eeintech
1bf49a1458 Re-added ability to link manufacturer part to supplier part via API 2021-08-05 14:06:31 -04:00
Oliver
ce62da5a42 Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-05 23:35:34 +10:00
Oliver
76572bf82f Merge pull request #1907 from matmair/trans-improv
translation improvement
2021-08-05 20:28:45 +10:00
Matthias Mair
96378cb556 Merge branch 'inventree:master' into trans-improv 2021-08-05 08:17:21 +02:00
Oliver
599c53ea53 Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-05 13:24:47 +10:00
Oliver
a45437dac8 Merge pull request #1909 from SchrodingersGat/new-weasyprint
Pin weasyprint version to 52.5
2021-08-05 13:24:27 +10:00
Oliver
00ffab472c Fix for build report template 2021-08-05 10:44:47 +10:00
Oliver
fa6daeb679 Pin weasyprint version to 52.5 2021-08-05 10:30:38 +10:00
Matthias
d6c6cb96ba make keyvalue non-existing key tolerant 2021-08-05 01:24:49 +02:00
Matthias
58f2dce18d show translation level in ui 2021-08-05 01:23:11 +02:00
Matthias
d6672372a5 script to save the locale stats 2021-08-05 00:44:02 +02:00
Oliver
96b5f70c21 Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-05 08:43:04 +10:00
Oliver
be67832821 Merge pull request #1908 from eeintech/fix_typo
Fixed typo for build responsible column header
2021-08-05 08:14:51 +10:00
Oliver
38815211af Merge pull request #1904 from SchrodingersGat/part-forms
Refactor Part creation and editing forms
2021-08-05 08:14:32 +10:00
eeintech
c0ccb8f588 Fixed typo for build responsible column header 2021-08-04 17:11:35 -04:00
Matthias
3ecb1e6577 cleaner structure 2021-08-04 19:44:01 +02:00
eeintech
fbdf11e6e7 Merged run_task code into offload_task function
Added option to force synchronous operation
Use that option for update_exchange_rates
2021-08-04 11:23:52 -04:00
Oliver Walters
c7712d4235 even more unit tests 2021-08-05 01:13:48 +10:00
Oliver Walters
655e5692e9 More unit test fixes 2021-08-05 00:58:07 +10:00
Oliver Walters
6acff2a26e Fixes unit test 2021-08-05 00:40:02 +10:00
Oliver Walters
aaf394ca7a PEP fixes 2021-08-05 00:26:21 +10:00
Oliver Walters
dd78464a74 remove unused function 2021-08-05 00:25:47 +10:00
Oliver Walters
aa4ed9feb0 Refactor MakeVariant form
- Now is essentially identical to the DuplicatePart form
- Uses the API form structure
2021-08-05 00:24:38 +10:00
eeintech
1b79ef940e Merge branch 'master' of github.com:inventree/InvenTree into exchange_rate_task 2021-08-04 10:22:14 -04:00
Oliver Walters
0e8fb6a5ad Refactored DuplicatePart form
- API endpoint now takes care of duplication of other data
2021-08-05 00:16:42 +10:00
Oliver Walters
2cb0b448b7 Fix error message styles for API errors
- django ValidationError uses "__all__" key for non_field_errors
- whyyyyyyyyyyyy
2021-08-05 00:15:55 +10:00
Oliver Walters
408ff639dd Adds ability to pre-fill a form with a complete dataset 2021-08-04 23:48:21 +10:00
Oliver Walters
1fafaf8577 Refactor partfields function (was essentially duplicated) 2021-08-04 23:29:39 +10:00
Oliver Walters
b04f22fc53 CreatePart form now uses the API
- Simplify the way category parameter templates are copied
2021-08-04 23:27:16 +10:00
Oliver Walters
2bf3e3ab02 Function to construct part form fields 2021-08-04 23:26:17 +10:00
Oliver Walters
a64ee23afc Add more options for form rendering
- "before" a field
- "after" a field
- pure "eye candy" field
2021-08-04 23:16:11 +10:00
Oliver
5aa111b0aa Merge pull request #1902 from SchrodingersGat/bom-item-form
Use API forms for creating and editing BomItem objects
2021-08-04 18:06:42 +10:00
Oliver Walters
2e8a490ca9 Fixes for unit tests 2021-08-04 17:41:47 +10:00
Oliver Walters
75a1be0284 Use API forms for creating and editing BomItem objects 2021-08-04 17:25:51 +10:00
Matthias
efd4644045 translation information 2021-08-04 07:55:58 +02:00
Oliver
96a79e557b Merge pull request #1901 from SchrodingersGat/table-refresh
Adds a button to tables to reload data
2021-08-04 14:59:51 +10:00
Oliver
1f70538b04 Adds a button to tables to reload data 2021-08-04 14:24:17 +10:00
Oliver
db6d7c2d27 Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-04 12:32:36 +10:00
Oliver
7911801dbf Merge pull request #1900 from SchrodingersGat/part-image-search
Make the part thumbnail selection window searchable
2021-08-04 12:28:52 +10:00
Oliver
56c0e289bd Style fix 2021-08-04 12:13:24 +10:00
Oliver
6cd87e830d Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-04 12:12:12 +10:00
Oliver
f95346f214 Make the part thumbnail selection window searchable 2021-08-04 12:10:49 +10:00
Oliver
7545591c59 Merge pull request #1899 from SchrodingersGat/cat-create
Refactor "CreatePartCategory" form to API
2021-08-04 11:52:21 +10:00
Oliver
989983bdb5 Fixed missing import 2021-08-04 11:37:59 +10:00
Oliver
83d8226ad6 Refactor "CreatePartCategory" form to API
(cherry picked from commit 06ff961564)
2021-08-04 11:34:42 +10:00
Oliver
c4570a79de Merge remote-tracking branch 'inventree/master' into 0.4.x 2021-08-04 09:04:24 +10:00
Oliver
8daf601f00 Merge pull request #1897 from matmair/price-terms
updating language to be clearer
2021-08-04 09:03:13 +10:00
Oliver
69f242d11d Merge pull request #1892 from eeintech/stock_installed_items
Re-enabled installing stock items into others
2021-08-04 09:01:28 +10:00
Oliver
910c57c92d Merge pull request #1895 from eeintech/fix_has_ipn_filter
'has_ipn' filter method did not return queryset
2021-08-04 08:55:49 +10:00
Matthias
fa3c5ae108 updating language to be clearer
see https://github.com/inventree/InvenTree/issues/1889#issuecomment-891901070
2021-08-04 00:45:56 +02:00
eeintech
29c8daed0a 'has_ipn' filter method did not return queryset 2021-08-03 12:21:44 -04:00
eeintech
172a08fbba Removed old quantity setting lines 2021-08-03 09:53:08 -04:00
Oliver
073bb7c488 Merge pull request #1894 from SchrodingersGat/non-int-serial-fix
Fix for non-integer serial numbers

(cherry picked from commit 529742b520)
2021-08-03 10:06:19 +10:00
Oliver
529742b520 Merge pull request #1894 from SchrodingersGat/non-int-serial-fix
Fix for non-integer serial numbers
2021-08-03 10:03:05 +10:00
Oliver
f057937df0 Fix for non-integer serial numbers 2021-08-03 09:46:28 +10:00
eeintech
1c4924a4a5 Style duh 2021-08-02 15:14:55 -04:00
eeintech
ac3dcac641 Re-enabled installing stock items into others 2021-08-02 15:05:24 -04:00
Oliver
9aa5086067 Merge pull request #1819 from eeintech/part_main_details
Cleaner part details
2021-08-02 08:47:18 +10:00
Oliver
b18f360daf 0.4.2 2021-08-02 08:43:04 +10:00
Oliver
20cc952982 Merge pull request #1887 from matmair/settings-safety
settings fixes

(cherry picked from commit d154ca08ea)
2021-08-02 08:42:34 +10:00
Oliver
cd39fd1dc2 Merge pull request #1890 from matmair/fix-for-1888
catch connection errors in exchange update

(cherry picked from commit db57e9516b)
2021-08-02 08:42:26 +10:00
Oliver
d154ca08ea Merge pull request #1887 from matmair/settings-safety
settings fixes
2021-08-02 08:38:34 +10:00
Oliver
db57e9516b Merge pull request #1890 from matmair/fix-for-1888
catch connection errors in exchange update
2021-08-02 08:34:52 +10:00
Matthias
0f11ab527f PEP fix 2021-08-01 20:58:57 +02:00
Matthias
83dab558d7 catch connection errors in exchange update
#Fixes #1888
2021-08-01 20:44:26 +02:00
Matthias
55762f2a96 do not use safe in template
that can cause wrong escaping and generally is considered unsafe
2021-08-01 01:41:46 +02:00
Matthias
c0921fc7ce removing unneeded prints 2021-08-01 01:16:10 +02:00
Matthias
ae8e58ac12 invoke task for celan_settings 2021-08-01 01:06:17 +02:00
Matthias
2347f15c2e new command to cleanup old settings in db 2021-08-01 01:05:43 +02:00
Matthias
369864574e only include setting in the settings that have a key 2021-07-30 23:25:45 +02:00
eeintech
634e5e0da6 Added toggle for part details
Added persistence for page refresh or new part page
2021-07-30 14:55:12 -04:00
eeintech
20b21a2b71 Merge branch 'master' of github.com:inventree/InvenTree into part_main_details 2021-07-30 10:50:28 -04:00
Oliver
7ed43f5a11 Merge pull request #1886 from inventree/revert-1885-docker-publish
Revert "Publish on tags also"
2021-07-30 13:39:49 +10:00
Oliver
1d19393442 Revert "Publish on tags also" 2021-07-30 12:42:03 +10:00
Oliver
6d0b01d0fb Merge pull request #1885 from SchrodingersGat/docker-publish
Publish on tags also
2021-07-30 12:33:31 +10:00
Oliver
13898d6687 Publish on tags also 2021-07-30 11:51:06 +10:00
Oliver
0e59c15773 0.4.1 2021-07-30 11:26:53 +10:00
Oliver
eb883d7e70 Merge pull request #1884 from SchrodingersGat/typo-fix
logging.get -> logging.getLogger
2021-07-30 00:09:43 +10:00
Oliver Walters
d9f4c34a42 logging.get -> logging.getLogger 2021-07-29 23:44:52 +10:00
Oliver
3806e3ebeb Merge pull request #1880 from SchrodingersGat/settings-fix
Bug fix
2021-07-29 17:56:45 +10:00
Oliver
c39e3aaa82 Bug fix 2021-07-29 17:52:24 +10:00
Oliver
60e4022568 Merge pull request #1879 from SchrodingersGat/docker-improvements
Specify how many workers to use
2021-07-29 17:19:41 +10:00
Oliver
542c204ca0 PEP fixes 2021-07-29 16:39:51 +10:00
Oliver
dd12a593f4 Specify how many workers to use 2021-07-29 16:37:34 +10:00
Oliver
935ef968de Merge pull request #1878 from SchrodingersGat/js-template-stuff
Js template stuff
2021-07-29 13:42:47 +10:00
Oliver
7756c766c3 Fix stock.js 2021-07-29 12:35:21 +10:00
Oliver
4381a16b0e Template cleanup 2021-07-29 12:31:07 +10:00
Oliver
6fe5f0e0e6 Fixes for order.js 2021-07-29 11:58:32 +10:00
Oliver
ba5479090a Fix nav.js 2021-07-29 11:54:04 +10:00
Oliver
28bf5bfdbc Fix table_filters.js 2021-07-29 11:52:50 +10:00
Oliver
a222efda33 Fix rendering issues 2021-07-29 11:43:50 +10:00
Oliver
27ec65a002 Add 'settings.js' which provides all settings (global and user) as a dynamic javascript file
- Minimal database hits required
2021-07-29 11:28:04 +10:00
Oliver
915756eacf Improve test output 2021-07-29 09:28:08 +10:00
Oliver
8e97d14f1f Rename CI test 2021-07-29 09:26:56 +10:00
Oliver
14aebfdae1 Split dynamic javascript files into two separate directories
- One gets translated and is served statically
- One does not get translated and is served dynamically
- Add CI step
2021-07-29 09:23:24 +10:00
Oliver
bc3c3be751 force linux-style line endings for .sh files 2021-07-29 09:10:46 +10:00
Oliver
0a73032950 Merge pull request #1877 from eeintech/fix_search_js
Fixed missing comma propagating to translated JS files

(cherry picked from commit 2009773d9d)
2021-07-29 08:27:49 +10:00
Oliver
2009773d9d Merge pull request #1877 from eeintech/fix_search_js
Fixed missing comma propagating to translated JS files
2021-07-29 08:27:20 +10:00
eeintech
d43312d162 Missing comma propagating to translated JS files 2021-07-28 13:29:12 -04:00
Oliver
430f737953 Merge pull request #1876 from SchrodingersGat/mpn-api
Adds an API filter class for the ManufacturerPart list endpoint
2021-07-29 00:23:44 +10:00
Oliver
baa6283d20 Fixes 2021-07-28 23:47:50 +10:00
Oliver
5744796506 Adds an API filter class for the ManufacturerPart list endpoint 2021-07-28 23:32:49 +10:00
Oliver
a7229b5b0b Merge pull request #1874 from SchrodingersGat/docker-dev-fix
Copy static files when starting dev server

(cherry picked from commit 50eb70f538)
2021-07-28 22:50:31 +10:00
Oliver
50eb70f538 Merge pull request #1874 from SchrodingersGat/docker-dev-fix
Copy static files when starting dev server
2021-07-28 22:50:03 +10:00
Oliver
399e44fce7 Copy static files when starting dev server 2021-07-28 22:30:41 +10:00
Oliver
20b6e0fd1a Update version.py 2021-07-28 15:46:52 +10:00
Oliver
9d9bfd6c30 Update version.py
0.4.0 release
2021-07-28 15:46:20 +10:00
Oliver
5dc11ad8e9 Merge pull request #1873 from SchrodingersGat/translation
Translation
2021-07-28 15:45:08 +10:00
Oliver
839cd55f20 Merge branch 'l10' into translation
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/el/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/locale/fr/LC_MESSAGES/django.po
#	InvenTree/locale/he/LC_MESSAGES/django.po
#	InvenTree/locale/id/LC_MESSAGES/django.po
#	InvenTree/locale/it/LC_MESSAGES/django.po
#	InvenTree/locale/ja/LC_MESSAGES/django.po
#	InvenTree/locale/ko/LC_MESSAGES/django.po
#	InvenTree/locale/nl/LC_MESSAGES/django.po
#	InvenTree/locale/no/LC_MESSAGES/django.po
#	InvenTree/locale/pl/LC_MESSAGES/django.po
#	InvenTree/locale/ru/LC_MESSAGES/django.po
#	InvenTree/locale/sv/LC_MESSAGES/django.po
#	InvenTree/locale/th/LC_MESSAGES/django.po
#	InvenTree/locale/tr/LC_MESSAGES/django.po
#	InvenTree/locale/vi/LC_MESSAGES/django.po
#	InvenTree/locale/zh/LC_MESSAGES/django.po
2021-07-28 15:23:10 +10:00
Oliver
78ed2776d1 Merge pull request #1863 from SchrodingersGat/settings-refactor
Refactoring existing settings views
2021-07-28 15:04:37 +10:00
Oliver
6fd70e4741 Fix search settings page 2021-07-28 14:18:42 +10:00
Oliver
cd1ecc5e8f style fixes 2021-07-28 14:17:25 +10:00
Oliver
1fe00ef7df Refactor 'category' setttings 2021-07-28 14:16:55 +10:00
Oliver
25ff74835d Refactor PartCategoryParameter API 2021-07-28 14:05:49 +10:00
Oliver
29b496b588 Merge pull request #1870 from eeintech/fix_1864
Fix user setting query
2021-07-28 07:01:46 +10:00
Oliver
d6420341f4 Merge pull request #1871 from eeintech/stock_item_remove_redirect
Redirect to stock index if stock item is completely depleted
2021-07-28 07:00:47 +10:00
eeintech
e9be3fb4ec Redirect to stock index if stock item is completely depleted 2021-07-27 11:11:30 -04:00
eeintech
4e3635d1fe Exact query on ID made the PostGreSQL DB choke 2021-07-27 10:05:22 -04:00
Oliver
c08cb43c39 Template rendering fix for inventree.js 2021-07-27 17:22:44 +10:00
Oliver
a93d96de58 Cleanjup 2021-07-27 17:13:02 +10:00
Oliver
990b987692 Reload settings values "live" (without a page refresh) 2021-07-27 17:03:37 +10:00
Oliver
46d5a6f00b - Convert "PART_RECENT_COUNT" to user setting
- Convert "STOCK_RECENT_COUNT" to user setting
2021-07-27 14:53:32 +10:00
Oliver
33a0b73a05 Convert SEARCH_PREVIEW_RESULTS to a "user" setting 2021-07-27 14:44:51 +10:00
Oliver
3e0655a9d8 Add "homepage" settings page 2021-07-27 14:34:23 +10:00
Oliver
7fdc0546b4 Merge remote-tracking branch 'inventree/master' into settings-refactor 2021-07-27 14:28:17 +10:00
Oliver
985870d626 Translation merge (#1869)
* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2021-07-27 13:11:46 +10:00
Oliver
fff4f27816 Merge pull request #1868 from SchrodingersGat/new-locales
Support more language codes
2021-07-27 09:48:02 +10:00
Oliver
461238f8ae Locale name fix 2021-07-27 08:57:33 +10:00
Oliver
783f43db5f Support more language codes 2021-07-27 08:53:50 +10:00
Oliver
cfd4626c96 More PEP cleanin 2021-07-27 08:33:41 +10:00
Oliver
35d64b7069 PEP cleanup 2021-07-27 08:33:22 +10:00
Oliver
de2d9b30ec Merge pull request #1867 from SchrodingersGat/delete-fix
inventreeDelete was not returning the promise
2021-07-27 08:32:04 +10:00
Oliver
c63a061cf3 Refactor "theme" selection 2021-07-27 08:31:43 +10:00
Oliver
57551d3ac3 inventreeDelete was not returning the promise 2021-07-27 08:17:53 +10:00
Oliver
0186d23563 inline theme form 2021-07-27 07:56:24 +10:00
Oliver
f9918758dd Merge pull request #1866 from eeintech/fix_1861
Fixes BOM purchase price conversion
2021-07-27 07:35:31 +10:00
eeintech
a6b52a9fae Fix for #1861 2021-07-26 17:02:04 -04:00
eeintech
f61c768bbe Merge branch 'master' of github.com:inventree/InvenTree into part_main_details 2021-07-26 13:59:15 -04:00
Oliver
3349e9ff6c Refactor language selection 2021-07-27 00:58:31 +10:00
Oliver
b7b0574a44 Add "appearance" 2021-07-27 00:38:59 +10:00
Oliver
9b0fbb7006 Separate tab for "barcode" settings 2021-07-27 00:36:41 +10:00
Oliver
ca1c692b15 Refactor "Currency settings" view 2021-07-27 00:29:55 +10:00
Oliver
de89c3997d Refactoring a lot of existing settings views 2021-07-27 00:20:31 +10:00
Oliver
125260160c Merge pull request #1859 from matmair/homepage-settings
User settings
2021-07-26 23:19:05 +10:00
Matthias
aabefc2815 Merge branch 'master' of https://github.com/inventree/InvenTree into homepage-settings 2021-07-25 00:09:34 +02:00
Oliver
bcfb3ac067 Merge pull request #1860 from matmair/fix-for-1775
fix for phantom migration warning
2021-07-24 10:07:07 +10:00
Matthias
4a32bdb7ab fix for phantom migration warning
Closes #1775
2021-07-24 01:30:53 +02:00
Matthias
175b24a794 changing user settings icon 2021-07-24 00:45:37 +02:00
Matthias
a82483dbaa hiding homepage block when no setting is used 2021-07-24 00:44:16 +02:00
Matthias
431b35ed32 new tag for building lists 2021-07-24 00:42:17 +02:00
Matthias
31050f23aa adding all homepage settings 2021-07-24 00:08:46 +02:00
Matthias
32eace0c36 moving settings into own section 2021-07-23 11:05:41 +02:00
Matthias
e97ee95deb typo 2021-07-23 01:09:06 +02:00
Matthias
46b0db8263 more hompage settings 2021-07-23 01:07:28 +02:00
Matthias
e167f27258 get user settings in templates 2021-07-23 00:46:48 +02:00
Matthias
50356afd41 Merge branch 'master' of https://github.com/inventree/InvenTree into homepage-settings 2021-07-23 00:03:21 +02:00
Matthias
7abf70fdd7 style fix 2021-07-22 23:53:17 +02:00
Matthias
3b12b0231e fixing wired unique behaviour 2021-07-22 23:50:51 +02:00
Matthias
5f2bef7ee1 base implementation of user setting 2021-07-22 23:50:09 +02:00
Matthias
3f6c7df7a8 change template setting behaviour for user setting 2021-07-22 23:48:28 +02:00
Matthias
e287860e10 admin for user setting 2021-07-22 23:46:31 +02:00
Matthias
449fc329c9 usersetting edit url 2021-07-22 23:45:34 +02:00
Matthias
7ef87320a0 abstract edit 2021-07-22 23:44:25 +02:00
Matthias
6f5fc528b7 override functions 2021-07-22 23:43:51 +02:00
Matthias
8f374e255e abstract filters and refactor 2021-07-22 23:43:03 +02:00
Matthias
69ff0ac248 ruleset 2021-07-22 23:39:36 +02:00
Matthias
c0d6ef80fc unique model settings 2021-07-22 23:39:19 +02:00
eeintech
3f44233074 Improve import 2021-07-22 16:41:45 -04:00
eeintech
d7028b6d74 Make it generic method instead 2021-07-22 16:34:35 -04:00
eeintech
9b542ed23f Run exchange rate updated as task if worker cluster is running 2021-07-22 15:55:17 -04:00
Oliver
2bf7b61668 Merge pull request #1857 from SchrodingersGat/part-parameters-in-reports
Part parameters in reports
2021-07-21 22:33:39 +10:00
Oliver
964672d6cc Add parameters to template 2021-07-21 22:14:03 +10:00
Oliver
afde997cf9 Expose part parameters to Part label templates 2021-07-21 22:05:52 +10:00
Oliver
20a30f317f Merge pull request #1856 from SchrodingersGat/query-filters
Add instance-specific filters to API OPTIONS data
2021-07-21 21:50:17 +10:00
Oliver
4ee0004c97 Filtering for Build and StockItem 2021-07-21 21:34:16 +10:00
Oliver
9cf372f633 PEP fixes 2021-07-21 21:24:18 +10:00
Oliver
85a40ec418 Tree exclusion for PartCategory and StockLocation 2021-07-21 21:23:30 +10:00
Oliver
bee0a519ef Allow filtering of PartList by exclude_tree 2021-07-21 21:18:01 +10:00
Oliver
df48df8119 Catch recursive tree error for part / variant relationship 2021-07-21 21:10:31 +10:00
Oliver
dad9239a1c Add instance-specific filters to API OPTIONS data 2021-07-21 20:59:55 +10:00
Oliver
5f8c9a0f31 Merge pull request #1855 from SchrodingersGat/search-preview-results
Add an option to configure number of parts in search preview
2021-07-21 15:26:27 +10:00
Oliver
2ffae368f1 Add an option to configure number of parts displayed in search preview box 2021-07-21 15:05:14 +10:00
Oliver
140396ccdd Merge pull request #1854 from SchrodingersGat/url-unit-test
Add unit test for validation of reverse url lookup
2021-07-21 11:09:10 +10:00
Oliver
15b3055e53 Merge pull request #1838 from matmair/search-autocomplete
Search add autocomplete
2021-07-21 10:55:40 +10:00
Oliver
893628d1b8 URL fixes 2021-07-21 10:52:14 +10:00
Oliver
8cb336f581 PEP fixes 2021-07-21 10:42:24 +10:00
Oliver
2d6a78ffb8 Add unit test for validation of reverse url lookup 2021-07-21 10:25:16 +10:00
Oliver
8eeb88a0ea Merge pull request #1850 from SchrodingersGat/api-speed
Api speed
2021-07-21 09:42:31 +10:00
Oliver
598ea11211 Add manager class for StockItem 2021-07-21 09:28:58 +10:00
Oliver
96a065cdb7 Merge pull request #1852 from eeintech/po_destination
Improved handling of PO items destination
2021-07-21 08:09:39 +10:00
eeintech
8ac3d42fd8 Improved handling of po items destination 2021-07-20 17:15:01 -04:00
Matthias
ff07cf5516 cleanup 2021-07-20 18:52:52 +02:00
Matthias
30f94bef41 adding style and picture 2021-07-20 18:51:27 +02:00
Oliver
5e2145e151 Bug fix - delete line which don't belong no more 2021-07-20 22:26:43 +10:00
Oliver
b04a403081 subclass TreeManager 2021-07-20 22:15:49 +10:00
Oliver
cb0b7209ec Add custom "list" function back in
- Actually does make a significant difference to query speed
2021-07-20 22:12:01 +10:00
Oliver
4199e7567f Remove duplicate annotation call 2021-07-20 21:46:27 +10:00
Oliver
dbe550a159 Optimizations for PartList API endpoint:
- Remove custom list() function
- Queryset prefetch now performed by the model manager
2021-07-20 21:37:32 +10:00
Oliver
84fc2785d6 Create a custom Manager class for the Part model
- Always perform prefetch_related calls
2021-07-20 21:26:51 +10:00
Matthias
d0e425ad30 Merge branch 'search-autocomplete' of https://github.com/matmair/InvenTree into search-autocomplete 2021-07-20 07:49:42 +02:00
Matthias
289b030f4e limit results in response 2021-07-20 07:49:21 +02:00
Oliver
d9673244d5 Merge pull request #1849 from SchrodingersGat/url-fix
Fix URL patterns for ManufacturerPart and SupplierPart
2021-07-20 15:21:32 +10:00
Oliver
b0c4a58f30 Fix URL patterns for ManufacturerPart and SupplierPart 2021-07-20 15:06:09 +10:00
Oliver
4600b0d337 Update README.md 2021-07-20 11:35:55 +10:00
Matthias
ce3f7b698d InvenTreeUserSettings added 2021-07-20 01:35:58 +02:00
Matthias
ec53099872 abstracting Settings model 2021-07-20 01:34:35 +02:00
Oliver
17c8dc3441 Merge pull request #1844 from eeintech/po_import
Purchase Order File Upload Update
2021-07-20 07:58:48 +10:00
Oliver
8d04acd5f5 Merge pull request #1846 from matmair/bom-internal
Allow BOM pricing to be valid when using internal pricing - style fix
2021-07-20 07:53:43 +10:00
Matthias Mair
ebb202b19b Merge branch 'inventree:master' into search-autocomplete 2021-07-19 23:39:16 +02:00
eeintech
456710c5ce clean_decimal should also check if the string can be converted to Decimal type 2021-07-19 15:57:51 -04:00
Matthias Mair
c2ce569506 Merge branch 'inventree:master' into bom-internal 2021-07-19 21:51:18 +02:00
eeintech
53f2aa107a Umm watch out for the true fix! 2021-07-19 15:51:04 -04:00
Matthias
8d2e910323 style fix 2021-07-19 21:50:06 +02:00
eeintech
9acd57f8e0 CI was not completely fixed 2021-07-19 15:29:04 -04:00
eeintech
c1db4c7b3d Try to catch encoding error, fixed CI 2021-07-19 15:14:08 -04:00
eeintech
3ab058e84b Fixed default currency selection 2021-07-19 14:49:55 -04:00
eeintech
23db7a89a9 Updated PO upload template, moved call to button, improved cleaned_decimal method to handle comma separator 2021-07-19 14:20:54 -04:00
eeintech
2703ae520e Merge branch 'master' of github.com:inventree/InvenTree into part_main_details 2021-07-19 09:20:06 -04:00
Oliver
af68ea23c3 Merge pull request #1843 from SchrodingersGat/stock-export
Stock export
2021-07-19 17:45:11 +10:00
Oliver
ca36775f62 Merge pull request #1842 from SchrodingersGat/installed-items
Add "installed_items" as a context variable to TestReport
2021-07-19 17:23:56 +10:00
Oliver
4413699844 PEP fixes 2021-07-19 17:23:51 +10:00
Oliver
efb4f194b6 Refactor StockExportOptions form 2021-07-19 17:23:18 +10:00
Oliver
87d4a51575 Add "installed items" section to default TestReport 2021-07-19 16:44:56 +10:00
Oliver
4fdb18318a Add "installed_items" as a context variable to the StockItem TestReport template 2021-07-19 16:32:36 +10:00
Matthias
1d549bcdbd style fix 2021-07-19 07:56:55 +02:00
Oliver
e7d9485c16 Merge pull request #1841 from SchrodingersGat/api-bump
0.3.1
2021-07-19 15:56:39 +10:00
Matthias
43f1e2b8f9 switching back to using extensive apis for search 2021-07-19 07:54:12 +02:00
Oliver
e04bbb016d 0.3.1
Bumped API version to 8
2021-07-19 15:10:57 +10:00
Oliver
44d45050b9 Merge pull request #1840 from SchrodingersGat/bom-table-fix
Fix duplicate table naming
2021-07-19 15:03:31 +10:00
Oliver
40c203c123 Ensure BOM pricing table is loaded 2021-07-19 14:40:02 +10:00
Oliver
bbada3e873 Fix duplicate table naming 2021-07-19 14:34:58 +10:00
Oliver
fa9ef02d23 Merge pull request #1836 from SchrodingersGat/supplier-part-forms
Supplier part forms
2021-07-19 11:17:45 +10:00
Oliver
33e70ec5a7 Unit test fixes 2021-07-19 10:55:23 +10:00
Oliver
efd0caba6e Merge pull request #1829 from matmair/initial-amount
Initial amount
2021-07-19 09:53:40 +10:00
Oliver
565fe9a98e Remove custom creation code for SupplierPart serializer 2021-07-19 09:44:48 +10:00
Matthias
4013abe4de style fix 2021-07-19 01:26:26 +02:00
Matthias
6ca34276bd refactor 2021-07-19 01:17:32 +02:00
Matthias
866c8af393 adding styling to autocomplete 2021-07-19 01:07:33 +02:00
Matthias
17eee66b95 Adding search auto-complete #280 2021-07-19 00:46:51 +02:00
Matthias
c71fbf7893 added autocomplete to jquery ui 2021-07-18 20:57:15 +02:00
Oliver Walters
0d660e3c69 Unit test fixes
(cherry picked from commit 787064abc0)
2021-07-19 00:24:21 +10:00
Oliver Walters
0288a1acbf Refactor edit and delete views for ManufacturerPart 2021-07-18 22:59:34 +10:00
Oliver Walters
0c91691ed2 Refactor SupplierPartEdit and SupplierPartDelete forms 2021-07-18 22:46:23 +10:00
Oliver Walters
29d7cb40e1 Add edit and delete buttons for supplier-part table 2021-07-18 22:31:04 +10:00
Oliver Walters
56fa6c512b Refactor SupplierPartCreate form 2021-07-18 22:21:11 +10:00
Oliver
f9b7257bdb Merge pull request #1835 from SchrodingersGat/disable-secondary
Disable secondary modals
2021-07-18 21:46:22 +10:00
Oliver
14e2cabffa Merge pull request #1834 from SchrodingersGat/add-line-item-fix
Add 'destination' field to POLineItem API serializer
2021-07-18 21:41:29 +10:00
Oliver
b1165af3c3 Merge pull request #1833 from SchrodingersGat/part-cat-form-improvements
Part cat form improvements
2021-07-18 21:32:31 +10:00
Oliver Walters
b04d6051a4 Disable secondary modals 2021-07-18 21:32:25 +10:00
Oliver Walters
e17b92b126 Add 'destination' field to POLineItem API serializer 2021-07-18 21:25:59 +10:00
Oliver Walters
c33cfe9503 Small rendering improvements 2021-07-18 21:17:03 +10:00
Oliver Walters
753fe9c80f Ordering and rendering for StockLocation 2021-07-18 21:15:51 +10:00
Oliver Walters
36cf614aed Add "level" to PartCategory serializer
- Also use tree ordering by default
2021-07-18 21:11:53 +10:00
Oliver
8c1248d74b Merge pull request #1828 from SchrodingersGat/supplier-reference-fiix
Add supplier_reference field to form
2021-07-18 11:04:14 +10:00
Matthias
eba5512a38 extending form for stock creation 2021-07-18 02:58:39 +02:00
Oliver Walters
f4f7514b45 Similar fix for customer_reference field 2021-07-18 10:47:35 +10:00
Oliver Walters
9719a14587 Add supplier_reference field to form 2021-07-18 10:33:27 +10:00
Matthias
44482800e4 switching out icon for setting 2021-07-18 02:27:15 +02:00
Matthias
210a4bccde setting for #1796 2021-07-18 02:20:56 +02:00
eeintech
f938e722b9 Another shot at it! 2021-07-16 12:08:26 -04:00
eeintech
86f3f56a60 Merge branch 'master' of github.com:inventree/InvenTree into part_main_details 2021-07-16 10:43:53 -04:00
Oliver
5ce6dd325d Merge pull request #1824 from SchrodingersGat/po-currency
Use default curreny code
2021-07-16 13:54:41 +10:00
Oliver
9ded804707 Merge pull request #1823 from SchrodingersGat/table-fixes
Link fixes
2021-07-16 13:43:04 +10:00
Oliver
733951883e Use default curreny code 2021-07-16 13:35:51 +10:00
Oliver
0fcb4e3170 Link fixes 2021-07-16 13:30:11 +10:00
Oliver
3f3d058bfa Merge pull request #1817 from SchrodingersGat/spa-bug-fix
Fixes for issues with new SPA approach
2021-07-16 07:33:28 +10:00
Oliver
db16b23287 Merge pull request #1820 from eeintech/fix_logout_css
Fix logout CSS
2021-07-16 07:33:11 +10:00
eeintech
886d95e467 Easy fix! 2021-07-15 16:31:07 -04:00
eeintech
bfc421c50b Cleaner part details 2021-07-15 14:52:33 -04:00
Oliver
cbbd58c743 Fixes for issues with new SPA approach
- Fix manufacturer part table
- Fix supplier part table
- Consolidate manufacturer and supplier parts onto single page
- CSS fixes
2021-07-16 01:13:48 +10:00
Oliver
bb60eed897 Merge pull request #1811 from SchrodingersGat/spa
Dynamically switch between navbar selections on pages
2021-07-15 23:43:43 +10:00
Oliver
28b3432afe Delete outdated unit test 2021-07-15 23:19:47 +10:00
Oliver
e86e15df99 Fix part import form 2021-07-15 23:18:41 +10:00
Oliver
e116ef9a8b Fix BOM upload form 2021-07-15 23:14:40 +10:00
Oliver
09d175f7cf Fix purchase order import form 2021-07-15 23:11:59 +10:00
Oliver
c61fc7c1df Refactor part pricing page 2021-07-15 23:06:37 +10:00
Oliver
0fc558068f Refactor BuildOrder pages 2021-07-15 22:40:14 +10:00
Oliver
533a3aa368 Refactor StockItem pages 2021-07-15 22:19:13 +10:00
Oliver
b1640fcc23 Refactor StockLocation pages 2021-07-15 21:38:05 +10:00
Oliver
676cca89a1 Refactor ManufacturerPart pages 2021-07-15 21:32:46 +10:00
Oliver
52da678636 Refactor SupplierPart page 2021-07-15 21:24:33 +10:00
Oliver
72337dab49 Refactor PartCategory views 2021-07-15 17:26:06 +10:00
Oliver
d5bf108fef Remove unused template file 2021-07-15 16:54:49 +10:00
Oliver
df89008116 Refactor allocation page(s)
- Also perform null check on notes before displaying
2021-07-15 16:53:14 +10:00
Oliver
e38d740bbc Refactor "used in" page 2021-07-15 16:44:46 +10:00
Oliver
e7c7bdcd00 Refactor BOM page 2021-07-15 16:42:28 +10:00
Oliver
57851b0eaf Refactor build orders display 2021-07-15 16:36:20 +10:00
Oliver
c8c7f78ce9 Refactor "related parts" view 2021-07-15 16:28:26 +10:00
Oliver
8607d702c4 Refactor variants page 2021-07-15 16:17:41 +10:00
Oliver
985bd39234 Fix links 2021-07-15 16:14:48 +10:00
Oliver
84149d34a6 Refactor part-supplier view 2021-07-15 16:12:27 +10:00
Oliver
984e16d5af Return all part parameters to the main part edit form
- refactor purchaseorder view
- refactor salesorder view
2021-07-15 16:07:46 +10:00
Oliver
352a58b373 Can select nav based on URL query parameter 2021-07-15 13:41:26 +10:00
Oliver
3786454e4c Remove URL 2021-07-15 12:56:26 +10:00
Oliver
1a30a5bc16 Merge "test template" page 2021-07-15 12:56:17 +10:00
Oliver
2d2ad91545 Move "stock" part view 2021-07-15 12:52:36 +10:00
Oliver
0667857754 Refactor part base display 2021-07-15 12:04:48 +10:00
Oliver
94792596e9 Update version.py
Bumped version number
2021-07-15 09:54:55 +10:00
Oliver
c816afbe62 Merge pull request #1812 from eeintech/improve_supplier_part_fetch
Custom SupplierPart object manager and prefetch related models
2021-07-14 07:59:25 +10:00
eeintech
3d9ad24e27 Defined custom SupplierPart object manager and prefetch related models in all queries 2021-07-13 12:55:36 -04:00
Oliver
8fed3b3522 Typo fix 2021-07-13 22:03:49 +10:00
Oliver
8dde89e781 Table fixes 2021-07-13 21:57:49 +10:00
Oliver
c1c0a262b2 Refactor Company detail view 2021-07-13 21:53:48 +10:00
Oliver
b6227f7d28 Refactor PurchaseOrder display 2021-07-13 21:21:00 +10:00
Oliver
65de52b705 Add javascript to dynamically switch between views 2021-07-13 20:58:05 +10:00
Oliver
9889e314a9 Remove unused templates 2021-07-13 20:04:12 +10:00
Oliver
970f08260c Update navbar 2021-07-13 20:04:02 +10:00
Oliver
39c58e4015 Move all "SalesOrder" content onto a single page 2021-07-13 19:59:11 +10:00
Oliver
a0b3359d62 Fix filtering for build orders 2021-07-13 19:58:47 +10:00
Oliver
2295008944 Merge pull request #1808 from SchrodingersGat/part-page-refactor
Move "attachments" and "notes" to "Part Detail" page
2021-07-12 23:56:40 +10:00
Oliver
cf23fb6fe8 PEP fixes 2021-07-12 23:32:08 +10:00
Oliver
b1af07c8cb Remove stale pages 2021-07-12 23:31:10 +10:00
Oliver
77d80f5c0f Move "attachments" and "notes" to "Part Detail" page
(cherry picked from commit daf0a082dc04c04cfd68cab70148a7d7cf28460f)
2021-07-12 23:27:50 +10:00
Oliver
6af05b2b83 Merge pull request #1807 from SchrodingersGat/forms-cleanup
Remove unused forms
2021-07-12 22:40:20 +10:00
Oliver
374c3676a3 Merge pull request #1806 from SchrodingersGat/manufacturer-part-api-form
Refactor ManufacturerPartCreate form
2021-07-12 22:23:15 +10:00
Oliver
0cb2b49333 Remove unused forms 2021-07-12 22:23:08 +10:00
Oliver
bd8b52d7d2 Merge pull request #1804 from SchrodingersGat/api-stock-adjustments
Api stock adjustments
2021-07-12 22:16:56 +10:00
Oliver
7c80767414 PEP fixes 2021-07-12 22:06:03 +10:00
Oliver
30fd3c8841 Unit test fixes 2021-07-12 22:03:36 +10:00
Oliver
e9c7937ef4 Merge pull request #1805 from SchrodingersGat/selec2-fix
Fix dodgy CSS file
2021-07-12 21:34:14 +10:00
Oliver
c3b0593aba Refactor ManufacturerPartCreate form 2021-07-12 21:32:09 +10:00
Oliver
ccf17bf4c5 Fix dodgy CSS file 2021-07-12 21:19:00 +10:00
Oliver
77cfadad42 Add 'title' option for contsructed fields 2021-07-12 21:11:29 +10:00
Oliver
52eedef820 remove old StockAdjust view 2021-07-12 21:03:28 +10:00
Oliver
edf4aab063 Refactor "showQuestionDialog" function 2021-07-12 21:03:01 +10:00
Oliver
a1579eecfd Refactor "showAlertDialog" function 2021-07-12 20:55:28 +10:00
Oliver
e9bf4b4cef Add some more functionality to StockLocation page 2021-07-12 20:53:36 +10:00
Oliver
2ea4824030 Add option to move stock for a part 2021-07-12 20:45:45 +10:00
Oliver
9fc7976569 Refactor all "adjustment" forms to use the new API approach 2021-07-12 20:38:54 +10:00
Oliver
74e5b2cd3f Handle delete differently 2021-07-12 20:06:53 +10:00
Oliver
2bebf2d41a Test fixes 2021-07-12 20:00:50 +10:00
Oliver
11ee8e8369 Raise error if specified quantity is above available quantity 2021-07-12 19:59:10 +10:00
Oliver
5329e3e56c Display per-line errors 2021-07-12 19:42:06 +10:00
Oliver
51314a0261 Refactor error messaging for stock adjustment API 2021-07-12 19:41:50 +10:00
Oliver
e04828214a Refactor showApiError() function 2021-07-12 19:20:29 +10:00
Oliver
0c41cc7c77 Handle form submissions 2021-07-12 18:13:06 +10:00
Oliver
e3f85414fa Stock API URL cleanup 2021-07-12 17:32:06 +10:00
Oliver
747cccfa42 Refactor to use more generic forms approach 2021-07-12 16:55:35 +10:00
Oliver
7531984c78 Fix read_only attribute 2021-07-11 21:17:54 +10:00
Oliver
cc90c8abbe Move buttons to separate table column 2021-07-11 21:15:06 +10:00
Oliver
9eb1367d80 Add "location" field 2021-07-11 21:07:56 +10:00
Oliver
3efd7f7777 Add a "notes" field 2021-07-11 20:56:29 +10:00
Oliver
ca5d3a57de Set quantity input parameters based on action 2021-07-11 20:49:54 +10:00
Oliver
9e4bc274cf Allow custom code to be run on form submission 2021-07-11 20:40:27 +10:00
Oliver
c045a3b6f6 Refactorin' 2021-07-11 20:36:52 +10:00
Oliver
0be787ea5b Merge pull request #1802 from matmair/next-btn-leadingzero
support leading zeros in serial numbers
2021-07-11 09:04:09 +10:00
Matthias
03fb6e5c61 support leading zeros in serial numbers 2021-07-10 17:54:17 +02:00
Oliver
14ab1bef14 Callback to remove row 2021-07-11 00:15:46 +10:00
Oliver
0507e8a3bc Building stock adjustment modal 2021-07-10 23:59:35 +10:00
Oliver
02214ea713 Merge pull request #1799 from SchrodingersGat/bom-export-fix
Bug fix for BOM export
2021-07-10 23:27:17 +10:00
Oliver
7cc1063114 PEP 2021-07-10 23:04:34 +10:00
Oliver
73e03636a2 Add unit tests 2021-07-10 23:04:20 +10:00
Oliver
d9c2d061cc Merge pull request #1797 from SchrodingersGat/bom-validation-fix
Add numerical validation step for BomItem
2021-07-10 14:14:52 +10:00
Oliver
cf66a386ea Bug fix 2021-07-10 14:13:46 +10:00
Oliver
bf2774eb21 Add numerical validation step for BomItem 2021-07-10 13:48:44 +10:00
Oliver
f6d5bd4ed8 Merge pull request #1760 from eeintech/bom_import
Converted BOM import to new multi-step form framework
2021-07-10 13:47:25 +10:00
Oliver
fe6da32e64 Merge pull request #1793 from SchrodingersGat/combine-manufacturer-supplier-tables
Consolidate Manufacturers and Suppliers views
2021-07-09 16:57:11 +10:00
Oliver
9ae5c241f5 Move part parameters onto the part details page 2021-07-09 16:34:47 +10:00
Oliver
ff92210b25 Fix URLs 2021-07-09 16:31:29 +10:00
Oliver
6eec6a0599 Consolidate Manufacturers and Suppliers views 2021-07-09 16:29:58 +10:00
Oliver
b89fe4f9d4 Merge pull request #1789 from SchrodingersGat/supplier-part-table
Add more fields to ManufacturerPart and SupplierPart tables
2021-07-09 15:09:39 +10:00
Oliver
47a56f7f5d Fixes for unit tests 2021-07-09 14:54:03 +10:00
Oliver
c694c9467b sessionStorage -> localStorage
OMG
2021-07-09 14:39:08 +10:00
Oliver
6b73e7a408 Add more fields to ManufacturerPart and SupplierPart tables 2021-07-09 14:28:32 +10:00
Oliver
5235ad1b0c Merge pull request #1787 from SchrodingersGat/bom-table-additions
Add sub_part_assembly filter to BOM table
2021-07-09 13:39:09 +10:00
Oliver
7168607a88 PEP fix 2021-07-09 13:07:01 +10:00
Oliver
079e331bf6 Add sub_part_assembly filter to BOM table 2021-07-09 13:04:48 +10:00
Oliver
558e24c985 Merge pull request #1783 from SchrodingersGat/build-table-filtering
Fix for strange table filtering bug
2021-07-09 12:57:03 +10:00
Oliver
c45e2d682e Merge pull request #1782 from SchrodingersGat/company-rendering
Improve rendering of "Company" in API form
2021-07-09 12:31:31 +10:00
Oliver
9d7f9a9aa3 Fix for strange table filtering bug
- When a table was "refreshed" based on the selectable filters, table ordering was not observed
- This was due to the original query parameter conversion not being observed
- Refactored out the conversion function so it works correctly now
- Also removed some cruft from generated query strings
2021-07-09 12:31:25 +10:00
Oliver
7539bd47fe Fix rendering issues 2021-07-09 12:10:27 +10:00
Oliver
6a995042c9 Fix bug relating no PurchaseOrderLineItem with null Part reference 2021-07-09 12:10:17 +10:00
Oliver
4b6ca548b6 Improve form rendering for SupplierPart 2021-07-09 12:09:57 +10:00
Oliver
40ac1f39e0 Improve rendering of "Company" in API form
- Add a thumbnail image
- Refactor select2 thumbnail code

(cherry picked from commit 2df7c520be)
2021-07-09 11:14:38 +10:00
Oliver
19ba9bf93c Merge pull request #1780 from SchrodingersGat/IPN_case
Fix case for filtering parts by IPN
2021-07-09 09:26:48 +10:00
Oliver
0c73fa3b58 Add regex filter for part name 2021-07-09 09:11:31 +10:00
Oliver
fd5d20ad13 Fix case for filtering parts by IPN 2021-07-09 09:08:55 +10:00
Oliver
433098ce6e Merge pull request #1778 from SchrodingersGat/build-forms
Refactor BuildOrderEdit form
2021-07-09 09:02:39 +10:00
Oliver
0a86d947bc Refactor PartParameterCreate form 2021-07-09 02:03:33 +10:00
Oliver
cbf0e0bd4a Refactor forms for editing and deleting a PartParameter
- PartParameters now loaded using the API, not pre-rendered
2021-07-09 01:56:04 +10:00
Oliver
cbd291849c More unit test fixes 2021-07-09 01:49:17 +10:00
Oliver
6e26bd0b71 Fixes for unit tests 2021-07-09 01:29:17 +10:00
Oliver
337223b8eb Modal form improvements 2021-07-09 01:20:40 +10:00
Oliver
ecf47aa69d Fix for BuildOrder reference default value 2021-07-09 01:20:29 +10:00
Oliver
60e8a17f07 bug fix: Prevent API forms from being submitted multiple times
- A problem if you're a manic clicker
2021-07-09 01:06:38 +10:00
Oliver
9947a0cf90 PEP fix 2021-07-09 00:59:56 +10:00
Oliver
7e7fe7d63f Refactor buildlist filtering 2021-07-09 00:58:17 +10:00
Oliver
bec98d355a Improvements
- part_detail defaults to True for BuildSerializer
- Handle invalid parent for BuildOrder
2021-07-09 00:49:19 +10:00
Oliver
be6ecd9587 Fixes for BuildOrder forms 2021-07-09 00:36:54 +10:00
Oliver
13ca076f42 Fix for form rendering of "required" fields with a default value
- Force the "required" parameter to be set
2021-07-09 00:29:36 +10:00
Oliver
004b36b1df Refactor BuildOrderCreate form 2021-07-09 00:18:03 +10:00
Oliver
5016d44b83 Add default value for BuildOrder reference 2021-07-09 00:15:49 +10:00
Oliver
245c04367b Refactor BuildOrderEdit form 2021-07-08 23:57:42 +10:00
Oliver
522432f4aa Merge pull request #1776 from SchrodingersGat/part-labels
Part labels
2021-07-08 23:34:59 +10:00
Oliver
bd4dde2cb7 Add permissions for PartLabel model 2021-07-08 23:22:25 +10:00
Oliver
15cb1e0005 Print part labels 2021-07-08 22:54:41 +10:00
Oliver
c39f705ef7 Copy default part label templates 2021-07-08 22:42:31 +10:00
Oliver
1830467487 Add admin / serializer / API for PartLabel model 2021-07-08 22:10:10 +10:00
Oliver
a1a4bddcc6 Add model for PartLabel 2021-07-08 21:07:45 +10:00
Oliver
0599fbaf26 Merge pull request #1773 from SchrodingersGat/ipn-filtering
API Filtering improvements
2021-07-08 20:47:07 +10:00
Oliver
a985e11aa8 Simplify and add filters for StockList API endpoint 2021-07-08 20:10:22 +10:00
Oliver
c7f79a5a08 Fixes 2021-07-08 19:23:01 +10:00
Oliver
79d90b1c4a Additional filtering options for name and IPN fields 2021-07-08 17:46:57 +10:00
Oliver
f0e7826fdc Adds some more API filters for the StockItem endpoint 2021-07-08 17:44:52 +10:00
Oliver
81010994e7 Adds regex filtering for "batch" code on StockItem 2021-07-08 17:26:55 +10:00
Oliver
a8a21f7c9d Transition "has IPN" filter to django-filters approach 2021-07-08 17:16:02 +10:00
Oliver
ba0a13443f PEP fixes 2021-07-08 17:02:55 +10:00
Oliver
376428b80b Add regex IPN filter for Part API 2021-07-08 17:02:45 +10:00
Oliver
800cb9606a Merge pull request #1772 from SchrodingersGat/part-stock-part-column
Reintroduces "part" column to part stock
2021-07-08 15:27:59 +10:00
Oliver
2467690111 Reintroduces "part" column to part stock 2021-07-08 13:46:53 +10:00
Oliver
a2870b60d9 Merge pull request #1757 from matmair/stock-next-prev
Stock previous / next serial
2021-07-08 11:41:01 +10:00
Oliver
f1797dbe2f Merge pull request #1771 from SchrodingersGat/company-part-search-fix
API: Allow search of IPN field for ManufacturerPart and SupplierPart
2021-07-08 11:30:58 +10:00
Oliver
ae68463f46 API: Allow search of IPN field for ManufacturerPart and SupplierPart 2021-07-08 11:16:04 +10:00
Oliver
309097293f Merge pull request #1768 from SchrodingersGat/attachment-fixes
Fixes for attachment issues
2021-07-08 11:12:34 +10:00
Oliver
fcc244b52f Fixes for BuildOrder attachment API list 2021-07-08 10:50:34 +10:00
Oliver
1deab0c040 Fix for SalesOrder attachment table 2021-07-08 10:48:08 +10:00
Oliver
939d5838fa Fixes for PurchaseOrder attachment table 2021-07-08 10:45:42 +10:00
Oliver
41268d92bf Add missing bootstrap .map file 2021-07-08 10:45:23 +10:00
Oliver
1a979fc113 Filtering fix for StockItem attachments 2021-07-08 10:41:18 +10:00
Oliver
ff8ddfbb5c Fix link to select2 2021-07-08 10:38:12 +10:00
Oliver
1dbdcb6d9c Merge pull request #1763 from eeintech/stock_table_supplier_part_detail
Fixed supplier part detail handling in stock table
2021-07-07 07:53:04 +10:00
Matthias
2db42eff50 remove unneeded tag 2021-07-06 21:25:42 +02:00
Matthias
98c52c06ac Revert "fetching supplier part for stock tables"
This reverts commit eaf191dc8d.
2021-07-06 21:20:27 +02:00
Matthias
9ed2338162 bolder type for serial numbers 2021-07-06 21:10:42 +02:00
eeintech
87a7081185 Fixed supplier part detail handling in stock table 2021-07-06 14:32:16 -04:00
Oliver
c2df1fcd95 Merge pull request #1749 from matmair/extend-build-order
Extend build order table
2021-07-06 11:23:36 +10:00
Oliver
db21ccdb30 Merge pull request #1761 from eeintech/stock_move_modal_notes
Fixes for stock modal and notes propagation to tracking items
2021-07-06 08:59:15 +10:00
eeintech
6687661928 Fixes for stock modal and notes propagation to tracking items 2021-07-05 17:36:10 -04:00
eeintech
58efc952db Converted BOM import to new multi-step form framework 2021-07-05 14:57:45 -04:00
Oliver
1d0dd04ca4 Merge pull request #1759 from SchrodingersGat/manufacturer-part-table-fix
Fix filters for ManufacturerPart and SupplierPart table views
2021-07-05 17:54:41 +10:00
Oliver
f72762ceb7 Fix filters for ManufacturerPart and SupplierPart table views 2021-07-05 17:15:24 +10:00
Oliver
f790d6a6a5 L10 (#1752)
* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* updated translation base

* updated translation base

* updated translation base

* updated translation base

* updated translation base

* New Crowdin updates (#1751)

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* updated translation base

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

* Fix: New translations django.po from Crowdin

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2021-07-05 16:54:15 +10:00
Matthias
84b67e2cc1 also allow the boundaries 2021-07-05 00:53:05 +02:00
Matthias
1786c029b4 prev and next serial link in stock items 2021-07-05 00:47:45 +02:00
Matthias
369acb494b new tag for url resolve 2021-07-05 00:46:51 +02:00
Matthias
eaf191dc8d fetching supplier part for stock tables 2021-07-04 23:45:04 +02:00
Matthias
4711f0b823 fromatter for responsible group 2021-07-04 00:16:14 +02:00
Matthias
7b3bc33b88 using owner serializer 2021-07-04 00:15:44 +02:00
Matthias
4f31cee6a3 Merge branch 'master' of https://github.com/inventree/InvenTree into extend-build-order 2021-07-04 00:02:29 +02:00
Matthias
ffa9dd18cf adding new fields into table 2021-07-03 01:49:18 +02:00
Matthias
4f432d4db2 extend api with issuer
#1356
2021-07-03 01:47:54 +02:00
rgilham
c6fd2281d6 Allow BOM pricing to be valid when using internal pricing 2021-06-24 02:13:55 +02:00
736 changed files with 235218 additions and 106066 deletions

View File

@@ -1,9 +0,0 @@
[run]
source = ./InvenTree
omit =
InvenTree/manage.py
InvenTree/setup.py
InvenTree/InvenTree/middleware.py
InvenTree/InvenTree/utils.py
InvenTree/InvenTree/wsgi.py
InvenTree/users/apps.py

25
.eslintrc.yml Normal file
View File

@@ -0,0 +1,25 @@
env:
commonjs: false
browser: true
es2021: true
jquery: true
extends:
- google
parserOptions:
ecmaVersion: 12
rules:
no-var: off
guard-for-in: off
no-trailing-spaces: off
camelcase: off
padded-blocks: off
prefer-const: off
max-len: off
require-jsdoc: off
valid-jsdoc: off
no-multiple-empty-lines: off
comma-dangle: off
prefer-spread: off
indent:
- error
- 4

2
.gitattributes vendored
View File

@@ -7,5 +7,5 @@
*.yml text
*.yaml text
*.conf text
*.sh text
*.sh text eol=lf
*.js text

2
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
patreon: inventree
ko_fi: inventree

47
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,47 @@
---
name: Bug
about: Create a bug report to help us improve InvenTree!
title: "[BUG] Enter bug description"
labels: bug, question
assignees: ''
---
<!---
Everything inside these brackets is hidden - please remove them where you fill out information.
--->
**Describe the bug**
<!---
A clear and concise description of what the bug is.
--->
**Steps to Reproduce**
Steps to reproduce the behavior:
<!---
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
--->
**Expected behavior**
<!---
A clear and concise description of what you expected to happen.
--->
<!---
**Screenshots**
If applicable, add screenshots to help explain your problem.
--->
**Deployment Method**
- [ ] Docker
- [ ] Bare Metal
**Version Information**
<!---
You can get this by going to the "About InvenTree" section in the upper right corner and clicking on to the "copy version information"
--->

View File

@@ -0,0 +1,26 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FR]"
labels: enhancement
assignees: ''
---
**Is your feature request the result of a bug?**
Please link it here.
**Problem**
A clear and concise description of what the problem is. e.g. I'm always frustrated when [...]
**Suggested solution**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Examples of other systems**
Show how other software handles your FR if you have examples.
**Do you want to develop this?**
If so please describe briefly how you would like to implement it (so we can give advice) and if you have experience in the needed technology (you do not need to be a pro - this is just as a information for us).

View File

@@ -0,0 +1,37 @@
name: Check Translations
on:
push:
branches:
- l10
pull_request:
branches:
- l10
jobs:
check:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_NAME: './test_db.sqlite'
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
INVENTREE_DEBUG: info
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install gettext
pip3 install invoke
invoke install
- name: Test Translations
run: invoke translate
- name: Check Migration Files
run: python3 ci/check_migration_files.py

View File

@@ -1,60 +0,0 @@
# Perform CI checks, and calculate code coverage
name: SQLite
on:
push:
branches-ignore:
- l10*
pull_request:
branches-ignore:
- l10*
jobs:
# Run tests on SQLite database
# These tests are used for code coverage analysis
coverage:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_NAME: './test_db.sqlite'
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
INVENTREE_DEBUG: info
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install gettext
pip3 install invoke
invoke install
invoke static
- name: Coverage Tests
run: |
invoke coverage
- name: Data Import Export
run: |
invoke migrate
invoke import-fixtures
invoke export-records -f data.json
rm test_db.sqlite
invoke migrate
invoke import-records -f data.json
invoke import-records -f data.json
- name: Test Translations
run: invoke translate
- name: Check Migration Files
run: python3 ci/check_migration_files.py
- name: Upload Coverage Report
run: coveralls

View File

@@ -15,6 +15,9 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Check version number
run: |
python3 ci/check_version_number.py --dev
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@@ -31,7 +34,6 @@ jobs:
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
target: production
repository: inventree/inventree
tags: inventree/inventree:latest
- name: Image Digest
run: echo ${{ steps.docker_build.outputs.digest }}

42
.github/workflows/docker_stable.yaml vendored Normal file
View File

@@ -0,0 +1,42 @@
# Build and push docker image on push to 'stable' branch
# Docker build will be uploaded to dockerhub with the 'inventree:stable' tag
name: Docker Build
on:
push:
branches:
- 'stable'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Check version number
run: |
python3 ci/check_version_number.py --release
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Dockerhub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push
uses: docker/build-push-action@v2
with:
context: ./docker
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
target: production
build-args:
branch=stable
tags: inventree/inventree:stable
- name: Image Digest
run: echo ${{ steps.docker_build.outputs.digest }}

View File

@@ -1,4 +1,5 @@
# Publish docker images to dockerhub
# Publish docker images to dockerhub on a tagged release
# Docker build will be uploaded to dockerhub with the 'invetree:<tag>' tag
name: Docker Publish
@@ -13,6 +14,9 @@ jobs:
steps:
- name: Check out repo
uses: actions/checkout@v2
- name: Check Release tag
run: |
python3 ci/check_version_number.py --release --tag ${{ github.event.release.tag_name }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@@ -29,5 +33,6 @@ jobs:
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
target: production
repository: inventree/inventree
build-args:
tag=${{ github.event.release.tag_name }}
tags: inventree/inventree:${{ github.event.release.tag_name }}

37
.github/workflows/docker_test.yaml vendored Normal file
View File

@@ -0,0 +1,37 @@
# Test that the InvenTree docker image compiles correctly
# This CI action runs on pushes to either the master or stable branches
# 1. Build the development docker image (as per the documentation)
# 2. Install requied python libs into the docker container
# 3. Launch the container
# 4. Check that the API endpoint is available
name: Docker Test
on:
push:
branches:
- 'master'
- 'stable'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Build Docker Image
run: |
cd docker
docker-compose -f docker-compose.sqlite.yml build
docker-compose -f docker-compose.sqlite.yml run inventree-dev-server invoke update
docker-compose -f docker-compose.sqlite.yml up -d
- name: Sleepy Time
run: sleep 60
- name: Test API
run: |
pip install requests
python3 ci/check_api_endpoint.py

View File

@@ -1,67 +0,0 @@
# MySQL Unit Testing
name: MySQL
on:
push:
branches-ignore:
- l10*
pull_request:
branches-ignore:
- l10*
jobs:
test:
runs-on: ubuntu-latest
env:
# Database backend configuration
INVENTREE_DB_ENGINE: django.db.backends.mysql
INVENTREE_DB_NAME: inventree
INVENTREE_DB_USER: root
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: '127.0.0.1'
INVENTREE_DB_PORT: 3306
INVENTREE_DEBUG: info
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
services:
mysql:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: inventree
MYSQL_USER: inventree
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
ports:
- 3306:3306
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Dependencies
run: |
sudo apt-get install mysql-server libmysqlclient-dev
pip3 install invoke
pip3 install mysqlclient
invoke install
- name: Run Tests
run: invoke test
- name: Data Import Export
run: |
invoke migrate
python3 ./InvenTree/manage.py flush --noinput
invoke import-fixtures
invoke export-records -f data.json
python3 ./InvenTree/manage.py flush --noinput
invoke import-records -f data.json
invoke import-records -f data.json

View File

@@ -1,63 +0,0 @@
# PostgreSQL Unit Testing
name: PostgreSQL
on:
push:
branches-ignore:
- l10*
pull_request:
branches-ignore:
- l10*
jobs:
test:
runs-on: ubuntu-latest
env:
# Database backend configuration
INVENTREE_DB_ENGINE: django.db.backends.postgresql
INVENTREE_DB_NAME: inventree
INVENTREE_DB_USER: inventree
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: '127.0.0.1'
INVENTREE_DB_PORT: 5432
INVENTREE_DEBUG: info
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
services:
postgres:
image: postgres
env:
POSTGRES_USER: inventree
POSTGRES_PASSWORD: password
ports:
- 5432:5432
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Dependencies
run: |
sudo apt-get install libpq-dev
pip3 install invoke
pip3 install psycopg2
invoke install
- name: Run Tests
run: invoke test
- name: Data Import Export
run: |
invoke migrate
python3 ./InvenTree/manage.py flush --noinput
invoke import-fixtures
invoke export-records -f data.json
python3 ./InvenTree/manage.py flush --noinput
invoke import-records -f data.json
invoke import-records -f data.json

View File

@@ -1,49 +0,0 @@
# Run python library tests whenever code is pushed to master
name: Python Bindings
on:
push:
branches:
- master
pull_request:
branches-ignore:
- l10*
jobs:
python:
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_NAME: './test_db.sqlite'
INVENTREE_DB_ENGINE: 'sqlite3'
INVENTREE_DEBUG: info
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Install InvenTree
run: |
sudo apt-get update
sudo apt-get install python3-dev python3-pip python3-venv
pip3 install invoke
invoke install
invoke migrate
- name: Download Python Code
run: |
git clone --depth 1 https://github.com/inventree/inventree-python ./inventree-python
- name: Start Server
run: |
invoke import-records -f ./inventree-python/test/test_data.json
invoke server -a 127.0.0.1:8000 &
sleep 60
- name: Run Tests
run: |
cd inventree-python
invoke test

304
.github/workflows/qc_checks.yaml vendored Normal file
View File

@@ -0,0 +1,304 @@
# Checks for each PR / push
name: QC checks
on:
push:
branches-ignore:
- l10*
pull_request:
branches-ignore:
- l10*
env:
python_version: 3.8
node_version: 16
server_start_sleep: 60
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_DB_NAME: inventree
INVENTREE_MEDIA_ROOT: ./media
INVENTREE_STATIC_ROOT: ./static
jobs:
pep_style:
name: PEP style (python)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Python ${{ env.python_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.python_version }}
cache: 'pip'
- name: Install deps
run: |
pip install flake8==3.8.3
pip install pep8-naming==0.11.1
- name: flake8
run: |
flake8 InvenTree
javascript:
name: javascript template files
needs: pep_style
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Install node.js ${{ env.node_version }}
uses: actions/setup-node@v2
with:
node-version: ${{ env.node_version }}
cache: 'npm'
- run: npm install
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: ${{ env.python_version }}
cache: 'pip'
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install gettext
pip3 install invoke
invoke install
invoke static
- name: Check Templated Files
run: |
cd ci
python check_js_templates.py
- name: Lint Javascript Files
run: |
invoke render-js-files
npx eslint js_tmp/*.js
html:
name: html template files
needs: pep_style
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Install node.js ${{ env.node_version }}
uses: actions/setup-node@v2
with:
node-version: ${{ env.node_version }}
cache: 'npm'
- run: npm install
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: ${{ env.python_version }}
cache: 'pip'
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install gettext
pip3 install invoke
invoke install
invoke static
- name: Check HTML Files
run: |
npx markuplint InvenTree/build/templates/build/*.html
npx markuplint InvenTree/company/templates/company/*.html
npx markuplint InvenTree/order/templates/order/*.html
npx markuplint InvenTree/part/templates/part/*.html
npx markuplint InvenTree/stock/templates/stock/*.html
npx markuplint InvenTree/templates/*.html
npx markuplint InvenTree/templates/InvenTree/*.html
npx markuplint InvenTree/templates/InvenTree/settings/*.html
python:
name: python bindings
needs: pep_style
runs-on: ubuntu-latest
env:
wrapper_name: inventree-python
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Install InvenTree
run: |
sudo apt-get update
sudo apt-get install python3-dev python3-pip python3-venv
pip3 install invoke
invoke install
invoke migrate
- name: Download Python Code
run: |
git clone --depth 1 https://github.com/inventree/${{ env.wrapper_name }} ./${{ env.wrapper_name }}
- name: Start Server
run: |
invoke import-records -f ./${{ env.wrapper_name }}/test/test_data.json
invoke server -a 127.0.0.1:8000 &
sleep ${{ env.server_start_sleep }}
- name: Run Tests
run: |
cd ${{ env.wrapper_name }}
invoke test
coverage:
name: Sqlite / coverage
needs: ['javascript', 'html']
runs-on: ubuntu-latest
env:
INVENTREE_DB_NAME: ./inventree.sqlite
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_PLUGINS_ENABLED: true
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python ${{ env.python_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.python_version }}
cache: 'pip'
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install gettext
pip3 install invoke
invoke install
invoke static
- name: Coverage Tests
run: |
invoke coverage
- name: Data Import Export
run: |
invoke migrate
invoke import-fixtures
invoke export-records -f data.json
rm inventree.sqlite
invoke migrate
invoke import-records -f data.json
invoke import-records -f data.json
- name: Test Translations
run: invoke translate
- name: Check Migration Files
run: python3 ci/check_migration_files.py
- name: Upload Coverage Report
run: coveralls
postgres:
name: Postgres
needs: ['javascript', 'html']
runs-on: ubuntu-latest
env:
INVENTREE_DB_ENGINE: django.db.backends.postgresql
INVENTREE_DB_USER: inventree
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: '127.0.0.1'
INVENTREE_DB_PORT: 5432
INVENTREE_DEBUG: info
INVENTREE_CACHE_HOST: localhost
INVENTREE_PLUGINS_ENABLED: true
services:
postgres:
image: postgres
env:
POSTGRES_USER: inventree
POSTGRES_PASSWORD: password
ports:
- 5432:5432
redis:
image: redis
ports:
- 6379:6379
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python ${{ env.python_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.python_version }}
cache: 'pip'
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install libpq-dev
pip3 install invoke
pip3 install psycopg2
pip3 install django-redis>=5.0.0
invoke install
- name: Run Tests
run: invoke test
- name: Data Import Export
run: |
invoke migrate
python3 ./InvenTree/manage.py flush --noinput
invoke import-fixtures
invoke export-records -f data.json
python3 ./InvenTree/manage.py flush --noinput
invoke import-records -f data.json
invoke import-records -f data.json
mysql:
name: MySql
needs: ['javascript', 'html']
runs-on: ubuntu-latest
env:
# Database backend configuration
INVENTREE_DB_ENGINE: django.db.backends.mysql
INVENTREE_DB_USER: root
INVENTREE_DB_PASSWORD: password
INVENTREE_DB_HOST: '127.0.0.1'
INVENTREE_DB_PORT: 3306
INVENTREE_DEBUG: info
INVENTREE_PLUGINS_ENABLED: true
services:
mysql:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: ${{ env.INVENTREE_DB_NAME }}
MYSQL_USER: inventree
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
ports:
- 3306:3306
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python ${{ env.python_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.python_version }}
cache: 'pip'
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install libmysqlclient-dev
pip3 install invoke
pip3 install mysqlclient
invoke install
- name: Run Tests
run: invoke test
- name: Data Import Export
run: |
invoke migrate
python3 ./InvenTree/manage.py flush --noinput
invoke import-fixtures
invoke export-records -f data.json
python3 ./InvenTree/manage.py flush --noinput
invoke import-records -f data.json
invoke import-records -f data.json

25
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
# Marks all issues that do not receive activity stale starting 2022
name: Mark stale issues and pull requests
on:
schedule:
- cron: '24 11 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue seems stale. Please react to show this is still important.'
stale-pr-message: 'This PR seems stale. Please react to show this is still important.'
stale-issue-label: 'no-activity'
stale-pr-label: 'no-activity'
start-date: '2022-01-01'
exempt-all-milestones: true

View File

@@ -1,34 +0,0 @@
name: Style Checks
on:
push:
branches-ignore:
- l10*
pull_request:
branches-ignore:
- l10*
jobs:
style:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.7]
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install deps
run: |
pip install flake8==3.8.3
pip install pep8-naming==0.11.1
- name: flake8
run: |
flake8 InvenTree

21
.github/workflows/version.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
# Checks version number
name: version number
on:
pull_request:
branches-ignore:
- l10*
jobs:
check_version:
name: version number
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Check version number
run: |
python3 ci/check_version_number.py --branch ${{ github.base_ref }}

17
.github/workflows/welcome.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
# welcome new contributers
name: Welcome
on:
pull_request:
types: [opened]
issues:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: 'Welcome to InvenTree! Please check the [contributing docs](https://inventree.readthedocs.io/en/latest/contribute/) on how to help.\nIf you experience setup / install issues please read all [install docs]( https://inventree.readthedocs.io/en/latest/start/intro/).'
pr-message: 'This is your first PR, welcome!\nPlease check [Contributing](https://github.com/inventree/InvenTree/blob/master/CONTRIBUTING.md) to make sure your submission fits our general code-style and workflow.\nMake sure to document why this PR is needed and to link connected issues so we can review it faster.'

11
.gitignore vendored
View File

@@ -49,6 +49,7 @@ static_i18n
# Local config file
config.yaml
plugins.txt
# Default data file
data.json
@@ -77,6 +78,10 @@ dev/
locale_stats.json
# node.js
package-lock.json
package.json
node_modules/
node_modules/
# maintenance locker
maintenance_mode_state.txt
# plugin dev directory
plugins/

47
.gitpod.yml Normal file
View File

@@ -0,0 +1,47 @@
tasks:
- name: Setup django
before: |
export INVENTREE_DB_ENGINE='sqlite3'
export INVENTREE_DB_NAME='/workspace/InvenTree/dev/database.sqlite3'
export INVENTREE_MEDIA_ROOT='/workspace/InvenTree/inventree-data/media'
export INVENTREE_STATIC_ROOT='/workspace/InvenTree/dev/static'
export PIP_USER='no'
python3 -m venv venv
source venv/bin/activate
pip install invoke
inv install
mkdir dev
inv update
gp sync-done setup_server
- name: Start server
init: gp sync-await setup_server
command: |
gp sync-await setup_server
export INVENTREE_DB_ENGINE='sqlite3'
export INVENTREE_DB_NAME='/workspace/InvenTree/dev/database.sqlite3'
export INVENTREE_MEDIA_ROOT='/workspace/InvenTree/inventree-data/media'
export INVENTREE_STATIC_ROOT='/workspace/InvenTree/dev/static'
source venv/bin/activate
rm /workspace/InvenTree/inventree-data -r
git clone https://github.com/inventree/demo-dataset /workspace/InvenTree/inventree-data
invoke delete-data -f
invoke import-records -f /workspace/InvenTree/inventree-data/inventree_data.json
inv server
# List the ports to expose. Learn more https://www.gitpod.io/docs/config-ports/
ports:
- port: 8000
onOpen: open-preview
github:
prebuilds:
master: true
pullRequests: false
pullRequestsFromForks: true
addBadge: true
addLabel: gitpod-ready
addCheck: false

View File

@@ -1,29 +1,102 @@
Contributions to InvenTree are welcomed - please follow the guidelines below.
Please read the contribution guidelines below, before submitting your first pull request to the InvenTree codebase.
## Feature Branches
## Branches and Versioning
No pushing to master! New featues must be submitted in a separate branch (one branch per feature).
InvenTree roughly follow the [GitLab flow](https://docs.gitlab.com/ee/topics/gitlab_flow.html) branching style, to allow simple management of multiple tagged releases, short-lived branches, and development on the main branch.
## Include Migration Files
### Version Numbering
InvenTree version numbering follows the [semantic versioning](https://semver.org/) specification.
### Master Branch
The HEAD of the "main" or "master" branch of InvenTree represents the current "latest" state of code development.
- All feature branches are merged into master
- All bug fixes are merged into master
**No pushing to master:** New featues must be submitted as a pull request from a separate branch (one branch per feature).
#### Feature Branches
Feature branches should be branched *from* the *master* branch.
- One major feature per branch / pull request
- Feature pull requests are merged back *into* the master branch
- Features *may* also be merged into a release candidate branch
### Stable Branch
The HEAD of the "stable" branch represents the latest stable release code.
- Versioned releases are merged into the "stable" branch
- Bug fix branches are made *from* the "stable" branch
#### Release Candidate Branches
- Release candidate branches are made from master, and merged into stable.
- RC branches are targetted at a major/minor version e.g. "0.5"
- When a release candidate branch is merged into *stable*, the release is tagged
#### Bugfix Branches
- If a bug is discovered in a tagged release version of InvenTree, a "bugfix" or "hotfix" branch should be made *from* that tagged release
- When approved, the branch is merged back *into* stable, with an incremented PATCH number (e.g. 0.4.1 -> 0.4.2)
- The bugfix *must* also be cherry picked into the *master* branch.
## Migration Files
Any required migration files **must** be included in the commit, or the pull-request will be rejected. If you change the underlying database schema, make sure you run `invoke migrate` and commit the migration files before submitting the PR.
## Update Translation Files
*Note: A github action checks for unstaged migration files and will reject the PR if it finds any!*
Any PRs which update translatable strings (i.e. text strings that will appear in the web-front UI) must also update the translation (locale) files to include hooks for the translated strings.
## Unit Testing
*This does not mean that all translations must be provided, but that the translation files must include locations for the translated strings to be written.*
Any new code should be covered by unit tests - a submitted PR may not be accepted if the code coverage for any new features is insufficient, or the overall code coverage is decreased.
To perform this step, simply run `invoke translate` from the top level directory before submitting the PR.
The InvenTree code base makes use of [GitHub actions](https://github.com/features/actions) to run a suite of automated tests against the code base every time a new pull request is received. These actions include (but are not limited to):
## Testing
- Checking Python and Javascript code against standard style guides
- Running unit test suite
- Automated building and pushing of docker images
- Generating translation files
Any new code should be covered by unit tests - a submitted PR may not be accepted if the code coverage is decreased.
The various github actions can be found in the `./github/workflows` directory
## Code Style
Sumbitted Python code is automatically checked against PEP style guidelines. Locally you can run `invoke style` to ensure the style checks will pass, before submitting the PR.
## Documentation
New features or updates to existing features should be accompanied by user documentation. A PR with associated documentation should link to the matching PR at https://github.com/inventree/inventree-docs/
## Code Style
## Translations
Sumbitted Python code is automatically checked against PEP style guidelines. Locally you can run `invoke style` to ensure the style checks will pass, before submitting the PR.
Any user-facing strings *must* be passed through the translation engine.
- InvenTree code is written in English
- User translatable strings are provided in English as the primary language
- Secondary language translations are provided [via Crowdin](https://crowdin.com/project/inventree)
*Note: Translation files are updated via GitHub actions - you do not need to compile translations files before submitting a pull request!*
### Python Code
For strings exposed via Python code, use the following format:
```python
from django.utils.translation import ugettext_lazy as _
user_facing_string = _('This string will be exposed to the translation engine!')
```
### Templated Strings
HTML and javascript files are passed through the django templating engine. Translatable strings are implemented as follows:
```html
{% load i18n %}
<span>{% trans "This string will be translated" %} - this string will not!</span>
```

View File

@@ -5,8 +5,6 @@ Main JSON interface views
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import logging
from django.utils.translation import ugettext_lazy as _
from django.http import JsonResponse
@@ -21,14 +19,7 @@ from .views import AjaxView
from .version import inventreeVersion, inventreeApiVersion, inventreeInstanceName
from .status import is_worker_running
from plugins import plugins as inventree_plugins
logger = logging.getLogger("inventree")
logger.info("Loading action plugins...")
action_plugins = inventree_plugins.load_action_plugins()
from plugin import registry
class InfoView(AjaxView):
@@ -110,10 +101,11 @@ class ActionPluginView(APIView):
'error': _("No action specified")
})
for plugin_class in action_plugins:
if plugin_class.action_name() == action:
plugin = plugin_class(request.user, data=data)
action_plugins = registry.with_mixin('action')
for plugin in action_plugins:
if plugin.action_name() == action:
# TODO @matmair use easier syntax once InvenTree 0.7.0 is released
plugin.init(request.user, data=data)
plugin.perform_action()

View File

@@ -46,7 +46,7 @@ class InvenTreeAPITestCase(APITestCase):
self.user.is_staff = True
self.user.save()
for role in self.roles:
self.assignRole(role)
@@ -106,12 +106,12 @@ class InvenTreeAPITestCase(APITestCase):
return response
def post(self, url, data, expected_code=None):
def post(self, url, data, expected_code=None, format='json'):
"""
Issue a POST request
"""
response = self.client.post(url, data=data, format='json')
response = self.client.post(url, data=data, format=format)
if expected_code is not None:
self.assertEqual(response.status_code, expected_code)
@@ -130,12 +130,24 @@ class InvenTreeAPITestCase(APITestCase):
return response
def patch(self, url, data, files=None, expected_code=None):
def patch(self, url, data, expected_code=None, format='json'):
"""
Issue a PATCH request
"""
response = self.client.patch(url, data=data, files=files, format='json')
response = self.client.patch(url, data=data, format=format)
if expected_code is not None:
self.assertEqual(response.status_code, expected_code)
return response
def options(self, url, expected_code=None):
"""
Issue an OPTIONS request
"""
response = self.client.options(url, format='json')
if expected_code is not None:
self.assertEqual(response.status_code, expected_code)

View File

@@ -18,41 +18,78 @@ class InvenTreeConfig(AppConfig):
def ready(self):
if canAppAccessDatabase():
self.remove_obsolete_tasks()
self.start_background_tasks()
if not isInTestMode():
self.update_exchange_rates()
def remove_obsolete_tasks(self):
"""
Delete any obsolete scheduled tasks in the database
"""
obsolete = [
'InvenTree.tasks.delete_expired_sessions',
'stock.tasks.delete_old_stock_items',
]
try:
from django_q.models import Schedule
except AppRegistryNotReady: # pragma: no cover
return
# Remove any existing obsolete tasks
Schedule.objects.filter(func__in=obsolete).delete()
def start_background_tasks(self):
try:
from django_q.models import Schedule
except (AppRegistryNotReady):
except AppRegistryNotReady: # pragma: no cover
return
logger.info("Starting background tasks...")
# Remove successful task results from the database
InvenTree.tasks.schedule_task(
'InvenTree.tasks.delete_successful_tasks',
schedule_type=Schedule.DAILY,
)
# Check for InvenTree updates
InvenTree.tasks.schedule_task(
'InvenTree.tasks.check_for_updates',
schedule_type=Schedule.DAILY
)
# Heartbeat to let the server know the background worker is running
InvenTree.tasks.schedule_task(
'InvenTree.tasks.heartbeat',
schedule_type=Schedule.MINUTES,
minutes=15
)
# Keep exchange rates up to date
InvenTree.tasks.schedule_task(
'InvenTree.tasks.update_exchange_rates',
schedule_type=Schedule.DAILY,
)
# Delete old error messages
InvenTree.tasks.schedule_task(
'InvenTree.tasks.delete_old_error_logs',
schedule_type=Schedule.DAILY,
)
# Delete old notification records
InvenTree.tasks.schedule_task(
'common.tasks.delete_old_notifications',
schedule_type=Schedule.DAILY,
)
def update_exchange_rates(self):
"""
Update exchange rates each time the server is started, *if*:
@@ -63,10 +100,10 @@ class InvenTreeConfig(AppConfig):
try:
from djmoney.contrib.exchange.models import ExchangeBackend
from datetime import datetime, timedelta
from InvenTree.tasks import update_exchange_rates
from common.settings import currency_code_default
except AppRegistryNotReady:
except AppRegistryNotReady: # pragma: no cover
pass
base_currency = currency_code_default()
@@ -78,23 +115,18 @@ class InvenTreeConfig(AppConfig):
last_update = backend.last_update
if last_update is not None:
delta = datetime.now().date() - last_update.date()
if delta > timedelta(days=1):
print(f"Last update was {last_update}")
update = True
else:
if last_update is None:
# Never been updated
print("Exchange backend has never been updated")
logger.info("Exchange backend has never been updated")
update = True
# Backend currency has changed?
if not base_currency == backend.base_currency:
print(f"Base currency changed from {backend.base_currency} to {base_currency}")
logger.info(f"Base currency changed from {backend.base_currency} to {base_currency}")
update = True
except (ExchangeBackend.DoesNotExist):
print("Exchange backend not found - updating")
logger.info("Exchange backend not found - updating")
update = True
except:
@@ -102,4 +134,7 @@ class InvenTreeConfig(AppConfig):
return
if update:
update_exchange_rates()
try:
update_exchange_rates()
except Exception as e:
logger.error(f"Error updating exchange rates: {e}")

View File

@@ -0,0 +1,100 @@
"""
Pull rendered copies of the templated
only used for testing the js files! - This file is omited from coverage
"""
from django.test import TestCase
from django.contrib.auth import get_user_model
import os
import pathlib
class RenderJavascriptFiles(TestCase):
"""
A unit test to "render" javascript files.
The server renders templated javascript files,
we need the fully-rendered files for linting and static tests.
"""
def setUp(self):
user = get_user_model()
self.user = user.objects.create_user(
username='testuser',
password='testpassword',
email='user@gmail.com',
)
self.client.login(username='testuser', password='testpassword')
def download_file(self, filename, prefix):
url = os.path.join(prefix, filename)
response = self.client.get(url)
here = os.path.abspath(os.path.dirname(__file__))
output_dir = os.path.join(
here,
'..',
'..',
'js_tmp',
)
output_dir = os.path.abspath(output_dir)
if not os.path.exists(output_dir):
os.mkdir(output_dir)
output_file = os.path.join(
output_dir,
filename,
)
with open(output_file, 'wb') as output:
output.write(response.content)
def download_files(self, subdir, prefix):
here = os.path.abspath(os.path.dirname(__file__))
js_template_dir = os.path.join(
here,
'..',
'templates',
'js',
)
directory = os.path.join(js_template_dir, subdir)
directory = os.path.abspath(directory)
js_files = pathlib.Path(directory).rglob('*.js')
n = 0
for f in js_files:
js = os.path.basename(f)
self.download_file(js, prefix)
n += 1
return n
def test_render_files(self):
"""
Look for all javascript files
"""
n = 0
print("Rendering javascript files...")
n += self.download_files('translated', '/js/i18n')
n += self.download_files('dynamic', '/js/dynamic')
print(f"Rendered {n} javascript files.")

View File

@@ -0,0 +1,90 @@
"""
Helper functions for loading InvenTree configuration options
"""
import os
import shutil
import logging
logger = logging.getLogger('inventree')
def get_base_dir():
""" Returns the base (top-level) InvenTree directory """
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def get_config_file():
"""
Returns the path of the InvenTree configuration file.
Note: It will be created it if does not already exist!
"""
base_dir = get_base_dir()
cfg_filename = os.getenv('INVENTREE_CONFIG_FILE')
if cfg_filename:
cfg_filename = cfg_filename.strip()
cfg_filename = os.path.abspath(cfg_filename)
else:
# Config file is *not* specified - use the default
cfg_filename = os.path.join(base_dir, 'config.yaml')
if not os.path.exists(cfg_filename):
print("InvenTree configuration file 'config.yaml' not found - creating default file")
cfg_template = os.path.join(base_dir, "config_template.yaml")
shutil.copyfile(cfg_template, cfg_filename)
print(f"Created config file {cfg_filename}")
return cfg_filename
def get_plugin_file():
"""
Returns the path of the InvenTree plugins specification file.
Note: It will be created if it does not already exist!
"""
# Check if the plugin.txt file (specifying required plugins) is specified
PLUGIN_FILE = os.getenv('INVENTREE_PLUGIN_FILE')
if not PLUGIN_FILE:
# If not specified, look in the same directory as the configuration file
config_dir = os.path.dirname(get_config_file())
PLUGIN_FILE = os.path.join(config_dir, 'plugins.txt')
if not os.path.exists(PLUGIN_FILE):
logger.warning("Plugin configuration file does not exist")
logger.info(f"Creating plugin file at '{PLUGIN_FILE}'")
# If opening the file fails (no write permission, for example), then this will throw an error
with open(PLUGIN_FILE, 'w') as plugin_file:
plugin_file.write("# InvenTree Plugins (uses PIP framework to install)\n\n")
return PLUGIN_FILE
def get_setting(environment_var, backup_val, default_value=None):
"""
Helper function for retrieving a configuration setting value
- First preference is to look for the environment variable
- Second preference is to look for the value of the settings file
- Third preference is the default value
"""
val = os.getenv(environment_var)
if val is not None:
return val
if backup_val is not None:
return backup_val
return default_value

View File

@@ -23,7 +23,7 @@ def health_status(request):
if request.path.endswith('.js'):
# Do not provide to script requests
return {}
return {} # pragma: no cover
if hasattr(request, '_inventree_health_status'):
# Do not duplicate efforts
@@ -36,9 +36,14 @@ def health_status(request):
'email_configured': InvenTree.status.is_email_configured(),
}
# The following keys are required to denote system health
health_keys = [
'django_q_running',
]
all_healthy = True
for k in status.keys():
for k in health_keys:
if status[k] is not True:
all_healthy = False

View File

@@ -1,6 +1,12 @@
import certifi
import ssl
from urllib.request import urlopen
from common.settings import currency_code_default, currency_codes
from urllib.error import URLError
from djmoney.contrib.exchange.backends.base import SimpleExchangeBackend
from django.db.utils import OperationalError
class InvenTreeExchange(SimpleExchangeBackend):
@@ -22,8 +28,37 @@ class InvenTreeExchange(SimpleExchangeBackend):
return {
}
def get_response(self, **kwargs):
"""
Custom code to get response from server.
Note: Adds a 5-second timeout
"""
url = self.get_url(**kwargs)
try:
context = ssl.create_default_context(cafile=certifi.where())
response = urlopen(url, timeout=5, context=context)
return response.read()
except:
# Returning None here will raise an error upstream
return None
def update_rates(self, base_currency=currency_code_default()):
symbols = ','.join(currency_codes())
super().update_rates(base=base_currency, symbols=symbols)
try:
super().update_rates(base=base_currency, symbols=symbols)
# catch connection errors
except URLError:
print('Encountered connection error while updating')
except OperationalError as e:
if 'SerializationFailure' in e.__cause__.__class__.__name__:
print('Serialization Failure while updating exchange rates')
# We are just going to swallow this exception because the
# exchange rates will be updated later by the scheduled task
else:
# Other operational errors probably are still show stoppers
# so reraise them so that the log contains the stacktrace
raise

View File

@@ -20,7 +20,6 @@ from djmoney.forms.fields import MoneyField
from djmoney.models.validators import MinMoneyValidator
import InvenTree.helpers
import common.settings
class InvenTreeURLFormField(FormURLField):
@@ -42,9 +41,11 @@ class InvenTreeURLField(models.URLField):
def money_kwargs():
""" returns the database settings for MoneyFields """
from common.settings import currency_code_mappings, currency_code_default
kwargs = {}
kwargs['currency_choices'] = common.settings.currency_code_mappings()
kwargs['default_currency'] = common.settings.currency_code_default
kwargs['currency_choices'] = currency_code_mappings()
kwargs['default_currency'] = currency_code_default()
return kwargs
@@ -52,10 +53,10 @@ class InvenTreeModelMoneyField(ModelMoneyField):
"""
Custom MoneyField for clean migrations while using dynamic currency settings
"""
def __init__(self, **kwargs):
# detect if creating migration
if 'makemigrations' in sys.argv:
if 'migrate' in sys.argv or 'makemigrations' in sys.argv:
# remove currency information for a clean migration
kwargs['default_currency'] = ''
kwargs['currency_choices'] = []

View File

@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from rest_framework.filters import OrderingFilter
class InvenTreeOrderingFilter(OrderingFilter):
"""
Custom OrderingFilter class which allows aliased filtering of related fields.
To use, simply specify this filter in the "filter_backends" section.
filter_backends = [
InvenTreeOrderingFilter,
]
Then, specify a ordering_field_aliases attribute:
ordering_field_alises = {
'name': 'part__part__name',
'SKU': 'part__SKU',
}
"""
def get_ordering(self, request, queryset, view):
ordering = super().get_ordering(request, queryset, view)
aliases = getattr(view, 'ordering_field_aliases', None)
# Attempt to map ordering fields based on provided aliases
if ordering is not None and aliases is not None:
"""
Ordering fields should be mapped to separate fields
"""
ordering_initial = ordering
ordering = []
for field in ordering_initial:
reverse = field.startswith('-')
if reverse:
field = field[1:]
# Are aliases defined for this field?
if field in aliases:
alias = aliases[field]
else:
alias = field
"""
Potentially, a single field could be "aliased" to multiple field,
(For example to enforce a particular ordering sequence)
e.g. to filter first by the integer value...
ordering_field_aliases = {
"reference": ["integer_ref", "reference"]
}
"""
if type(alias) is str:
alias = [alias]
elif type(alias) in [list, tuple]:
pass
else:
# Unsupported alias type
continue
for a in alias:
if reverse:
a = '-' + a
ordering.append(a)
return ordering

View File

@@ -4,17 +4,31 @@ Helper forms which subclass Django forms to provide additional functionality
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from urllib.parse import urlencode
import logging
from django.utils.translation import ugettext_lazy as _
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.models import User, Group
from django.conf import settings
from django.http import HttpResponseRedirect
from django.urls import reverse
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field
from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText, StrictButton, Div
from common.models import ColorTheme
from allauth.account.forms import SignupForm, set_form_field_order
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.exceptions import ImmediateHttpResponse
from allauth_2fa.adapter import OTPAdapter
from allauth_2fa.utils import user_has_valid_totp_device
from part.models import PartCategory
from common.models import InvenTreeSetting
logger = logging.getLogger('inventree')
class HelperForm(forms.ModelForm):
@@ -145,7 +159,6 @@ class EditUserForm(HelperForm):
'username',
'first_name',
'last_name',
'email'
]
@@ -177,39 +190,6 @@ class SetPasswordForm(HelperForm):
]
class ColorThemeSelectForm(forms.ModelForm):
""" Form for setting color theme """
name = forms.ChoiceField(choices=(), required=False)
class Meta:
model = ColorTheme
fields = [
'name'
]
def __init__(self, *args, **kwargs):
super(ColorThemeSelectForm, self).__init__(*args, **kwargs)
# Populate color themes choices
self.fields['name'].choices = ColorTheme.get_color_themes_choices()
self.helper = FormHelper()
# Form rendering
self.helper.form_show_labels = False
self.helper.layout = Layout(
Div(
Div(Field('name'),
css_class='col-sm-6',
style='width: 200px;'),
Div(StrictButton(_('Apply Theme'), css_class='btn btn-primary', type='submit'),
css_class='col-sm-6',
style='width: auto;'),
css_class='row',
),
)
class SettingCategorySelectForm(forms.ModelForm):
""" Form for setting category settings """
@@ -238,3 +218,112 @@ class SettingCategorySelectForm(forms.ModelForm):
css_class='row',
),
)
# override allauth
class CustomSignupForm(SignupForm):
"""
Override to use dynamic settings
"""
def __init__(self, *args, **kwargs):
kwargs['email_required'] = InvenTreeSetting.get_setting('LOGIN_MAIL_REQUIRED')
super().__init__(*args, **kwargs)
# check for two mail fields
if InvenTreeSetting.get_setting('LOGIN_SIGNUP_MAIL_TWICE'):
self.fields["email2"] = forms.EmailField(
label=_("Email (again)"),
widget=forms.TextInput(
attrs={
"type": "email",
"placeholder": _("Email address confirmation"),
}
),
)
# check for two password fields
if not InvenTreeSetting.get_setting('LOGIN_SIGNUP_PWD_TWICE'):
self.fields.pop("password2")
# reorder fields
set_form_field_order(self, ["username", "email", "email2", "password1", "password2", ])
def clean(self):
cleaned_data = super().clean()
# check for two mail fields
if InvenTreeSetting.get_setting('LOGIN_SIGNUP_MAIL_TWICE'):
email = cleaned_data.get("email")
email2 = cleaned_data.get("email2")
if (email and email2) and email != email2:
self.add_error("email2", _("You must type the same email each time."))
return cleaned_data
class RegistratonMixin:
"""
Mixin to check if registration should be enabled
"""
def is_open_for_signup(self, request, *args, **kwargs):
if settings.EMAIL_HOST and InvenTreeSetting.get_setting('LOGIN_ENABLE_REG', True):
return super().is_open_for_signup(request, *args, **kwargs)
return False
def save_user(self, request, user, form, commit=True):
user = super().save_user(request, user, form)
start_group = InvenTreeSetting.get_setting('SIGNUP_GROUP')
if start_group:
try:
group = Group.objects.get(id=start_group)
user.groups.add(group)
except Group.DoesNotExist:
logger.error('The setting `SIGNUP_GROUP` contains an non existant group', start_group)
user.save()
return user
class CustomAccountAdapter(RegistratonMixin, OTPAdapter, DefaultAccountAdapter):
"""
Override of adapter to use dynamic settings
"""
def send_mail(self, template_prefix, email, context):
"""only send mail if backend configured"""
if settings.EMAIL_HOST:
return super().send_mail(template_prefix, email, context)
return False
class CustomSocialAccountAdapter(RegistratonMixin, DefaultSocialAccountAdapter):
"""
Override of adapter to use dynamic settings
"""
def is_auto_signup_allowed(self, request, sociallogin):
if InvenTreeSetting.get_setting('LOGIN_SIGNUP_SSO_AUTO', True):
return super().is_auto_signup_allowed(request, sociallogin)
return False
# from OTPAdapter
def has_2fa_enabled(self, user):
"""Returns True if the user has 2FA configured."""
return user_has_valid_totp_device(user)
def login(self, request, user):
# Require two-factor authentication if it has been configured.
if self.has_2fa_enabled(user):
# Cast to string for the case when this is not a JSON serializable
# object, e.g. a UUID.
request.session['allauth_2fa_user_id'] = str(user.id)
redirect_url = reverse('two-factor-authenticate')
# Add GET parameters to the URL if they exist.
if request.GET:
redirect_url += u'?' + urlencode(request.GET)
raise ImmediateHttpResponse(
response=HttpResponseRedirect(redirect_url)
)
# Otherwise defer to the original allauth adapter.
return super().login(request, user)

View File

@@ -69,6 +69,35 @@ def getStaticUrl(filename):
return os.path.join(STATIC_URL, str(filename))
def construct_absolute_url(*arg):
"""
Construct (or attempt to construct) an absolute URL from a relative URL.
This is useful when (for example) sending an email to a user with a link
to something in the InvenTree web framework.
This requires the BASE_URL configuration option to be set!
"""
base = str(InvenTreeSetting.get_setting('INVENTREE_BASE_URL'))
url = '/'.join(arg)
if not base:
return url
# Strip trailing slash from base url
if base.endswith('/'):
base = base[:-1]
if url.startswith('/'):
url = url[1:]
url = f"{base}/{url}"
return url
def getBlankImage():
"""
Return the qualified path for the 'blank image' placeholder.
@@ -286,7 +315,7 @@ def WrapWithQuotes(text, quote='"'):
return text
def MakeBarcode(object_name, object_pk, object_data={}, **kwargs):
def MakeBarcode(object_name, object_pk, object_data=None, **kwargs):
""" Generate a string for a barcode. Adds some global InvenTree parameters.
Args:
@@ -298,6 +327,8 @@ def MakeBarcode(object_name, object_pk, object_data={}, **kwargs):
Returns:
json string of the supplied data plus some other data
"""
if object_data is None:
object_data = {}
url = kwargs.get('url', False)
brief = kwargs.get('brief', True)
@@ -344,13 +375,15 @@ def GetExportFormats():
]
def DownloadFile(data, filename, content_type='application/text'):
""" Create a dynamic file for the user to download.
def DownloadFile(data, filename, content_type='application/text', inline=False):
"""
Create a dynamic file for the user to download.
Args:
data: Raw file data (string or bytes)
filename: Filename for the file download
content_type: Content type for the download
inline: Download "inline" or as attachment? (Default = attachment)
Return:
A StreamingHttpResponse object wrapping the supplied data
@@ -365,26 +398,36 @@ def DownloadFile(data, filename, content_type='application/text'):
response = StreamingHttpResponse(wrapper, content_type=content_type)
response['Content-Length'] = len(data)
response['Content-Disposition'] = 'attachment; filename={f}'.format(f=filename)
disposition = "inline" if inline else "attachment"
response['Content-Disposition'] = f'{disposition}; filename={filename}'
return response
def extract_serial_numbers(serials, expected_quantity):
def extract_serial_numbers(serials, expected_quantity, next_number: int):
""" Attempt to extract serial numbers from an input string.
- Serial numbers must be integer values
- Serial numbers must be positive
- Serial numbers can be split by whitespace / newline / commma chars
- Serial numbers can be supplied as an inclusive range using hyphen char e.g. 10-20
- Serial numbers can be defined as ~ for getting the next available serial number
- Serial numbers can be supplied as <start>+ for getting all expecteded numbers starting from <start>
- Serial numbers can be supplied as <start>+<length> for getting <length> numbers starting from <start>
Args:
serials: input string with patterns
expected_quantity: The number of (unique) serial numbers we expect
next_number(int): the next possible serial number
"""
serials = serials.strip()
# fill in the next serial number into the serial
if '~' in serials:
serials = serials.replace('~', str(next_number))
groups = re.split("[\s,]+", serials)
numbers = []
@@ -432,7 +475,6 @@ def extract_serial_numbers(serials, expected_quantity):
continue
else:
errors.append(_("Invalid group: {g}").format(g=group))
continue
# plus signals either
# 1: 'start+': expected number of serials, starting at start
@@ -457,13 +499,21 @@ def extract_serial_numbers(serials, expected_quantity):
# no case
else:
errors.append(_("Invalid group: {g}").format(g=group))
continue
# Group should be a number
elif group:
# try conversion
try:
number = int(group)
except:
# seem like it is not a number
raise ValidationError(_(f"Invalid group {group}"))
number_add(number)
# No valid input group detected
else:
if group in numbers:
errors.append(_("Duplicate serial: {g}".format(g=group)))
else:
numbers.append(group)
raise ValidationError(_(f"Invalid/no group {group}"))
if len(errors) > 0:
raise ValidationError(errors)
@@ -631,13 +681,49 @@ def clean_decimal(number):
""" Clean-up decimal value """
# Check if empty
if number is None or number == '':
if number is None or number == '' or number == 0:
return Decimal(0)
# Check if decimal type
# Convert to string and remove spaces
number = str(number).replace(' ', '')
# Guess what type of decimal and thousands separators are used
count_comma = number.count(',')
count_point = number.count('.')
if count_comma == 1:
# Comma is used as decimal separator
if count_point > 0:
# Points are used as thousands separators: remove them
number = number.replace('.', '')
# Replace decimal separator with point
number = number.replace(',', '.')
elif count_point == 1:
# Point is used as decimal separator
if count_comma > 0:
# Commas are used as thousands separators: remove them
number = number.replace(',', '')
# Convert to Decimal type
try:
clean_number = Decimal(number)
except InvalidOperation:
clean_number = number
# Number cannot be converted to Decimal (eg. a string containing letters)
return Decimal(0)
return clean_number.quantize(Decimal(1)) if clean_number == clean_number.to_integral() else clean_number.normalize()
def inheritors(cls):
"""
Return all classes that are subclasses from the supplied cls
"""
subcls = set()
work = [cls]
while work:
parent = work.pop()
for child in parent.__subclasses__():
if child not in subcls:
subcls.add(child)
work.append(child)
return subcls

View File

@@ -1 +0,0 @@
{"de": 95, "el": 0, "en": 0, "es": 4, "fr": 6, "he": 0, "id": 0, "it": 0, "ja": 4, "ko": 0, "nl": 0, "no": 0, "pl": 27, "ru": 6, "sv": 0, "th": 0, "tr": 32, "vi": 0, "zh": 1}

View File

@@ -0,0 +1,43 @@
"""
Custom management command to cleanup old settings that are not defined anymore
"""
import logging
from django.core.management.base import BaseCommand
logger = logging.getLogger('inventree')
class Command(BaseCommand):
"""
Cleanup old (undefined) settings in the database
"""
def handle(self, *args, **kwargs):
logger.info("Collecting settings")
from common.models import InvenTreeSetting, InvenTreeUserSetting
# general settings
db_settings = InvenTreeSetting.objects.all()
model_settings = InvenTreeSetting.SETTINGS
# check if key exist and delete if not
for setting in db_settings:
if setting.key not in model_settings:
setting.delete()
logger.info(f"deleted setting '{setting.key}'")
# user settings
db_settings = InvenTreeUserSetting.objects.all()
model_settings = InvenTreeUserSetting.SETTINGS
# check if key exist and delete if not
for setting in db_settings:
if setting.key not in model_settings:
setting.delete()
logger.info(f"deleted user setting '{setting.key}'")
logger.info("checked all settings")

View File

@@ -0,0 +1,70 @@
"""
Custom management command to rebuild thumbnail images
- May be required after importing a new dataset, for example
"""
import os
import logging
from PIL import UnidentifiedImageError
from django.core.management.base import BaseCommand
from django.conf import settings
from django.db.utils import OperationalError, ProgrammingError
from company.models import Company
from part.models import Part
logger = logging.getLogger('inventree')
class Command(BaseCommand):
"""
Rebuild all thumbnail images
"""
def rebuild_thumbnail(self, model):
"""
Rebuild the thumbnail specified by the "image" field of the provided model
"""
if not model.image:
return
img = model.image
url = img.thumbnail.name
loc = os.path.join(settings.MEDIA_ROOT, url)
if not os.path.exists(loc):
logger.info(f"Generating thumbnail image for '{img}'")
try:
model.image.render_variations(replace=False)
except FileNotFoundError:
logger.error(f"ERROR: Image file '{img}' is missing")
except UnidentifiedImageError:
logger.error(f"ERROR: Image file '{img}' is not a valid image")
def handle(self, *args, **kwargs):
logger.setLevel(logging.INFO)
logger.info("Rebuilding Part thumbnails")
for part in Part.objects.exclude(image=None):
try:
self.rebuild_thumbnail(part)
except (OperationalError, ProgrammingError):
logger.error("ERROR: Database read error.")
break
logger.info("Rebuilding Company thumbnails")
for company in Company.objects.exclude(image=None):
try:
self.rebuild_thumbnail(company)
except (OperationalError, ProgrammingError):
logger.error("ERROR: abase read error.")
break

View File

@@ -0,0 +1,36 @@
"""
Custom management command to remove MFA for a user
"""
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
class Command(BaseCommand):
"""
Remove MFA for a user
"""
def add_arguments(self, parser):
parser.add_argument('mail', type=str)
def handle(self, *args, **kwargs):
# general settings
mail = kwargs.get('mail')
if not mail:
raise KeyError('A mail is required')
user = get_user_model()
mfa_user = [*set(user.objects.filter(email=mail) | user.objects.filter(emailaddress__email=mail))]
if len(mfa_user) == 0:
print('No user with this mail associated')
elif len(mfa_user) > 1:
print('More than one user found with this mail')
else:
# and clean out all MFA methods
# backup codes
mfa_user[0].staticdevice_set.all().delete()
# TOTP tokens
mfa_user[0].totpdevice_set.all().delete()
print(f'Removed all MFA methods for user {str(mfa_user[0])}')

View File

@@ -31,7 +31,10 @@ class InvenTreeMetadata(SimpleMetadata):
"""
def determine_metadata(self, request, view):
self.request = request
self.view = view
metadata = super().determine_metadata(request, view)
user = request.user
@@ -69,7 +72,10 @@ class InvenTreeMetadata(SimpleMetadata):
# Remove any HTTP methods that the user does not have permission for
for method, permission in rolemap.items():
if method in actions and not check(user, table, permission):
result = check(user, table, permission)
if method in actions and not result:
del actions[method]
# Add a 'DELETE' action if we are allowed to delete
@@ -95,25 +101,48 @@ class InvenTreeMetadata(SimpleMetadata):
serializer_info = super().get_serializer_info(serializer)
try:
ModelClass = serializer.Meta.model
model_class = None
model_fields = model_meta.get_field_info(ModelClass)
try:
model_class = serializer.Meta.model
model_fields = model_meta.get_field_info(model_class)
model_default_func = getattr(model_class, 'api_defaults', None)
if model_default_func:
model_default_values = model_class.api_defaults(self.request)
else:
model_default_values = {}
# Iterate through simple fields
for name, field in model_fields.fields.items():
if field.has_default() and name in serializer_info.keys():
if name in serializer_info.keys():
default = field.default
if field.has_default():
if callable(default):
try:
default = default()
except:
continue
default = field.default
serializer_info[name]['default'] = default
if callable(default):
try:
default = default()
except:
continue
serializer_info[name]['default'] = default
elif name in model_default_values:
serializer_info[name]['default'] = model_default_values[name]
# Attributes to copy from the model to the field (if they don't exist)
attributes = ['help_text']
for attr in attributes:
if attr not in serializer_info[name]:
if hasattr(field, attr):
serializer_info[name][attr] = getattr(field, attr)
# Iterate through relations
for name, relation in model_fields.relations.items():
@@ -133,9 +162,60 @@ class InvenTreeMetadata(SimpleMetadata):
if 'help_text' not in serializer_info[name] and hasattr(relation.model_field, 'help_text'):
serializer_info[name]['help_text'] = relation.model_field.help_text
if name in model_default_values:
serializer_info[name]['default'] = model_default_values[name]
except AttributeError:
pass
# Try to extract 'instance' information
instance = None
# Extract extra information if an instance is available
if hasattr(serializer, 'instance'):
instance = serializer.instance
if instance is None and model_class is not None:
# Attempt to find the instance based on kwargs lookup
kwargs = getattr(self.view, 'kwargs', None)
if kwargs:
pk = None
for field in ['pk', 'id', 'PK', 'ID']:
if field in kwargs:
pk = kwargs[field]
break
if pk is not None:
try:
instance = model_class.objects.get(pk=pk)
except (ValueError, model_class.DoesNotExist):
pass
if instance is not None:
"""
If there is an instance associated with this API View,
introspect that instance to find any specific API info.
"""
if hasattr(instance, 'api_instance_filters'):
instance_filters = instance.api_instance_filters()
for field_name, field_filters in instance_filters.items():
if field_name not in serializer_info.keys():
# The field might be missing, but is added later on
# This function seems to get called multiple times?
continue
if 'instance_filters' not in serializer_info[field_name].keys():
serializer_info[field_name]['instance_filters'] = {}
for key, value in field_filters.items():
serializer_info[field_name]['instance_filters'][key] = value
return serializer_info
def get_field_info(self, field):
@@ -153,9 +233,14 @@ class InvenTreeMetadata(SimpleMetadata):
if 'default' not in field_info and not field.default == empty:
field_info['default'] = field.get_default()
# Force non-nullable fields to read as "required"
# (even if there is a default value!)
if not field.allow_null and not (hasattr(field, 'allow_blank') and field.allow_blank):
field_info['required'] = True
# Introspect writable related fields
if field_info['type'] == 'field' and not field_info['read_only']:
# If the field is a PrimaryKeyRelatedField, we can extract the model from the queryset
if isinstance(field, serializers.PrimaryKeyRelatedField):
model = field.queryset.model
@@ -166,7 +251,12 @@ class InvenTreeMetadata(SimpleMetadata):
if model:
# Mark this field as "related", and point to the URL where we can get the data!
field_info['type'] = 'related field'
field_info['api_url'] = model.get_api_url()
field_info['model'] = model._meta.model_name
# Special case for 'user' model
if field_info['model'] == 'user':
field_info['api_url'] = '/api/user/'
else:
field_info['api_url'] = model.get_api_url()
return field_info

View File

@@ -1,12 +1,18 @@
from django.shortcuts import HttpResponseRedirect
from django.urls import reverse_lazy
from django.urls import reverse_lazy, Resolver404
from django.db import connection
from django.shortcuts import redirect
from django.conf.urls import include, url
import logging
import time
import operator
from rest_framework.authtoken.models import Token
from allauth_2fa.middleware import BaseRequire2FAMiddleware, AllauthTwoFactorMiddleware
from InvenTree.urls import frontendpatterns
from common.models import InvenTreeSetting
logger = logging.getLogger("inventree")
@@ -21,28 +27,15 @@ class AuthRequiredMiddleware(object):
assert hasattr(request, 'user')
response = self.get_response(request)
# API requests are handled by the DRF library
if request.path_info.startswith('/api/'):
return self.get_response(request)
if not request.user.is_authenticated:
"""
Normally, a web-based session would use csrftoken based authentication.
However when running an external application (e.g. the InvenTree app),
we wish to use token-based auth to grab media files.
So, we will allow token-based authentication but ONLY for the /media/ directory.
What problem is this solving?
- The InvenTree mobile app does not use csrf token auth
- Token auth is used by the Django REST framework, but that is under the /api/ endpoint
- Media files (e.g. Part images) are required to be served to the app
- We do not want to make /media/ files accessible without login!
There is PROBABLY a better way of going about this?
a) Allow token-based authentication against a user?
b) Serve /media/ files in a duplicate location e.g. /api/media/ ?
c) Is there a "standard" way of solving this problem?
My [google|stackoverflow]-fu has failed me. So this hack has been created.
However when running an external application (e.g. the InvenTree app or Python library),
we must validate the user token manually.
"""
authorized = False
@@ -56,33 +49,35 @@ class AuthRequiredMiddleware(object):
elif request.path_info.startswith('/accounts/'):
authorized = True
elif 'Authorization' in request.headers.keys():
auth = request.headers['Authorization'].strip()
elif 'Authorization' in request.headers.keys() or 'authorization' in request.headers.keys():
auth = request.headers.get('Authorization', request.headers.get('authorization')).strip()
if auth.startswith('Token') and len(auth.split()) == 2:
token = auth.split()[1]
if auth.lower().startswith('token') and len(auth.split()) == 2:
token_key = auth.split()[1]
# Does the provided token match a valid user?
if Token.objects.filter(key=token).exists():
try:
token = Token.objects.get(key=token_key)
allowed = ['/api/', '/media/']
# Provide the user information to the request
request.user = token.user
authorized = True
# Only allow token-auth for /media/ or /static/ dirs!
if any([request.path_info.startswith(a) for a in allowed]):
authorized = True
except Token.DoesNotExist:
logger.warning(f"Access denied for unknown token {token_key}")
# No authorization was found for the request
if not authorized:
# A logout request will redirect the user to the login screen
if request.path_info == reverse_lazy('logout'):
return HttpResponseRedirect(reverse_lazy('login'))
if request.path_info == reverse_lazy('account_logout'):
return HttpResponseRedirect(reverse_lazy('account_login'))
path = request.path_info
# List of URL endpoints we *do not* want to redirect to
urls = [
reverse_lazy('login'),
reverse_lazy('logout'),
reverse_lazy('account_login'),
reverse_lazy('account_logout'),
reverse_lazy('admin:login'),
reverse_lazy('admin:logout'),
]
@@ -90,10 +85,9 @@ class AuthRequiredMiddleware(object):
if path not in urls and not path.startswith('/api/'):
# Save the 'next' parameter to pass through to the login view
return redirect('%s?next=%s' % (reverse_lazy('login'), request.path))
return redirect('%s?next=%s' % (reverse_lazy('account_login'), request.path))
# Code to be executed for each request/response after
# the view is called.
response = self.get_response(request)
return response
@@ -157,3 +151,28 @@ class QueryCountMiddleware(object):
print(x[0], ':', x[1])
return response
url_matcher = url('', include(frontendpatterns))
class Check2FAMiddleware(BaseRequire2FAMiddleware):
"""check if user is required to have MFA enabled"""
def require_2fa(self, request):
# Superusers are require to have 2FA.
try:
if url_matcher.resolve(request.path[1:]):
return InvenTreeSetting.get_setting('LOGIN_ENFORCE_MFA')
except Resolver404:
pass
return False
class CustomAllauthTwoFactorMiddleware(AllauthTwoFactorMiddleware):
"""This function ensures only frontend code triggers the MFA auth cycle"""
def process_request(self, request):
try:
if not url_matcher.resolve(request.path[1:]):
super().process_request(request)
except Resolver404:
pass

View File

@@ -4,9 +4,12 @@ Generic models which provide extra functionality over base Django model types.
from __future__ import unicode_literals
import re
import os
import logging
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _
@@ -18,7 +21,11 @@ from django.dispatch import receiver
from mptt.models import MPTTModel, TreeForeignKey
from mptt.exceptions import InvalidMove
from .validators import validate_tree_name
from InvenTree.fields import InvenTreeURLField
from InvenTree.validators import validate_tree_name
logger = logging.getLogger('inventree')
def rename_attachment(instance, filename):
@@ -38,15 +45,131 @@ def rename_attachment(instance, filename):
return os.path.join(instance.getSubdir(), filename)
class DataImportMixin(object):
"""
Model mixin class which provides support for 'data import' functionality.
Models which implement this mixin should provide information on the fields available for import
"""
# Define a map of fields avaialble for import
IMPORT_FIELDS = {}
@classmethod
def get_import_fields(cls):
"""
Return all available import fields
Where information on a particular field is not explicitly provided,
introspect the base model to (attempt to) find that information.
"""
fields = cls.IMPORT_FIELDS
for name, field in fields.items():
# Attempt to extract base field information from the model
base_field = None
for f in cls._meta.fields:
if f.name == name:
base_field = f
break
if base_field:
if 'label' not in field:
field['label'] = base_field.verbose_name
if 'help_text' not in field:
field['help_text'] = base_field.help_text
fields[name] = field
return fields
@classmethod
def get_required_import_fields(cls):
""" Return all *required* import fields """
fields = {}
for name, field in cls.get_import_fields().items():
required = field.get('required', False)
if required:
fields[name] = field
return fields
class ReferenceIndexingMixin(models.Model):
"""
A mixin for keeping track of numerical copies of the "reference" field.
!!DANGER!! always add `ReferenceIndexingSerializerMixin`to all your models serializers to
ensure the reference field is not too big
Here, we attempt to convert a "reference" field value (char) to an integer,
for performing fast natural sorting.
This requires extra database space (due to the extra table column),
but is required as not all supported database backends provide equivalent casting.
This mixin adds a field named 'reference_int'.
- If the 'reference' field can be cast to an integer, it is stored here
- If the 'reference' field *starts* with an integer, it is stored here
- Otherwise, we store zero
"""
class Meta:
abstract = True
def rebuild_reference_field(self):
reference = getattr(self, 'reference', '')
self.reference_int = extract_int(reference)
reference_int = models.BigIntegerField(default=0)
def extract_int(reference, clip=0x7fffffff):
# Default value if we cannot convert to an integer
ref_int = 0
# Look at the start of the string - can it be "integerized"?
result = re.match(r"^(\d+)", reference)
if result and len(result.groups()) == 1:
ref = result.groups()[0]
try:
ref_int = int(ref)
except:
ref_int = 0
# Ensure that the returned values are within the range that can be stored in an IntegerField
# Note: This will result in large values being "clipped"
if clip is not None:
if ref_int > clip:
ref_int = clip
elif ref_int < -clip:
ref_int = -clip
return ref_int
class InvenTreeAttachment(models.Model):
""" Provides an abstracted class for managing file attachments.
An attachment can be either an uploaded file, or an external URL
Attributes:
attachment: File
comment: String descriptor for the attachment
user: User associated with file upload
upload_date: Date the file was uploaded
"""
def getSubdir(self):
"""
Return the subdirectory under which attachments should be stored.
@@ -55,11 +178,32 @@ class InvenTreeAttachment(models.Model):
return "attachments"
def save(self, *args, **kwargs):
# Either 'attachment' or 'link' must be specified!
if not self.attachment and not self.link:
raise ValidationError({
'attachment': _('Missing file'),
'link': _('Missing external link'),
})
super().save(*args, **kwargs)
def __str__(self):
return os.path.basename(self.attachment.name)
if self.attachment is not None:
return os.path.basename(self.attachment.name)
else:
return str(self.link)
attachment = models.FileField(upload_to=rename_attachment, verbose_name=_('Attachment'),
help_text=_('Select file to attach'))
help_text=_('Select file to attach'),
blank=True, null=True
)
link = InvenTreeURLField(
blank=True, null=True,
verbose_name=_('Link'),
help_text=_('Link to external URL')
)
comment = models.CharField(blank=True, max_length=100, verbose_name=_('Comment'), help_text=_('File comment'))
@@ -75,7 +219,76 @@ class InvenTreeAttachment(models.Model):
@property
def basename(self):
return os.path.basename(self.attachment.name)
if self.attachment:
return os.path.basename(self.attachment.name)
else:
return None
@basename.setter
def basename(self, fn):
"""
Function to rename the attachment file.
- Filename cannot be empty
- Filename cannot contain illegal characters
- Filename must specify an extension
- Filename cannot match an existing file
"""
fn = fn.strip()
if len(fn) == 0:
raise ValidationError(_('Filename must not be empty'))
attachment_dir = os.path.join(
settings.MEDIA_ROOT,
self.getSubdir()
)
old_file = os.path.join(
settings.MEDIA_ROOT,
self.attachment.name
)
new_file = os.path.join(
settings.MEDIA_ROOT,
self.getSubdir(),
fn
)
new_file = os.path.abspath(new_file)
# Check that there are no directory tricks going on...
if not os.path.dirname(new_file) == attachment_dir:
logger.error(f"Attempted to rename attachment outside valid directory: '{new_file}'")
raise ValidationError(_("Invalid attachment directory"))
# Ignore further checks if the filename is not actually being renamed
if new_file == old_file:
return
forbidden = ["'", '"', "#", "@", "!", "&", "^", "<", ">", ":", ";", "/", "\\", "|", "?", "*", "%", "~", "`"]
for c in forbidden:
if c in fn:
raise ValidationError(_(f"Filename contains illegal character '{c}'"))
if len(fn.split('.')) < 2:
raise ValidationError(_("Filename missing extension"))
if not os.path.exists(old_file):
logger.error(f"Trying to rename attachment '{old_file}' which does not exist")
return
if os.path.exists(new_file):
raise ValidationError(_("Attachment with this filename already exists"))
try:
os.rename(old_file, new_file)
self.attachment.name = os.path.join(self.getSubdir(), fn)
self.save()
except:
raise ValidationError(_("Error renaming file"))
class Meta:
abstract = True
@@ -93,6 +306,17 @@ class InvenTreeTree(MPTTModel):
parent: The item immediately above this one. An item with a null parent is a top-level item
"""
def api_instance_filters(self):
"""
Instance filters for InvenTreeTree models
"""
return {
'parent': {
'exclude_tree': self.pk,
}
}
def save(self, *args, **kwargs):
try:

View File

@@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
import inspect
import importlib
import pkgutil
def iter_namespace(pkg):
return pkgutil.iter_modules(pkg.__path__, pkg.__name__ + ".")
def get_modules(pkg):
# Return all modules in a given package
return [importlib.import_module(name) for finder, name, ispkg in iter_namespace(pkg)]
def get_classes(module):
# Return all classes in a given module
return inspect.getmembers(module, inspect.isclass)
def get_plugins(pkg, baseclass):
"""
Return a list of all modules under a given package.
- Modules must be a subclass of the provided 'baseclass'
- Modules must have a non-empty PLUGIN_NAME parameter
"""
plugins = []
modules = get_modules(pkg)
# Iterate through each module in the package
for mod in modules:
# Iterate through each class in the module
for item in get_classes(mod):
plugin = item[1]
if issubclass(plugin, baseclass) and plugin.PLUGIN_NAME:
plugins.append(plugin)
return plugins

View File

@@ -6,10 +6,16 @@ def isInTestMode():
Returns True if the database is in testing mode
"""
if 'test' in sys.argv:
return True
return 'test' in sys.argv
return False
def isImportingData():
"""
Returns True if the database is currently importing data,
e.g. 'loaddata' command is performed
"""
return 'loaddata' in sys.argv
def canAppAccessDatabase(allow_test=False):

View File

@@ -5,15 +5,18 @@ Serializers used in various InvenTree apps
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
import tablib
from decimal import Decimal
from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils.translation import ugettext_lazy as _
from django.db import models
from djmoney.contrib.django_rest_framework.fields import MoneyField
from djmoney.money import Money
@@ -25,6 +28,8 @@ from rest_framework.fields import empty
from rest_framework.exceptions import ValidationError
from rest_framework.serializers import DecimalField
from .models import extract_int
class InvenTreeMoneySerializer(MoneyField):
"""
@@ -34,6 +39,13 @@ class InvenTreeMoneySerializer(MoneyField):
Ref: https://github.com/django-money/django-money/blob/master/djmoney/contrib/django_rest_framework/fields.py
"""
def __init__(self, *args, **kwargs):
kwargs["max_digits"] = kwargs.get("max_digits", 19)
kwargs["decimal_places"] = kwargs.get("decimal_places", 4)
super().__init__(*args, **kwargs)
def get_value(self, data):
"""
Test that the returned amount is a valid Decimal
@@ -46,16 +58,18 @@ class InvenTreeMoneySerializer(MoneyField):
amount = None
try:
if amount is not None:
if amount is not None and amount is not empty:
amount = Decimal(amount)
except:
raise ValidationError(_("Must be a valid number"))
raise ValidationError({
self.field_name: [_("Must be a valid number")],
})
currency = data.get(get_currency_field_name(self.field_name), self.default_currency)
if currency and amount is not None and not isinstance(amount, MONEY_CLASSES) and amount is not empty:
return Money(amount, currency)
return amount
@@ -85,14 +99,21 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
"""
def __init__(self, instance=None, data=empty, **kwargs):
# self.instance = instance
"""
Custom __init__ routine to ensure that *default* values (as specified in the ORM)
are used by the DRF serializers, *if* the values are not provided by the user.
"""
# If instance is None, we are creating a new instance
if instance is None and data is not empty:
# Required to side-step immutability of a QueryDict
data = data.copy()
if data is None:
data = OrderedDict()
else:
new_data = OrderedDict()
new_data.update(data)
data = new_data
# Add missing fields which have default values
ModelClass = self.Meta.model
@@ -165,6 +186,18 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
return self.instance
def update(self, instance, validated_data):
"""
Catch any django ValidationError, and re-throw as a DRF ValidationError
"""
try:
instance = super().update(instance, validated_data)
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=serializers.as_serializer_error(exc))
return instance
def run_validation(self, data=empty):
"""
Perform serializer validation.
@@ -186,18 +219,40 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
# Update instance fields
for attr, value in data.items():
setattr(instance, attr, value)
try:
setattr(instance, attr, value)
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=serializers.as_serializer_error(exc))
# Run a 'full_clean' on the model.
# Note that by default, DRF does *not* perform full model validation!
try:
instance.full_clean()
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=serializers.as_serializer_error(exc))
data = exc.message_dict
# Change '__all__' key (django style) to 'non_field_errors' (DRF style)
if '__all__' in data:
data['non_field_errors'] = data['__all__']
del data['__all__']
raise ValidationError(data)
return data
class ReferenceIndexingSerializerMixin():
"""
This serializer mixin ensures the the reference is not to big / small
for the BigIntegerField
"""
def validate_reference(self, value):
if extract_int(value) > models.BigIntegerField.MAX_BIGINT:
raise serializers.ValidationError('reference is to to big')
return value
class InvenTreeAttachmentSerializerField(serializers.FileField):
"""
Override the DRF native FileField serializer,
@@ -227,6 +282,27 @@ class InvenTreeAttachmentSerializerField(serializers.FileField):
return os.path.join(str(settings.MEDIA_URL), str(value))
class InvenTreeAttachmentSerializer(InvenTreeModelSerializer):
"""
Special case of an InvenTreeModelSerializer, which handles an "attachment" model.
The only real addition here is that we support "renaming" of the attachment file.
"""
attachment = InvenTreeAttachmentSerializerField(
required=False,
allow_null=False,
)
# The 'filename' field must be present in the serializer
filename = serializers.CharField(
label=_('Filename'),
required=False,
source='basename',
allow_blank=False,
)
class InvenTreeImageSerializerField(serializers.ImageField):
"""
Custom image serializer.
@@ -239,3 +315,326 @@ class InvenTreeImageSerializerField(serializers.ImageField):
return None
return os.path.join(str(settings.MEDIA_URL), str(value))
class InvenTreeDecimalField(serializers.FloatField):
"""
Custom serializer for decimal fields. Solves the following issues:
- The normal DRF DecimalField renders values with trailing zeros
- Using a FloatField can result in rounding issues: https://code.djangoproject.com/ticket/30290
"""
def to_internal_value(self, data):
# Convert the value to a string, and then a decimal
try:
return Decimal(str(data))
except:
raise serializers.ValidationError(_("Invalid value"))
class DataFileUploadSerializer(serializers.Serializer):
"""
Generic serializer for uploading a data file, and extracting a dataset.
- Validates uploaded file
- Extracts column names
- Extracts data rows
"""
# Implementing class should register a target model (database model) to be used for import
TARGET_MODEL = None
class Meta:
fields = [
'data_file',
]
data_file = serializers.FileField(
label=_("Data File"),
help_text=_("Select data file for upload"),
required=True,
allow_empty_file=False,
)
def validate_data_file(self, data_file):
"""
Perform validation checks on the uploaded data file.
"""
self.filename = data_file.name
name, ext = os.path.splitext(data_file.name)
# Remove the leading . from the extension
ext = ext[1:]
accepted_file_types = [
'xls', 'xlsx',
'csv', 'tsv',
'xml',
]
if ext not in accepted_file_types:
raise serializers.ValidationError(_("Unsupported file type"))
# Impose a 50MB limit on uploaded BOM files
max_upload_file_size = 50 * 1024 * 1024
if data_file.size > max_upload_file_size:
raise serializers.ValidationError(_("File is too large"))
# Read file data into memory (bytes object)
try:
data = data_file.read()
except Exception as e:
raise serializers.ValidationError(str(e))
if ext in ['csv', 'tsv', 'xml']:
try:
data = data.decode()
except Exception as e:
raise serializers.ValidationError(str(e))
# Convert to a tablib dataset (we expect headers)
try:
self.dataset = tablib.Dataset().load(data, ext, headers=True)
except Exception as e:
raise serializers.ValidationError(str(e))
if len(self.dataset.headers) == 0:
raise serializers.ValidationError(_("No columns found in file"))
if len(self.dataset) == 0:
raise serializers.ValidationError(_("No data rows found in file"))
return data_file
def match_column(self, column_name, field_names, exact=False):
"""
Attempt to match a column name (from the file) to a field (defined in the model)
Order of matching is:
- Direct match
- Case insensitive match
- Fuzzy match
"""
column_name = column_name.strip()
column_name_lower = column_name.lower()
if column_name in field_names:
return column_name
for field_name in field_names:
if field_name.lower() == column_name_lower:
return field_name
if exact:
# Finished available 'exact' matches
return None
# TODO: Fuzzy pattern matching for column names
# No matches found
return None
def extract_data(self):
"""
Returns dataset extracted from the file
"""
# Provide a dict of available import fields for the model
model_fields = {}
# Keep track of columns we have already extracted
matched_columns = set()
if self.TARGET_MODEL:
try:
model_fields = self.TARGET_MODEL.get_import_fields()
except:
pass
# Extract a list of valid model field names
model_field_names = [key for key in model_fields.keys()]
# Provide a dict of available columns from the dataset
file_columns = {}
for header in self.dataset.headers:
column = {}
# Attempt to "match" file columns to model fields
match = self.match_column(header, model_field_names, exact=True)
if match is not None and match not in matched_columns:
matched_columns.add(match)
column['value'] = match
else:
column['value'] = None
file_columns[header] = column
return {
'file_fields': file_columns,
'model_fields': model_fields,
'rows': [row.values() for row in self.dataset.dict],
'filename': self.filename,
}
def save(self):
...
class DataFileExtractSerializer(serializers.Serializer):
"""
Generic serializer for extracting data from an imported dataset.
- User provides an array of matched headers
- User provides an array of raw data rows
"""
# Implementing class should register a target model (database model) to be used for import
TARGET_MODEL = None
class Meta:
fields = [
'columns',
'rows',
]
# Mapping of columns
columns = serializers.ListField(
child=serializers.CharField(
allow_blank=True,
),
)
rows = serializers.ListField(
child=serializers.ListField(
child=serializers.CharField(
allow_blank=True,
allow_null=True,
),
)
)
def validate(self, data):
data = super().validate(data)
self.columns = data.get('columns', [])
self.rows = data.get('rows', [])
if len(self.rows) == 0:
raise serializers.ValidationError(_("No data rows provided"))
if len(self.columns) == 0:
raise serializers.ValidationError(_("No data columns supplied"))
self.validate_extracted_columns()
return data
@property
def data(self):
if self.TARGET_MODEL:
try:
model_fields = self.TARGET_MODEL.get_import_fields()
except:
model_fields = {}
rows = []
for row in self.rows:
"""
Optionally pre-process each row, before sending back to the client
"""
processed_row = self.process_row(self.row_to_dict(row))
if processed_row:
rows.append({
"original": row,
"data": processed_row,
})
return {
'fields': model_fields,
'columns': self.columns,
'rows': rows,
}
def process_row(self, row):
"""
Process a 'row' of data, which is a mapped column:value dict
Returns either a mapped column:value dict, or None.
If the function returns None, the column is ignored!
"""
# Default implementation simply returns the original row data
return row
def row_to_dict(self, row):
"""
Convert a "row" to a named data dict
"""
row_dict = {
'errors': {},
}
for idx, value in enumerate(row):
if idx < len(self.columns):
col = self.columns[idx]
if col:
row_dict[col] = value
return row_dict
def validate_extracted_columns(self):
"""
Perform custom validation of header mapping.
"""
if self.TARGET_MODEL:
try:
model_fields = self.TARGET_MODEL.get_import_fields()
except:
model_fields = {}
cols_seen = set()
for name, field in model_fields.items():
required = field.get('required', False)
# Check for missing required columns
if required:
if name not in self.columns:
raise serializers.ValidationError(_(f"Missing required column: '{name}'"))
for col in self.columns:
if not col:
continue
# Check for duplicated columns
if col in cols_seen:
raise serializers.ValidationError(_(f"Duplicate column: '{col}'"))
cols_seen.add(col)
def save(self):
"""
No "save" action for this serializer
"""
...

View File

@@ -12,10 +12,11 @@ database setup in this file.
"""
import logging
import os
import random
import socket
import string
import shutil
import sys
from datetime import datetime
@@ -24,31 +25,14 @@ import moneyed
import yaml
from django.utils.translation import gettext_lazy as _
from django.contrib.messages import constants as messages
import django.conf.locale
from .config import get_base_dir, get_config_file, get_plugin_file, get_setting
def _is_true(x):
# Shortcut function to determine if a value "looks" like a boolean
return str(x).lower() in ['1', 'y', 'yes', 't', 'true']
def get_setting(environment_var, backup_val, default_value=None):
"""
Helper function for retrieving a configuration setting value
- First preference is to look for the environment variable
- Second preference is to look for the value of the settings file
- Third preference is the default value
"""
val = os.getenv(environment_var)
if val is not None:
return val
if backup_val is not None:
return backup_val
return default_value
return str(x).strip().lower() in ['1', 'y', 'yes', 't', 'true']
# Determine if we are running in "test" mode e.g. "manage.py test"
@@ -58,31 +42,16 @@ TESTING = 'test' in sys.argv
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BASE_DIR = get_base_dir()
# Specify where the "config file" is located.
# By default, this is 'config.yaml'
cfg_filename = os.getenv('INVENTREE_CONFIG_FILE')
if cfg_filename:
cfg_filename = cfg_filename.strip()
cfg_filename = os.path.abspath(cfg_filename)
else:
# Config file is *not* specified - use the default
cfg_filename = os.path.join(BASE_DIR, 'config.yaml')
if not os.path.exists(cfg_filename):
print("InvenTree configuration file 'config.yaml' not found - creating default file")
cfg_template = os.path.join(BASE_DIR, "config_template.yaml")
shutil.copyfile(cfg_template, cfg_filename)
print(f"Created config file {cfg_filename}")
cfg_filename = get_config_file()
with open(cfg_filename, 'r') as cfg:
CONFIG = yaml.safe_load(cfg)
# We will place any config files in the same directory as the config file
config_dir = os.path.dirname(cfg_filename)
# Default action is to run the system in Debug mode
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = _is_true(get_setting(
@@ -90,6 +59,12 @@ DEBUG = _is_true(get_setting(
CONFIG.get('debug', True)
))
# Determine if we are running in "demo mode"
DEMO_MODE = _is_true(get_setting(
'INVENTREE_DEMO',
CONFIG.get('demo', False)
))
DOCKER = _is_true(get_setting(
'INVENTREE_DOCKER',
False
@@ -107,7 +82,7 @@ logging.basicConfig(
)
if log_level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']:
log_level = 'WARNING'
log_level = 'WARNING' # pragma: no cover
LOGGING = {
'version': 1,
@@ -121,6 +96,11 @@ LOGGING = {
'handlers': ['console'],
'level': log_level,
},
'filters': {
'require_not_maintenance_mode_503': {
'()': 'maintenance_mode.logging.RequireNotMaintenanceMode503',
},
},
}
# Get a logger instance for this setup file
@@ -139,20 +119,20 @@ d) Create "secret_key.txt" if it does not exist
if os.getenv("INVENTREE_SECRET_KEY"):
# Secret key passed in directly
SECRET_KEY = os.getenv("INVENTREE_SECRET_KEY").strip()
logger.info("SECRET_KEY loaded by INVENTREE_SECRET_KEY")
SECRET_KEY = os.getenv("INVENTREE_SECRET_KEY").strip() # pragma: no cover
logger.info("SECRET_KEY loaded by INVENTREE_SECRET_KEY") # pragma: no cover
else:
# Secret key passed in by file location
key_file = os.getenv("INVENTREE_SECRET_KEY_FILE")
if key_file:
key_file = os.path.abspath(key_file)
key_file = os.path.abspath(key_file) # pragma: no cover
else:
# default secret key location
key_file = os.path.join(BASE_DIR, "secret_key.txt")
key_file = os.path.abspath(key_file)
if not os.path.exists(key_file):
if not os.path.exists(key_file): # pragma: no cover
logger.info(f"Generating random key file at '{key_file}'")
# Create a random key file
with open(key_file, 'w') as f:
@@ -164,10 +144,34 @@ else:
try:
SECRET_KEY = open(key_file, "r").read().strip()
except Exception:
except Exception: # pragma: no cover
logger.exception(f"Couldn't load keyfile {key_file}")
sys.exit(-1)
# The filesystem location for served static files
STATIC_ROOT = os.path.abspath(
get_setting(
'INVENTREE_STATIC_ROOT',
CONFIG.get('static_root', None)
)
)
if STATIC_ROOT is None: # pragma: no cover
print("ERROR: INVENTREE_STATIC_ROOT directory not defined")
sys.exit(1)
# The filesystem location for served static files
MEDIA_ROOT = os.path.abspath(
get_setting(
'INVENTREE_MEDIA_ROOT',
CONFIG.get('media_root', None)
)
)
if MEDIA_ROOT is None: # pragma: no cover
print("ERROR: INVENTREE_MEDIA_ROOT directory is not defined")
sys.exit(1)
# List of allowed hosts (default = allow all)
ALLOWED_HOSTS = CONFIG.get('allowed_hosts', ['*'])
@@ -183,27 +187,17 @@ if cors_opt:
CORS_ORIGIN_ALLOW_ALL = cors_opt.get('allow_all', False)
if not CORS_ORIGIN_ALLOW_ALL:
CORS_ORIGIN_WHITELIST = cors_opt.get('whitelist', [])
CORS_ORIGIN_WHITELIST = cors_opt.get('whitelist', []) # pragma: no cover
# Web URL endpoint for served static files
STATIC_URL = '/static/'
# The filesystem location for served static files
STATIC_ROOT = os.path.abspath(
get_setting(
'INVENTREE_STATIC_ROOT',
CONFIG.get('static_root', '/home/inventree/data/static')
)
)
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'InvenTree', 'static'),
]
STATICFILES_DIRS = []
# Translated Template settings
STATICFILES_I18_PREFIX = 'i18n'
STATICFILES_I18_SRC = os.path.join(BASE_DIR, 'templates', 'js')
STATICFILES_I18_TRG = STATICFILES_DIRS[0] + '_' + STATICFILES_I18_PREFIX
STATICFILES_I18_SRC = os.path.join(BASE_DIR, 'templates', 'js', 'translated')
STATICFILES_I18_TRG = os.path.join(BASE_DIR, 'InvenTree', 'static_i18n')
STATICFILES_DIRS.append(STATICFILES_I18_TRG)
STATICFILES_I18_TRG = os.path.join(STATICFILES_I18_TRG, STATICFILES_I18_PREFIX)
@@ -217,19 +211,14 @@ STATIC_COLOR_THEMES_DIR = os.path.join(STATIC_ROOT, 'css', 'color-themes')
# Web URL endpoint for served media files
MEDIA_URL = '/media/'
# The filesystem location for served static files
MEDIA_ROOT = os.path.abspath(
get_setting(
'INVENTREE_MEDIA_ROOT',
CONFIG.get('media_root', '/home/inventree/data/media')
)
)
if DEBUG:
logger.info("InvenTree running in DEBUG mode")
logger.info("InvenTree running with DEBUG enabled")
logger.info(f"MEDIA_ROOT: '{MEDIA_ROOT}'")
logger.info(f"STATIC_ROOT: '{STATIC_ROOT}'")
if DEMO_MODE:
logger.warning("InvenTree running in DEMO mode") # pragma: no cover
logger.debug(f"MEDIA_ROOT: '{MEDIA_ROOT}'")
logger.debug(f"STATIC_ROOT: '{STATIC_ROOT}'")
# Application definition
@@ -239,9 +228,13 @@ INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'user_sessions', # db user sessions
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
# Maintenance
'maintenance_mode',
# InvenTree apps
'build.apps.BuildConfig',
@@ -253,6 +246,7 @@ INSTALLED_APPS = [
'report.apps.ReportConfig',
'stock.apps.StockConfig',
'users.apps.UsersConfig',
'plugin.apps.PluginAppConfig',
'InvenTree.apps.InvenTreeConfig', # InvenTree app runs last
# Third part add-ons
@@ -272,30 +266,45 @@ INSTALLED_APPS = [
'error_report', # Error reporting in the admin interface
'django_q',
'formtools', # Form wizard tools
'allauth', # Base app for SSO
'allauth.account', # Extend user with accounts
'allauth.socialaccount', # Use 'social' providers
'django_otp', # OTP is needed for MFA - base package
'django_otp.plugins.otp_totp', # Time based OTP
'django_otp.plugins.otp_static', # Backup codes
'allauth_2fa', # MFA flow for allauth
]
MIDDLEWARE = CONFIG.get('middleware', [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'user_sessions.middleware.SessionMiddleware', # db user sessions
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware', # MFA support
'InvenTree.middleware.CustomAllauthTwoFactorMiddleware', # Flow control for allauth
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'InvenTree.middleware.AuthRequiredMiddleware'
'InvenTree.middleware.AuthRequiredMiddleware',
'InvenTree.middleware.Check2FAMiddleware', # Check if the user should be forced to use MFA
'maintenance_mode.middleware.MaintenanceModeMiddleware',
])
# Error reporting middleware
MIDDLEWARE.append('error_report.middleware.ExceptionProcessor')
AUTHENTICATION_BACKENDS = CONFIG.get('authentication_backends', [
'django.contrib.auth.backends.ModelBackend'
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend', # SSO login via external providers
])
# If the debug toolbar is enabled, add the modules
if DEBUG and CONFIG.get('debug_toolbar', False):
if DEBUG and CONFIG.get('debug_toolbar', False): # pragma: no cover
logger.info("Running with DEBUG_TOOLBAR enabled")
INSTALLED_APPS.append('debug_toolbar')
MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')
@@ -311,7 +320,6 @@ TEMPLATES = [
os.path.join(MEDIA_ROOT, 'report'),
os.path.join(MEDIA_ROOT, 'label'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
@@ -319,10 +327,18 @@ TEMPLATES = [
'django.template.context_processors.i18n',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
# Custom InvenTree context processors
'InvenTree.context.health_status',
'InvenTree.context.status_codes',
'InvenTree.context.user_roles',
],
'loaders': [(
'django.template.loaders.cached.Loader', [
'plugin.loader.PluginTemplateLoader',
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
])
],
},
},
]
@@ -347,51 +363,6 @@ REST_FRAMEWORK = {
WSGI_APPLICATION = 'InvenTree.wsgi.application'
# django-q configuration
Q_CLUSTER = {
'name': 'InvenTree',
'workers': 4,
'timeout': 90,
'retry': 120,
'queue_limit': 50,
'bulk': 10,
'orm': 'default',
'sync': False,
}
# Markdownx configuration
# Ref: https://neutronx.github.io/django-markdownx/customization/
MARKDOWNX_MEDIA_PATH = datetime.now().strftime('markdownx/%Y/%m/%d')
# Markdownify configuration
# Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html
MARKDOWNIFY_WHITELIST_TAGS = [
'a',
'abbr',
'b',
'blockquote',
'em',
'h1', 'h2', 'h3',
'i',
'img',
'li',
'ol',
'p',
'strong',
'ul'
]
MARKDOWNIFY_WHITELIST_ATTRS = [
'href',
'src',
'alt',
]
MARKDOWNIFY_BLEACH = False
DATABASES = {}
"""
Configure the database backend based on the user-specified values.
@@ -400,7 +371,7 @@ Configure the database backend based on the user-specified values.
- The following code lets the user "mix and match" database configuration
"""
logger.info("Configuring database backend:")
logger.debug("Configuring database backend:")
# Extract database configuration from the config.yaml file
db_config = CONFIG.get('database', {})
@@ -425,7 +396,7 @@ for key in db_keys:
reqiured_keys = ['ENGINE', 'NAME']
for key in reqiured_keys:
if key not in db_config:
if key not in db_config: # pragma: no cover
error_msg = f'Missing required database configuration value {key}'
logger.error(error_msg)
@@ -444,7 +415,7 @@ db_engine = db_config['ENGINE'].lower()
# Correct common misspelling
if db_engine == 'sqlite':
db_engine = 'sqlite3'
db_engine = 'sqlite3' # pragma: no cover
if db_engine in ['sqlite3', 'postgresql', 'mysql']:
# Prepend the required python module string
@@ -454,20 +425,199 @@ if db_engine in ['sqlite3', 'postgresql', 'mysql']:
db_name = db_config['NAME']
db_host = db_config.get('HOST', "''")
print("InvenTree Database Configuration")
print("================================")
print(f"ENGINE: {db_engine}")
print(f"NAME: {db_name}")
print(f"HOST: {db_host}")
logger.info(f"DB_ENGINE: {db_engine}")
logger.info(f"DB_NAME: {db_name}")
logger.info(f"DB_HOST: {db_host}")
DATABASES['default'] = db_config
"""
In addition to base-level database configuration, we may wish to specify specific options to the database backend
Ref: https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-OPTIONS
"""
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
# 'OPTIONS' or 'options' can be specified in config.yaml
# Set useful sensible timeouts for a transactional webserver to communicate
# with its database server, that is, if the webserver is having issues
# connecting to the database server (such as a replica failover) don't sit and
# wait for possibly an hour or more, just tell the client something went wrong
# and let the client retry when they want to.
db_options = db_config.get("OPTIONS", db_config.get("options", {}))
# Specific options for postgres backend
if "postgres" in db_engine: # pragma: no cover
from psycopg2.extensions import (
ISOLATION_LEVEL_READ_COMMITTED,
ISOLATION_LEVEL_SERIALIZABLE,
)
# Connection timeout
if "connect_timeout" not in db_options:
# The DB server is in the same data center, it should not take very
# long to connect to the database server
# # seconds, 2 is minium allowed by libpq
db_options["connect_timeout"] = int(
os.getenv("INVENTREE_DB_TIMEOUT", 2)
)
# Setup TCP keepalive
# DB server is in the same DC, it should not become unresponsive for
# very long. With the defaults below we wait 5 seconds for the network
# issue to resolve itself. It it that doesn't happen whatever happened
# is probably fatal and no amount of waiting is going to fix it.
# # 0 - TCP Keepalives disabled; 1 - enabled
if "keepalives" not in db_options:
db_options["keepalives"] = int(
os.getenv("INVENTREE_DB_TCP_KEEPALIVES", "1")
)
# # Seconds after connection is idle to send keep alive
if "keepalives_idle" not in db_options:
db_options["keepalives_idle"] = int(
os.getenv("INVENTREE_DB_TCP_KEEPALIVES_IDLE", "1")
)
# # Seconds after missing ACK to send another keep alive
if "keepalives_interval" not in db_options:
db_options["keepalives_interval"] = int(
os.getenv("INVENTREE_DB_TCP_KEEPALIVES_INTERVAL", "1")
)
# # Number of missing ACKs before we close the connection
if "keepalives_count" not in db_options:
db_options["keepalives_count"] = int(
os.getenv("INVENTREE_DB_TCP_KEEPALIVES_COUNT", "5")
)
# # Milliseconds for how long pending data should remain unacked
# by the remote server
# TODO: Supported starting in PSQL 11
# "tcp_user_timeout": int(os.getenv("PGTCP_USER_TIMEOUT", "1000"),
# Postgres's default isolation level is Read Committed which is
# normally fine, but most developers think the database server is
# actually going to do Serializable type checks on the queries to
# protect against simultaneous changes.
# https://www.postgresql.org/docs/devel/transaction-iso.html
# https://docs.djangoproject.com/en/3.2/ref/databases/#isolation-level
if "isolation_level" not in db_options:
serializable = _is_true(
os.getenv("INVENTREE_DB_ISOLATION_SERIALIZABLE", "true")
)
db_options["isolation_level"] = (
ISOLATION_LEVEL_SERIALIZABLE
if serializable
else ISOLATION_LEVEL_READ_COMMITTED
)
# Specific options for MySql / MariaDB backend
if "mysql" in db_engine: # pragma: no cover
# TODO TCP time outs and keepalives
# MariaDB's default isolation level is Repeatable Read which is
# normally fine, but most developers think the database server is
# actually going to Serializable type checks on the queries to
# protect against siumltaneous changes.
# https://mariadb.com/kb/en/mariadb-transactions-and-isolation-levels-for-sql-server-users/#changing-the-isolation-level
# https://docs.djangoproject.com/en/3.2/ref/databases/#mysql-isolation-level
if "isolation_level" not in db_options:
serializable = _is_true(
os.getenv("INVENTREE_DB_ISOLATION_SERIALIZABLE", "true")
)
db_options["isolation_level"] = (
"serializable" if serializable else "read committed"
)
# Specific options for sqlite backend
if "sqlite" in db_engine:
# TODO: Verify timeouts are not an issue because no network is involved for SQLite
# SQLite's default isolation level is Serializable due to SQLite's
# single writer implementation. Presumably as a result of this, it is
# not possible to implement any lower isolation levels in SQLite.
# https://www.sqlite.org/isolation.html
pass
# Provide OPTIONS dict back to the database configuration dict
db_config['OPTIONS'] = db_options
DATABASES = {
'default': db_config
}
_cache_config = CONFIG.get("cache", {})
_cache_host = _cache_config.get("host", os.getenv("INVENTREE_CACHE_HOST"))
_cache_port = _cache_config.get(
"port", os.getenv("INVENTREE_CACHE_PORT", "6379")
)
if _cache_host: # pragma: no cover
# We are going to rely upon a possibly non-localhost for our cache,
# so don't wait too long for the cache as nothing in the cache should be
# irreplacable.
_cache_options = {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"SOCKET_CONNECT_TIMEOUT": int(os.getenv("CACHE_CONNECT_TIMEOUT", "2")),
"SOCKET_TIMEOUT": int(os.getenv("CACHE_SOCKET_TIMEOUT", "2")),
"CONNECTION_POOL_KWARGS": {
"socket_keepalive": _is_true(
os.getenv("CACHE_TCP_KEEPALIVE", "1")
),
"socket_keepalive_options": {
socket.TCP_KEEPCNT: int(
os.getenv("CACHE_KEEPALIVES_COUNT", "5")
),
socket.TCP_KEEPIDLE: int(
os.getenv("CACHE_KEEPALIVES_IDLE", "1")
),
socket.TCP_KEEPINTVL: int(
os.getenv("CACHE_KEEPALIVES_INTERVAL", "1")
),
socket.TCP_USER_TIMEOUT: int(
os.getenv("CACHE_TCP_USER_TIMEOUT", "1000")
),
},
},
}
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": f"redis://{_cache_host}:{_cache_port}/0",
"OPTIONS": _cache_options,
},
}
else:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
},
}
try:
# 4 background workers seems like a sensible default
background_workers = int(os.environ.get('INVENTREE_BACKGROUND_WORKERS', 4))
except ValueError: # pragma: no cover
background_workers = 4
# django-q configuration
Q_CLUSTER = {
'name': 'InvenTree',
'workers': background_workers,
'timeout': 90,
'retry': 120,
'queue_limit': 50,
'bulk': 10,
'orm': 'default',
'sync': False,
}
if _cache_host: # pragma: no cover
# If using external redis cache, make the cache the broker for Django Q
# as well
Q_CLUSTER["django_redis"] = "worker"
# database user sessions
SESSION_ENGINE = 'user_sessions.backends.db'
LOGOUT_REDIRECT_URL = 'index'
SILENCED_SYSTEM_CHECKS = [
'admin.E410',
]
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
@@ -491,7 +641,7 @@ AUTH_PASSWORD_VALIDATORS = [
EXTRA_URL_SCHEMES = CONFIG.get('extra_url_schemes', [])
if not type(EXTRA_URL_SCHEMES) in [list]:
if not type(EXTRA_URL_SCHEMES) in [list]: # pragma: no cover
logger.warning("extra_url_schemes not correctly formatted")
EXTRA_URL_SCHEMES = []
@@ -502,13 +652,47 @@ LANGUAGE_CODE = CONFIG.get('language', 'en-us')
# If a new language translation is supported, it must be added here
LANGUAGES = [
('en', _('English')),
('fr', _('French')),
('de', _('German')),
('el', _('Greek')),
('en', _('English')),
('es', _('Spanish')),
('es-mx', _('Spanish (Mexican)')),
('fr', _('French')),
('he', _('Hebrew')),
('it', _('Italian')),
('ja', _('Japanese')),
('ko', _('Korean')),
('nl', _('Dutch')),
('no', _('Norwegian')),
('pl', _('Polish')),
('pt', _('Portugese')),
('ru', _('Russian')),
('sv', _('Swedish')),
('th', _('Thai')),
('tr', _('Turkish')),
('vi', _('Vietnamese')),
('zh-cn', _('Chinese')),
]
# Testing interface translations
if get_setting('TEST_TRANSLATIONS', False): # pragma: no cover
# Set default language
LANGUAGE_CODE = 'xx'
# Add to language catalog
LANGUAGES.append(('xx', 'Test'))
# Add custom languages not provided by Django
EXTRA_LANG_INFO = {
'xx': {
'code': 'xx',
'name': 'Test',
'name_local': 'Test'
},
}
LANG_INFO = dict(django.conf.locale.LANG_INFO, **EXTRA_LANG_INFO)
django.conf.locale.LANG_INFO = LANG_INFO
# Currencies available for use
CURRENCIES = CONFIG.get(
'currencies',
@@ -519,7 +703,7 @@ CURRENCIES = CONFIG.get(
# Check that each provided currency is supported
for currency in CURRENCIES:
if currency not in moneyed.CURRENCIES:
if currency not in moneyed.CURRENCIES: # pragma: no cover
print(f"Currency code '{currency}' is not supported")
sys.exit(1)
@@ -593,14 +777,14 @@ USE_L10N = True
# Do not use native timezone support in "test" mode
# It generates a *lot* of cruft in the logs
if not TESTING:
USE_TZ = True
USE_TZ = True # pragma: no cover
DATE_INPUT_FORMATS = [
"%Y-%m-%d",
]
# crispy forms use the bootstrap templates
CRISPY_TEMPLATE_PACK = 'bootstrap3'
CRISPY_TEMPLATE_PACK = 'bootstrap4'
# Use database transactions when importing / exporting data
IMPORT_EXPORT_USE_TRANSACTIONS = True
@@ -615,3 +799,93 @@ MESSAGE_TAGS = {
messages.ERROR: 'alert alert-block alert-danger',
messages.INFO: 'alert alert-block alert-info',
}
SITE_ID = 1
# Load the allauth social backends
SOCIAL_BACKENDS = CONFIG.get('social_backends', [])
for app in SOCIAL_BACKENDS:
INSTALLED_APPS.append(app) # pragma: no cover
SOCIALACCOUNT_PROVIDERS = CONFIG.get('social_providers', [])
# settings for allauth
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = get_setting('INVENTREE_LOGIN_CONFIRM_DAYS', CONFIG.get('login_confirm_days', 3))
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = get_setting('INVENTREE_LOGIN_ATTEMPTS', CONFIG.get('login_attempts', 5))
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
# override forms / adapters
ACCOUNT_FORMS = {
'login': 'allauth.account.forms.LoginForm',
'signup': 'InvenTree.forms.CustomSignupForm',
'add_email': 'allauth.account.forms.AddEmailForm',
'change_password': 'allauth.account.forms.ChangePasswordForm',
'set_password': 'allauth.account.forms.SetPasswordForm',
'reset_password': 'allauth.account.forms.ResetPasswordForm',
'reset_password_from_key': 'allauth.account.forms.ResetPasswordKeyForm',
'disconnect': 'allauth.socialaccount.forms.DisconnectForm',
}
SOCIALACCOUNT_ADAPTER = 'InvenTree.forms.CustomSocialAccountAdapter'
ACCOUNT_ADAPTER = 'InvenTree.forms.CustomAccountAdapter'
# Markdownx configuration
# Ref: https://neutronx.github.io/django-markdownx/customization/
MARKDOWNX_MEDIA_PATH = datetime.now().strftime('markdownx/%Y/%m/%d')
# Markdownify configuration
# Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html
MARKDOWNIFY_WHITELIST_TAGS = [
'a',
'abbr',
'b',
'blockquote',
'em',
'h1', 'h2', 'h3',
'i',
'img',
'li',
'ol',
'p',
'strong',
'ul'
]
MARKDOWNIFY_WHITELIST_ATTRS = [
'href',
'src',
'alt',
]
MARKDOWNIFY_BLEACH = False
# Maintenance mode
MAINTENANCE_MODE_RETRY_AFTER = 60
MAINTENANCE_MODE_STATE_BACKEND = 'maintenance_mode.backends.DefaultStorageBackend'
# Are plugins enabled?
PLUGINS_ENABLED = _is_true(get_setting(
'INVENTREE_PLUGINS_ENABLED',
CONFIG.get('plugins_enabled', False),
))
PLUGIN_FILE = get_plugin_file()
# Plugin Directories (local plugins will be loaded from these directories)
PLUGIN_DIRS = ['plugin.builtin', 'barcodes.plugins', ]
if not TESTING:
# load local deploy directory in prod
PLUGIN_DIRS.append('plugins') # pragma: no cover
if DEBUG or TESTING:
# load samples in debug mode
PLUGIN_DIRS.append('plugin.samples')
# Plugin test settings
PLUGIN_TESTING = get_setting('PLUGIN_TESTING', TESTING) # are plugins beeing tested?
PLUGIN_TESTING_SETUP = get_setting('PLUGIN_TESTING_SETUP', False) # load plugins from setup hooks in testing?
PLUGIN_RETRY = get_setting('PLUGIN_RETRY', 5) # how often should plugin loading be tried?

File diff suppressed because one or more lines are too long

View File

@@ -1,170 +0,0 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @update: zhixin wen <wenzhixin2010@gmail.com>
*/
!($ => {
const diacriticsMap = {}
const defaultAccentsDiacritics = [
{base: 'A', letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'},
{base: 'AA',letters: '\uA732'},
{base: 'AE',letters: '\u00C6\u01FC\u01E2'},
{base: 'AO',letters: '\uA734'},
{base: 'AU',letters: '\uA736'},
{base: 'AV',letters: '\uA738\uA73A'},
{base: 'AY',letters: '\uA73C'},
{base: 'B', letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181'},
{base: 'C', letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E'},
{base: 'D', letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779'},
{base: 'DZ',letters: '\u01F1\u01C4'},
{base: 'Dz',letters: '\u01F2\u01C5'},
{base: 'E', letters: '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E'},
{base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B'},
{base: 'G', letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E'},
{base: 'H', letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D'},
{base: 'I', letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197'},
{base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248'},
{base: 'K', letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2'},
{base: 'L', letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780'},
{base: 'LJ',letters: '\u01C7'},
{base: 'Lj',letters: '\u01C8'},
{base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C'},
{base: 'N', letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4'},
{base: 'NJ',letters: '\u01CA'},
{base: 'Nj',letters: '\u01CB'},
{base: 'O', letters: '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C'},
{base: 'OI',letters: '\u01A2'},
{base: 'OO',letters: '\uA74E'},
{base: 'OU',letters: '\u0222'},
{base: 'OE',letters: '\u008C\u0152'},
{base: 'oe',letters: '\u009C\u0153'},
{base: 'P', letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754'},
{base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A'},
{base: 'R', letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782'},
{base: 'S', letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784'},
{base: 'T', letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786'},
{base: 'TZ',letters: '\uA728'},
{base: 'U', letters: '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244'},
{base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245'},
{base: 'VY',letters: '\uA760'},
{base: 'W', letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72'},
{base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C'},
{base: 'Y', letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE'},
{base: 'Z', letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762'},
{base: 'a', letters: '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250'},
{base: 'aa',letters: '\uA733'},
{base: 'ae',letters: '\u00E6\u01FD\u01E3'},
{base: 'ao',letters: '\uA735'},
{base: 'au',letters: '\uA737'},
{base: 'av',letters: '\uA739\uA73B'},
{base: 'ay',letters: '\uA73D'},
{base: 'b', letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253'},
{base: 'c', letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184'},
{base: 'd', letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A'},
{base: 'dz',letters: '\u01F3\u01C6'},
{base: 'e', letters: '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD'},
{base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C'},
{base: 'g', letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F'},
{base: 'h', letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265'},
{base: 'hv',letters: '\u0195'},
{base: 'i', letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131'},
{base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249'},
{base: 'k', letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3'},
{base: 'l', letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747'},
{base: 'lj',letters: '\u01C9'},
{base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F'},
{base: 'n', letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5'},
{base: 'nj',letters: '\u01CC'},
{base: 'o', letters: '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275'},
{base: 'oi',letters: '\u01A3'},
{base: 'ou',letters: '\u0223'},
{base: 'oo',letters: '\uA74F'},
{base: 'p',letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755'},
{base: 'q',letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759'},
{base: 'r',letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783'},
{base: 's',letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B'},
{base: 't',letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787'},
{base: 'tz',letters: '\uA729'},
{base: 'u',letters: '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289'},
{base: 'v',letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C'},
{base: 'vy',letters: '\uA761'},
{base: 'w',letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73'},
{base: 'x',letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D'},
{base: 'y',letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF'},
{base: 'z',letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763'}
]
const initNeutraliser = () => {
for (const diacritic of defaultAccentsDiacritics) {
const letters = diacritic.letters
for (let i = 0; i < letters.length; i++) {
diacriticsMap[letters[i]] = diacritic.base
}
}
}
/* eslint-disable no-control-regex */
const removeDiacritics = str => str.replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a)
$.extend($.fn.bootstrapTable.defaults, {
searchAccentNeutralise: false
})
$.BootstrapTable = class extends $.BootstrapTable {
init () {
if (this.options.searchAccentNeutralise) {
initNeutraliser()
}
super.init()
}
initSearch () {
if (this.options.sidePagination !== 'server') {
let s = this.searchText && this.searchText.toLowerCase()
const f = $.isEmptyObject(this.filterColumns) ? null : this.filterColumns
// Check filter
this.data = f ? this.options.data.filter((item, i) => {
for (const key in f) {
if (item[key] !== f[key]) {
return false
}
}
return true
}) : this.options.data
this.data = s ? this.options.data.filter((item, i) => {
for (let [key, value] of Object.entries(item)) {
key = $.isNumeric(key) ? parseInt(key, 10) : key
const column = this.columns[this.fieldsColumnsIndex[key]]
const j = this.header.fields.indexOf(key)
if (column && column.searchFormatter) {
value = $.fn.bootstrapTable.utils.calculateObjectValue(column,
this.header.formatters[j], [value, item, i], value)
}
const index = this.header.fields.indexOf(key)
if (index !== -1 && this.header.searchables[index] && typeof value === 'string') {
if (this.options.searchAccentNeutralise) {
value = removeDiacritics(value)
s = removeDiacritics(s)
}
if (this.options.strictSearch) {
if ((`${value}`).toLowerCase() === s) {
return true
}
} else {
if ((`${value}`).toLowerCase().includes(s)) {
return true
}
}
}
}
return false
}) : this.data
}
}
}
})(jQuery)

View File

@@ -1,17 +0,0 @@
{
"name": "Accent Neutralise",
"version": "1.0.0",
"description": "Plugin to neutralise the words.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/accent-neutralise",
"example": "#",
"plugins": [{
"name": "bootstrap-table-accent-neutralise",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/accent-neutralise"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Auto Refresh",
"version": "1.0.0",
"description": "Plugin to automatically refresh the table on an interval.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/auto-refresh",
"example": "#",
"plugins": [{
"name": "bootstrap-table-auto-refresh",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/auto-refresh"
}],
"author": {
"name": "fenichaler",
"image": "https://avatars.githubusercontent.com/u/3437075"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Cookie",
"version": "1.2.1",
"description": "Plugin to use the cookie of the browser.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/cookie",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/cookie.html",
"plugins": [{
"name": "bootstrap-table-cookie",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/cookie"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Copy Rows",
"version": "1.0.0",
"description": "Allows pushing of selected column data to the clipboard.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/copy-rows",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/copy-rows.html",
"plugins": [{
"name": "copy-rows",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/copy-rows"
}],
"author": {
"name": "Homer Glascock",
"image": "https://avatars1.githubusercontent.com/u/5546710"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "DeferURL",
"version": "1.0.0",
"description": "Plugin to defer server side processing.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/defer-url",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/defer-url.html",
"plugins": [{
"name": "bootstrap-table-defer-url",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/defer-url"
}],
"author": {
"name": "rubensa",
"image": "https://avatars1.githubusercontent.com/u/1469340"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Table Editable",
"version": "1.1.0",
"description": "Use the x-editable to in-place editing your table.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/editable",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/editable.html",
"plugins": [{
"name": "x-editable",
"url": "https://github.com/vitalets/x-editable"
}],
"author": {
"name": "wenzhixin",
"image": "https://avatars1.githubusercontent.com/u/2117018"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Table Export",
"version": "1.1.0",
"description": "Export your table data to JSON, XML, CSV, TXT, SQL, Word, Excel, PNG, PDF.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/export",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/export.html",
"plugins": [{
"name": "tableExport.jquery.plugin",
"url": "https://github.com/hhurz/tableExport.jquery.plugin"
}],
"author": {
"name": "wenzhixin",
"image": "https://avatars1.githubusercontent.com/u/2117018"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Filter Control",
"version": "2.1.0",
"description": "Plugin to add input/select element on the top of the columns in order to filter the data.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/filter-control",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/filter-control.html",
"plugins": [{
"name": "bootstrap-table-filter-control",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/filter-control"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,12 +0,0 @@
{
"name": "Group By V2",
"version": "1.0.0",
"description": "Group the data by field",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/group-by-v2",
"example": "",
"plugins": [],
"author": {
"name": "Knoxvillekm",
"image": "https://avatars3.githubusercontent.com/u/11072464"
}
}

View File

@@ -1,53 +0,0 @@
table.treetable tbody tr td {
cursor: default;
}
table.treetable span {
background-position: center left;
background-repeat: no-repeat;
padding: .2em 0 .2em 1.5em;
}
table.treetable tr.collapsed span.indenter a {
background-image: url(data:image/png;base64,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);
padding-right: 12px;
}
table.treetable tr.expanded span.indenter a {
background-image: url(data:image/png;base64,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);
padding-right: 12px;
}
table.treetable tr.branch {
background-color: #f9f9f9;
}
table.treetable tr.selected {
background-color: #3875d7;
color: #fff;
}
table.treetable tr span.indenter a {
outline: none; /* Expander shows outline after upgrading to 3.0 (#141) */
}
table.treetable tr.collapsed.selected span.indenter a {
background-image: url(data:image/png;base64,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);
}
table.treetable tr.expanded.selected span.indenter a {
background-image: url(data:image/png;base64,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);
}
table.treetable tr.accept {
background-color: #a3bce4;
color: #fff
}
table.treetable tr.collapsed.accept td span.indenter a {
background-image: url(data:image/x-png;base64,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);
}
table.treetable tr.expanded.accept td span.indenter a {
background-image: url(data:image/x-png;base64,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);
}

View File

@@ -1,243 +0,0 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.1.0
*/
!function ($) {
'use strict';
var originalRowAttr,
dataTTId = 'data-tt-id',
dataTTParentId = 'data-tt-parent-id',
obj = {},
parentId = undefined;
var getParentRowId = function (that, id) {
var parentRows = that.$body.find('tr').not('[' + 'data-tt-parent-id]');
for (var i = 0; i < parentRows.length; i++) {
if (i === id) {
return $(parentRows[i]).attr('data-tt-id');
}
}
return undefined;
};
var sumData = function (that, data) {
var sumRow = {};
$.each(data, function (i, row) {
if (!row.IsParent) {
for (var prop in row) {
if (!isNaN(parseFloat(row[prop]))) {
if (that.columns[that.fieldsColumnsIndex[prop]].groupBySumGroup) {
if (sumRow[prop] === undefined) {
sumRow[prop] = 0;
}
sumRow[prop] += +row[prop];
}
}
}
}
});
return sumRow;
};
var rowAttr = function (row, index) {
//Call the User Defined Function
originalRowAttr.apply([row, index]);
obj[dataTTId.toString()] = index;
if (!row.IsParent) {
obj[dataTTParentId.toString()] = parentId === undefined ? index : parentId;
} else {
parentId = index;
delete obj[dataTTParentId.toString()];
}
return obj;
};
var setObjectKeys = function () {
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Object.keys = function (o) {
if (o !== Object(o)) {
throw new TypeError('Object.keys called on a non-object');
}
var k = [],
p;
for (p in o) {
if (Object.prototype.hasOwnProperty.call(o, p)) {
k.push(p);
}
}
return k;
}
};
var getDataArrayFromItem = function (that, item) {
var itemDataArray = [];
for (var i = 0; i < that.options.groupByField.length; i++) {
itemDataArray.push(item[that.options.groupByField[i]]);
}
return itemDataArray;
};
var getNewRow = function (that, result, index) {
var newRow = {};
for (var i = 0; i < that.options.groupByField.length; i++) {
newRow[that.options.groupByField[i].toString()] = result[index][0][that.options.groupByField[i]];
}
newRow.IsParent = true;
return newRow;
};
var groupBy = function (array, f) {
var groups = {};
$.each(array, function (i, o) {
var group = JSON.stringify(f(o));
groups[group] = groups[group] || [];
groups[group].push(o);
});
return Object.keys(groups).map(function (group) {
return groups[group];
});
};
var makeGrouped = function (that, data) {
var newData = [],
sumRow = {};
var result = groupBy(data, function (item) {
return getDataArrayFromItem(that, item);
});
for (var i = 0; i < result.length; i++) {
result[i].unshift(getNewRow(that, result, i));
if (that.options.groupBySumGroup) {
sumRow = sumData(that, result[i]);
if (!$.isEmptyObject(sumRow)) {
result[i].push(sumRow);
}
}
}
newData = newData.concat.apply(newData, result);
if (!that.options.loaded && newData.length > 0) {
that.options.loaded = true;
that.options.originalData = that.options.data;
that.options.data = newData;
}
return newData;
};
$.extend($.fn.bootstrapTable.defaults, {
groupBy: false,
groupByField: [],
groupBySumGroup: false,
groupByInitExpanded: undefined, //node, 'all'
//internal variables
loaded: false,
originalData: undefined
});
$.fn.bootstrapTable.methods.push('collapseAll', 'expandAll', 'refreshGroupByField');
$.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
groupBySumGroup: false
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init,
_initData = BootstrapTable.prototype.initData;
BootstrapTable.prototype.init = function () {
//Temporal validation
if (!this.options.sortName) {
if ((this.options.groupBy) && (this.options.groupByField.length > 0)) {
var that = this;
// Compatibility: IE < 9 and old browsers
if (!Object.keys) {
$.fn.bootstrapTable.utils.objectKeys();
}
//Make sure that the internal variables are set correctly
this.options.loaded = false;
this.options.originalData = undefined;
originalRowAttr = this.options.rowAttributes;
this.options.rowAttributes = rowAttr;
this.$el.off('post-body.bs.table').on('post-body.bs.table', function () {
that.$el.treetable({
expandable: true,
onNodeExpand: function () {
if (that.options.height) {
that.resetHeader();
}
},
onNodeCollapse: function () {
if (that.options.height) {
that.resetHeader();
}
}
}, true);
if (that.options.groupByInitExpanded !== undefined) {
if (typeof that.options.groupByInitExpanded === 'number') {
that.expandNode(that.options.groupByInitExpanded);
} else if (that.options.groupByInitExpanded.toLowerCase() === 'all') {
that.expandAll();
}
}
});
}
}
_init.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.initData = function (data, type) {
//Temporal validation
if (!this.options.sortName) {
if ((this.options.groupBy) && (this.options.groupByField.length > 0)) {
this.options.groupByField = typeof this.options.groupByField === 'string' ?
this.options.groupByField.replace('[', '').replace(']', '')
.replace(/ /g, '').toLowerCase().split(',') : this.options.groupByField;
data = makeGrouped(this, data ? data : this.options.data);
}
}
_initData.apply(this, [data, type]);
};
BootstrapTable.prototype.expandAll = function () {
this.$el.treetable('expandAll');
};
BootstrapTable.prototype.collapseAll = function () {
this.$el.treetable('collapseAll');
};
BootstrapTable.prototype.expandNode = function (id) {
id = getParentRowId(this, id);
if (id !== undefined) {
this.$el.treetable('expandNode', id);
}
};
BootstrapTable.prototype.refreshGroupByField = function (groupByFields) {
if (!$.fn.bootstrapTable.utils.compareObjects(this.options.groupByField, groupByFields)) {
this.options.groupByField = groupByFields;
this.load(this.options.originalData);
}
};
}(jQuery);

View File

@@ -1,17 +0,0 @@
{
"name": "Group By",
"version": "1.1.0",
"description": "Plugin to group the data by fields.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/group-by",
"example": "#",
"plugins": [{
"name": "bootstrap-table-group-by",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/group-by"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "i18n Enhance",
"version": "1.0.0",
"description": "Plugin to add i18n API in order to change column's title and table locale.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/i18n-enhance",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/i18n-enhance.html",
"plugins": [{
"name": "bootstrap-table-i18n-enhance",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/i18n-enhance"
}],
"author": {
"name": "Jewway",
"image": "https://avatars0.githubusercontent.com/u/3501899"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Key Events",
"version": "1.0.0",
"description": "Plugin to support the key events in the bootstrap table.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/key-events",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/key-events.html",
"plugins": [{
"name": "bootstrap-table-key-events",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/key-events"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Mobile",
"version": "1.1.0",
"description": "Plugin to support the responsive feature.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/mobile",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/mobile.html",
"plugins": [{
"name": "bootstrap-table-mobile",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/mobile"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,88 +0,0 @@
/**
* @author Homer Glascock <HopGlascock@gmail.com>
* @version: v1.0.0
*/
!function ($) {
"use strict";
var sprintf = $.fn.bootstrapTable.utils.sprintf;
var reInit = function (self) {
self.initHeader();
self.initSearch();
self.initPagination();
self.initBody();
};
$.extend($.fn.bootstrapTable.defaults, {
showToggleBtn: false,
multiToggleDefaults: [], //column names go here
});
$.fn.bootstrapTable.methods.push('hideAllColumns', 'showAllColumns');
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initToolbar = BootstrapTable.prototype.initToolbar;
BootstrapTable.prototype.initToolbar = function () {
_initToolbar.apply(this, Array.prototype.slice.apply(arguments));
var that = this,
$btnGroup = this.$toolbar.find('>.btn-group');
if (typeof this.options.multiToggleDefaults === 'string') {
this.options.multiToggleDefaults = JSON.parse(this.options.multiToggleDefaults);
}
if (this.options.showToggleBtn && this.options.showColumns) {
var showbtn = "<button class='btn btn-default hidden' id='showAllBtn'><span class='glyphicon glyphicon-resize-full icon-zoom-in'></span></button>",
hidebtn = "<button class='btn btn-default' id='hideAllBtn'><span class='glyphicon glyphicon-resize-small icon-zoom-out'></span></button>";
$btnGroup.append(showbtn + hidebtn);
$btnGroup.find('#showAllBtn').click(function () { that.showAllColumns();
$btnGroup.find('#hideAllBtn').toggleClass('hidden');
$btnGroup.find('#showAllBtn').toggleClass('hidden');
});
$btnGroup.find('#hideAllBtn').click(function () { that.hideAllColumns();
$btnGroup.find('#hideAllBtn').toggleClass('hidden');
$btnGroup.find('#showAllBtn').toggleClass('hidden');
});
}
};
BootstrapTable.prototype.hideAllColumns = function () {
var that = this,
defaults = that.options.multiToggleDefaults;
$.each(this.columns, function (index, column) {
//if its one of the defaults dont touch it
if (defaults.indexOf(column.field) == -1 && column.switchable) {
column.visible = false;
var $items = that.$toolbar.find('.keep-open input').prop('disabled', false);
$items.filter(sprintf('[value="%s"]', index)).prop('checked', false);
}
});
reInit(that);
};
BootstrapTable.prototype.showAllColumns = function () {
var that = this;
$.each(this.columns, function (index, column) {
if (column.switchable) {
column.visible = true;
}
var $items = that.$toolbar.find('.keep-open input').prop('disabled', false);
$items.filter(sprintf('[value="%s"]', index)).prop('checked', true);
});
reInit(that);
that.toggleColumn(0, that.columns[0].visible, false);
};
}(jQuery);

View File

@@ -1,17 +0,0 @@
{
"name": "Multi Column Toggle",
"version": "1.0.0",
"description": "Allows hiding and showing of multiple columns at once.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multi-column-toggle",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/multi-column-toggle.html",
"plugins": [{
"name": "multi-column-toggle",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multi-column-toggle"
}],
"author": {
"name": "Homer Glascock",
"image": "https://avatars1.githubusercontent.com/u/5546710"
}
}

View File

@@ -1,71 +0,0 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.0.0
*/
!function ($) {
'use strict';
$.extend($.fn.bootstrapTable.defaults, {
multipleSearch: false,
delimeter: " "
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initSearch = BootstrapTable.prototype.initSearch;
BootstrapTable.prototype.initSearch = function () {
if (this.options.multipleSearch) {
if (this.searchText === undefined) {
return;
}
var strArray = this.searchText.split(this.options.delimeter),
that = this,
f = $.isEmptyObject(this.filterColumns) ? null : this.filterColumns,
dataFiltered = [];
if (strArray.length === 1) {
_initSearch.apply(this, Array.prototype.slice.apply(arguments));
} else {
for (var i = 0; i < strArray.length; i++) {
var str = strArray[i].trim();
dataFiltered = str ? $.grep(dataFiltered.length === 0 ? this.options.data : dataFiltered, function (item, i) {
for (var key in item) {
key = $.isNumeric(key) ? parseInt(key, 10) : key;
var value = item[key],
column = that.columns[that.fieldsColumnsIndex[key]],
j = $.inArray(key, that.header.fields);
// Fix #142: search use formated data
if (column && column.searchFormatter) {
value = $.fn.bootstrapTable.utils.calculateObjectValue(column,
that.header.formatters[j], [value, item, i], value);
}
var index = $.inArray(key, that.header.fields);
if (index !== -1 && that.header.searchables[index] && (typeof value === 'string' || typeof value === 'number')) {
if (that.options.strictSearch) {
if ((value + '').toLowerCase() === str) {
return true;
}
} else {
if ((value + '').toLowerCase().indexOf(str) !== -1) {
return true;
}
}
}
}
return false;
}) : this.data;
}
this.data = dataFiltered;
}
} else {
_initSearch.apply(this, Array.prototype.slice.apply(arguments));
}
};
}(jQuery);

View File

@@ -1,17 +0,0 @@
{
"name": "Multiple Search",
"version": "1.0.0",
"description": "Plugin to support the multiple search.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multiple-search",
"example": "#",
"plugins": [{
"name": "bootstrap-table-multiple-search",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multiple-search"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
.multiple-select-row-selected {
background: lightBlue
}
.table tbody tr:hover td,
.table tbody tr:hover th {
background-color: transparent;
}
.table-striped tbody tr:nth-child(odd):hover td {
background-color: #F9F9F9;
}
.fixed-table-container tbody .selected td {
background: lightBlue;
}

View File

@@ -1,127 +0,0 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.0.0
*/
!function ($) {
'use strict';
document.onselectstart = function() {
return false;
};
var getTableObjectFromCurrentTarget = function (currentTarget) {
currentTarget = $(currentTarget);
return currentTarget.is("table") ? currentTarget : currentTarget.parents().find(".table");
};
var getRow = function (target) {
target = $(target);
return target.parent().parent();
};
var onRowClick = function (e) {
var that = getTableObjectFromCurrentTarget(e.currentTarget);
if (window.event.ctrlKey) {
toggleRow(e.currentTarget, that, false, false);
}
if (window.event.button === 0) {
if (!window.event.ctrlKey && !window.event.shiftKey) {
clearAll(that);
toggleRow(e.currentTarget, that, false, false);
}
if (window.event.shiftKey) {
selectRowsBetweenIndexes([that.bootstrapTable("getOptions").multipleSelectRowLastSelectedRow.rowIndex, e.currentTarget.rowIndex], that)
}
}
};
var onCheckboxChange = function (e) {
var that = getTableObjectFromCurrentTarget(e.currentTarget);
clearAll(that);
toggleRow(getRow(e.currentTarget), that, false, false);
};
var toggleRow = function (row, that, clearAll, useShift) {
if (clearAll) {
row = $(row);
that.bootstrapTable("getOptions").multipleSelectRowLastSelectedRow = undefined;
row.removeClass(that.bootstrapTable("getOptions").multipleSelectRowCssClass);
that.bootstrapTable("uncheck", row.data("index"));
} else {
that.bootstrapTable("getOptions").multipleSelectRowLastSelectedRow = row;
row = $(row);
if (useShift) {
row.addClass(that.bootstrapTable("getOptions").multipleSelectRowCssClass);
that.bootstrapTable("check", row.data("index"));
} else {
if(row.hasClass(that.bootstrapTable("getOptions").multipleSelectRowCssClass)) {
row.removeClass(that.bootstrapTable("getOptions").multipleSelectRowCssClass)
that.bootstrapTable("uncheck", row.data("index"));
} else {
row.addClass(that.bootstrapTable("getOptions").multipleSelectRowCssClass);
that.bootstrapTable("check", row.data("index"));
}
}
}
};
var selectRowsBetweenIndexes = function (indexes, that) {
indexes.sort(function(a, b) {
return a - b;
});
for (var i = indexes[0]; i <= indexes[1]; i++) {
toggleRow(that.bootstrapTable("getOptions").multipleSelectRowRows[i-1], that, false, true);
}
};
var clearAll = function (that) {
for (var i = 0; i < that.bootstrapTable("getOptions").multipleSelectRowRows.length; i++) {
toggleRow(that.bootstrapTable("getOptions").multipleSelectRowRows[i], that, true, false);
}
};
$.extend($.fn.bootstrapTable.defaults, {
multipleSelectRow: false,
multipleSelectRowCssClass: 'multiple-select-row-selected',
//internal variables used by the extension
multipleSelectRowLastSelectedRow: undefined,
multipleSelectRowRows: []
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init,
_initBody = BootstrapTable.prototype.initBody;
BootstrapTable.prototype.init = function () {
if (this.options.multipleSelectRow) {
var that = this;
//Make sure that the internal variables have the correct value
this.options.multipleSelectRowLastSelectedRow = undefined;
this.options.multipleSelectRowRows = [];
this.$el.on("post-body.bs.table", function (e) {
setTimeout(function () {
that.options.multipleSelectRowRows = that.$body.children();
that.options.multipleSelectRowRows.click(onRowClick);
that.options.multipleSelectRowRows.find("input[type=checkbox]").change(onCheckboxChange);
}, 1);
});
}
_init.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.clearAllMultipleSelectionRow = function () {
clearAll(this);
};
$.fn.bootstrapTable.methods.push('clearAllMultipleSelectionRow');
}(jQuery);

View File

@@ -1,17 +0,0 @@
{
"name": "Multiple Selection Row",
"version": "1.0.0",
"description": "Plugin to enable the multiple selection row. You can use the ctrl+click to select one row or use ctrl+shift+click to select a range of rows.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multiple-selection-row",
"example": "",
"plugins": [{
"name": "bootstrap-table-multiple-selection-row",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multiple-selection-row"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Multiple Sort",
"version": "1.1.0",
"description": "Plugin to support the multiple sort.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multiple-sort",
"example": "#",
"plugins": [{
"name": "bootstrap-table-multiple-sort",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/multiple-sort"
}],
"author": {
"name": "dimbslmh",
"image": "https://avatars1.githubusercontent.com/u/745635"
}
}

View File

@@ -1,67 +0,0 @@
/**
* @author: Brian Huisman
* @webSite: http://www.greywyvern.com
* @version: v1.0.0
* JS functions to allow natural sorting on bootstrap-table columns
* add data-sorter="alphanum" or data-sorter="numericOnly" to any th
*
* @update Dennis Hernández <http://djhvscf.github.io/Blog>
* @update Duane May
*/
function alphanum(a, b) {
function chunkify(t) {
var tz = [],
x = 0,
y = -1,
n = 0,
i,
j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i === 46 || (i >= 48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
function stringfy(v) {
if (typeof(v) === "number") {
v = "" + v;
}
if (!v) {
v = "";
}
return v;
}
var aa = chunkify(stringfy(a));
var bb = chunkify(stringfy(b));
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]),
d = Number(bb[x]);
if (c == aa[x] && d == bb[x]) {
return c - d;
} else {
return (aa[x] > bb[x]) ? 1 : -1;
}
}
}
return aa.length - bb.length;
}
function numericOnly(a, b) {
function stripNonNumber(s) {
s = s.replace(new RegExp(/[^0-9]/g), "");
return parseInt(s, 10);
}
return stripNonNumber(a) - stripNonNumber(b);
}

View File

@@ -1,17 +0,0 @@
{
"name": "Natural Sorting",
"version": "1.0.0",
"description": "Plugin to support the natural sorting.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/natural-sorting",
"example": "#",
"plugins": [{
"name": "bootstrap-table-natural-sorting",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/natural-sorting"
}],
"author": {
"name": "GreyWyvern",
"image": "https://avatars1.githubusercontent.com/u/137631"
}
}

View File

@@ -1,21 +0,0 @@
(The MIT License)
Copyright (c) 2019 doug-the-guy <badlydrawnsun@yahoo.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,92 +0,0 @@
# Bootstrap Table Pipelining
Use Plugin: [bootstrap-table-pipeline]
This plugin enables client side data caching for server side requests which will
eliminate the need to issue a new request every page change. This will allow
for a performance balance for a large data set between returning all data at once
(client side paging) and a new server side request (server side paging).
There are two new options:
- usePipeline: enables this feature
- pipelineSize: the size of each cache window
The size of the pipeline must be evenly divisible by the current page size. This is
assured by rounding up to the nearest evenly divisible value. For example, if
the pipeline size is 4990 and the current page size is 25, then pipeline size will
be dynamically set to 5000.
The cache windows are computed based on the pipeline size and the total number of rows
returned by the server side query. For example, with pipeline size 500 and total rows
1300, the cache windows will be:
[{'lower': 0, 'upper': 499}, {'lower': 500, 'upper': 999}, {'lower': 1000, 'upper': 1499}]
Using the limit (i.e. the pipelineSize) and offset parameters, the server side request
**MUST** return only the data in the requested cache window **AND** the total number of rows.
To wit, the server side code must use the offset and limit parameters to prepare the response
data.
On a page change, the new offset is checked if it is within the current cache window. If so,
the requested page data is returned from the cached data set. Otherwise, a new server side
request will be issued for the new cache window.
The current cached data is only invalidated on these events:
- sorting
- searching
- page size change
- page change moves into a new cache window
There are two new events:
- cached-data-hit.bs.table: issued when cached data is used on a page change
- cached-data-reset.bs.table: issued when the cached data is invalidated and new server side request is issued
## Features
* Created with Bootstrap 4
## Usage
```
# assumed import of bootstrap and bootstrap-table assets
<script src="/path/to/bootstrap-table-pipeline.js"></script>
...
<table id="pipeline_table"
class="table table-striped"
data-method='post'
data-use-pipeline="true"
data-pipeline-size="5000"
data-pagination="true"
data-side-pagination="server"
data-page-size="50">
<thead><tr>
<th data-field="type" data-sortable="true">Type</th>
<th data-field="value" data-sortable="true">Value</th>
<th data-field="date" data-sortable="true">Date</th>
</tr></thead>
</table>
```
## Options
### usePipeline
* type: Boolean
* description: Set true to enable pipelining
* default: `false`
## pipelineSize
* type: Integer
* description: Size of each cache window. Must be greater than 0
* default: `1000`
## Events
### onCachedDataHit(cached-data-hit.bs.table)
* Fires when paging was able to use the locally cached data.
### onCachedDataReset(cached-data-reset.bs.table)
* Fires when the locally cached data needed to be reset (i.e. on sorting, searching, page size change or paged out of current cache window)

View File

@@ -1,18 +0,0 @@
{
"name": "Pipeline",
"version": "1.0.0",
"description": "Plugin to support a hybrid approach to server/client side paging.",
"url": "",
"example": "#",
"plugins": [{
"name": "bootstrap-table-pipeline",
"url": ""
}],
"author": {
"name": "doug-the-guy",
"image": ""
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Reorder Columns",
"version": "1.1.0",
"description": "Plugin to support the reordering columns feature.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/reorder-columns",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/reorder-columns.html",
"plugins": [{
"name": "bootstrap-table-reorder-columns",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/reorder-columns"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Reorder Rows",
"version": "1.0.0",
"description": "Plugin to support the reordering rows feature.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/reorder-rows",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/reorder-rows.html",
"plugins": [{
"name": "bootstrap-table-reorder-rows",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/reorder-rows"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Resizable",
"version": "1.1.0",
"description": "Plugin to support the resizable feature.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/resizable",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/resizable.html",
"plugins": [{
"name": "bootstrap-table-resizable",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/resizable"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1,332 +0,0 @@
/**
* @author: Jewway
* @version: v1.1.1
*/
! function ($) {
'use strict';
function getCurrentHeader(that) {
var header = that.$header;
if (that.options.height) {
header = that.$tableHeader;
}
return header;
}
function initFilterValues(that) {
if (!$.isEmptyObject(that.filterColumnsPartial)) {
var $header = getCurrentHeader(that);
$.each(that.columns, function (idx, column) {
var value = that.filterColumnsPartial[column.field];
if (column.filter) {
if (column.filter.setFilterValue) {
var $filter = $header.find('[data-field=' + column.field + '] .filter');
column.filter.setFilterValue($filter, column.field, value);
} else {
var $ele = $header.find('[data-filter-field=' + column.field + ']');
switch (column.filter.type) {
case 'input':
$ele.val(value);
case 'select':
$ele.val(value).trigger('change');
}
}
}
});
}
}
function createFilter(that, header) {
var enableFilter = false,
isVisible,
html,
timeoutId = 0;
$.each(that.columns, function (i, column) {
isVisible = 'hidden';
html = null;
if (!column.visible) {
return;
}
if (!column.filter) {
html = $('<div class="no-filter"></div>');
} else {
var filterClass = column.filter.class ? ' ' + column.filter.class : '';
html = $('<div style="margin: 0px 2px 2px 2px;" class="filter' + filterClass + '">');
if (column.searchable) {
enableFilter = true;
isVisible = 'visible'
}
if (column.filter.template) {
html.append(column.filter.template(that, column, isVisible));
} else {
var $filter = $(that.options.filterTemplate[column.filter.type.toLowerCase()](that, column, isVisible));
switch (column.filter.type) {
case 'input':
var cpLock = true;
$filter.off('compositionstart').on('compositionstart', function (event) {
cpLock = false;
});
$filter.off('compositionend').on('compositionend', function (event) {
cpLock = true;
var $input = $(this);
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
that.onColumnSearch(event, column.field, $input.val());
}, that.options.searchTimeOut);
});
$filter.off('keyup').on('keyup', function (event) {
if (cpLock) {
var $input = $(this);
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
that.onColumnSearch(event, column.field, $input.val());
}, that.options.searchTimeOut);
}
});
$filter.off('mouseup').on('mouseup', function (event) {
var $input = $(this),
oldValue = $input.val();
if (oldValue === "") {
return;
}
setTimeout(function () {
var newValue = $input.val();
if (newValue === "") {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
that.onColumnSearch(event, column.field, newValue);
}, that.options.searchTimeOut);
}
}, 1);
});
break;
case 'select':
$filter.on('select2:select', function (event) {
that.onColumnSearch(event, column.field, $(this).val());
});
$filter.on("select2:unselecting", function (event) {
var $select2 = $(this);
event.preventDefault();
$select2.val(null).trigger('change');
that.searchText = undefined;
that.onColumnSearch(event, column.field, $select2.val());
});
break;
}
html.append($filter);
}
}
$.each(header.children().children(), function (i, tr) {
tr = $(tr);
if (tr.data('field') === column.field) {
tr.find('.fht-cell').append(html);
return false;
}
});
});
if (!enableFilter) {
header.find('.filter').hide();
}
}
function initSelect2(that) {
var $header = getCurrentHeader(that);
$.each(that.columns, function (idx, column) {
if (column.filter && column.filter.type === 'select') {
var $selectEle = $header.find('select[data-filter-field="' + column.field + '"]');
if ($selectEle.length > 0 && !$selectEle.data().select2) {
var select2Opts = {
placeholder: "",
allowClear: true,
data: column.filter.data,
dropdownParent: that.$el.closest(".bootstrap-table")
};
$selectEle.select2(select2Opts);
}
}
});
}
$.extend($.fn.bootstrapTable.defaults, {
filter: false,
filterValues: {},
filterTemplate: {
input: function (instance, column, isVisible) {
return '<input type="text" class="form-control" data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '">';
},
select: function (instance, column, isVisible) {
return '<select data-filter-field="' + column.field + '" style="width: 100%; visibility:' + isVisible + '"></select>';
}
},
onColumnSearch: function (field, text) {
return false;
}
});
$.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
filter: undefined
});
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'column-search.bs.table': 'onColumnSearch'
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init,
_initHeader = BootstrapTable.prototype.initHeader,
_initSearch = BootstrapTable.prototype.initSearch;
BootstrapTable.prototype.init = function () {
//Make sure that the filtercontrol option is set
if (this.options.filter) {
var that = this;
if (that.options.filterTemplate) {
that.options.filterTemplate = $.extend({}, $.fn.bootstrapTable.defaults.filterTemplate, that.options.filterTemplate);
}
if (!$.isEmptyObject(that.options.filterValues)) {
that.filterColumnsPartial = that.options.filterValues;
that.options.filterValues = {};
}
this.$el.on('reset-view.bs.table', function () {
//Create controls on $tableHeader if the height is set
if (!that.options.height) {
return;
}
//Avoid recreate the controls
if (that.$tableHeader.find('select').length > 0 || that.$tableHeader.find('input').length > 0) {
return;
}
createFilter(that, that.$tableHeader);
}).on('post-header.bs.table', function () {
var timeoutId = 0;
initSelect2(that);
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
initFilterValues(that);
}, that.options.searchTimeOut - 1000);
}).on('column-switch.bs.table', function (field, checked) {
initFilterValues(that);
});
}
_init.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.initHeader = function () {
_initHeader.apply(this, Array.prototype.slice.apply(arguments));
if (this.options.filter) {
createFilter(this, this.$header);
}
};
BootstrapTable.prototype.initSearch = function () {
var that = this,
filterValues = that.filterColumnsPartial;
// Filter for client
if (that.options.sidePagination === 'client') {
this.data = $.grep(this.data, function (row, idx) {
for (var field in filterValues) {
var column = that.columns[that.fieldsColumnsIndex[field]],
filterValue = filterValues[field].toLowerCase(),
rowValue = row[field];
rowValue = $.fn.bootstrapTable.utils.calculateObjectValue(
that.header,
that.header.formatters[$.inArray(field, that.header.fields)], [rowValue, row, idx], rowValue);
if (column.filterStrictSearch) {
if (!($.inArray(field, that.header.fields) !== -1 &&
(typeof rowValue === 'string' || typeof rowValue === 'number') &&
rowValue.toString().toLowerCase() === filterValue.toString().toLowerCase())) {
return false;
}
} else {
if (!($.inArray(field, that.header.fields) !== -1 &&
(typeof rowValue === 'string' || typeof rowValue === 'number') &&
(rowValue + '').toLowerCase().indexOf(filterValue) !== -1)) {
return false;
}
}
}
return true;
});
}
_initSearch.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.onColumnSearch = function (event, field, value) {
if ($.isEmptyObject(this.filterColumnsPartial)) {
this.filterColumnsPartial = {};
}
if (value) {
this.filterColumnsPartial[field] = value;
} else {
delete this.filterColumnsPartial[field];
}
this.options.pageNumber = 1;
this.onSearch(event);
this.trigger('column-search', field, value);
};
BootstrapTable.prototype.setSelect2Data = function (field, data) {
var that = this,
$header = getCurrentHeader(that),
$selectEle = $header.find('select[data-filter-field=\"' + field + '\"]');
$selectEle.empty();
$selectEle.select2({
data: data,
placeholder: "",
allowClear: true,
dropdownParent: that.$el.closest(".bootstrap-table")
});
$.each(this.columns, function (idx, column) {
if (column.field === field) {
column.filter.data = data;
return false;
}
});
};
BootstrapTable.prototype.setFilterValues = function (values) {
this.filterColumnsPartial = values;
};
$.fn.bootstrapTable.methods.push('setSelect2Data');
$.fn.bootstrapTable.methods.push('setFilterValues');
}(jQuery);

View File

@@ -1,17 +0,0 @@
{
"name": "Select2 Filter",
"version": "1.1.0",
"description": "Plugin to add select2 filter on the top of the columns in order to filter the data.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/select2-filter",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/select2-filter.html",
"plugins": [{
"name": "bootstrap-table-select2-filter",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/select2-filter"
}],
"author": {
"name": "Jewway",
"image": "https://avatars0.githubusercontent.com/u/3501899"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Sticky Header",
"version": "1.0.0",
"description": "An extension which provides a sticky header for table columns when scrolling on a long page and / or table. Works for tables with many columns and narrow width with horizontal scrollbars too.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/sticky-header",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/sticky-header.html",
"plugins": [{
"name": "bootstrap-table-sticky-header",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/sticky-header"
}],
"author": {
"name": "vinzloh",
"image": "https://avatars0.githubusercontent.com/u/5501845"
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Toolbar",
"version": "2.0.0",
"description": "Plugin to support the advanced search.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/toolbar",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/toolbar.html",
"plugins": [{
"name": "bootstrap-table-toolbar",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/toolbar"
}],
"author": {
"name": "djhvscf",
"image": "https://avatars1.githubusercontent.com/u/4496763"
}
}

View File

@@ -1 +0,0 @@
.table:not(.table-condensed)>tbody>tr>td.treenode{padding-top:0;padding-bottom:0;border-bottom:solid #fff 1px}.table:not(.table-condensed)>tbody>tr:last-child>td.treenode{border-bottom:none}.treenode .text{float:left;display:block;padding-top:6px;padding-bottom:6px}.treenode .vertical,.treenode .vertical.last{float:left;display:block;width:1px;border-left:dashed silver 1px;height:38px;margin-left:8px}.treenode .vertical.last{height:15px}.treenode .space,.treenode .node{float:left;display:block;width:15px;height:5px;margin-top:15px}.treenode .node{border-top:dashed silver 1px}

View File

@@ -1,130 +0,0 @@
/**
* @author: KingYang
* @webSite: https://github.com/kingyang
* @version: v1.0.0
*/
! function ($) {
'use strict';
$.extend($.fn.bootstrapTable.defaults, {
treeShowField: null,
idField: 'id',
parentIdField: 'pid',
treeVerticalcls: 'vertical',
treeVerticalLastcls: 'vertical last',
treeSpacecls: 'space',
treeNodecls: 'node',
treeCellcls: 'treenode',
treeTextcls: 'text',
onTreeFormatter: function (row) {
var that = this,
options = that.options,
level = row._level || 0,
plevel = row._parent && row._parent._level || 0,
paddings = [];
for (var i = 0; i < plevel; i++) {
paddings.push('<i class="' + options.treeVerticalcls + '"></i>');
paddings.push('<i class="' + options.treeSpacecls + '"></i>');
}
for (var i = plevel; i < level; i++) {
if (row._last && i === (level - 1)) {
paddings.push('<i class="' + options.treeVerticalLastcls + '"></i>');
} else {
paddings.push('<i class="' + options.treeVerticalcls + '"></i>');
}
paddings.push('<i class="' + options.treeNodecls + '"></i>');
}
return paddings.join('');
}, onGetNodes: function (row, data) {
var that = this;
var nodes = [];
$.each(data, function (i, item) {
if (row[that.options.idField] === item[that.options.parentIdField]) {
nodes.push(item);
}
});
return nodes;
},
onCheckLeaf: function (row, data) {
if (row.isLeaf !== undefined) {
return row.isLeaf;
}
return !row._nodes || !row._nodes.length;
}, onCheckRoot: function (row, data) {
var that = this;
return !row[that.options.parentIdField];
}
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initRow = BootstrapTable.prototype.initRow,
_initHeader = BootstrapTable.prototype.initHeader;
BootstrapTable.prototype.initHeader = function () {
var that = this;
_initHeader.apply(that, Array.prototype.slice.apply(arguments));
var treeShowField = that.options.treeShowField;
if (treeShowField) {
$.each(this.header.fields, function (i, field) {
if (treeShowField === field) {
that.treeEnable = true;
var _formatter = that.header.formatters[i];
var _class = [that.options.treeCellcls];
if (that.header.classes[i]) {
_class.push(that.header.classes[i].split('"')[1] || '');
}
that.header.classes[i] = ' class="' + _class.join(' ') + '"';
that.header.formatters[i] = function (value, row, index) {
var colTree = [that.options.onTreeFormatter.apply(that, [row])];
colTree.push('<span class="' + that.options.treeTextcls + '">');
if (_formatter) {
colTree.push(_formatter.apply(this, Array.prototype.slice.apply(arguments)));
} else {
colTree.push(value);
}
colTree.push('</span>');
return colTree.join('');
};
return false;
}
});
}
};
var initNode = function (item, idx, data, parentDom) {
var that = this;
var nodes = that.options.onGetNodes.apply(that, [item, data]);
item._nodes = nodes;
parentDom.append(_initRow.apply(that, [item, idx, data, parentDom]));
var len = nodes.length - 1;
for (var i = 0; i <= len; i++) {
var node = nodes[i];
node._level = item._level + 1;
node._parent = item;
if (i === len)
node._last = 1;
initNode.apply(that, [node, $.inArray(node, data), data, parentDom]);
}
};
BootstrapTable.prototype.initRow = function (item, idx, data, parentDom) {
var that = this;
if (that.treeEnable) {
if (that.options.onCheckRoot.apply(that, [item, data])) {
if (item._level === undefined) {
item._level = 0;
}
initNode.apply(that, [item, idx, data, parentDom]);
return true;
}
return false;
}
return _initRow.apply(that, Array.prototype.slice.apply(arguments));
};
} (jQuery);

View File

@@ -1,43 +0,0 @@
.table:not(.table-condensed) > tbody > tr > td.treenode {
padding-top: 0;
padding-bottom: 0;
border-bottom: solid #fff 1px;
}
.table:not(.table-condensed) > tbody > tr:last-child > td.treenode {
border-bottom: none;
}
.treenode {
.text {
float: left;
display: block;
padding-top: 6px;
padding-bottom: 6px;
}
.vertical,
.vertical.last {
float: left;
display: block;
width: 1px;
border-left: dashed silver 1px;
height: 38px;
margin-left: 8px;
}
.vertical.last {
height: 15px;
}
.space,
.node {
float: left;
display: block;
width: 15px;
height: 5px;
margin-top: 15px;
}
.node {
border-top: dashed silver 1px;
}
}

View File

@@ -1,17 +0,0 @@
{
"name": "Tree column",
"version": "1.0.0",
"description": "Plugin to support display tree data column.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/tree-column",
"example": "http://issues.wenzhixin.net.cn/bootstrap-table/#extensions/tree-column.html",
"plugins": [{
"name": "bootstrap-table-reorder-rows",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/tree-column"
}],
"author": {
"name": "KingYang",
"image": "https://avatars3.githubusercontent.com/u/1540211"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

View File

@@ -1,17 +0,0 @@
{
"name": "treegrid",
"version": "1.0.0",
"description": "Plugin to support the jquery treegrid.",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/treegrid",
"example": "https://github.com/wenzhixin/bootstrap-table-examples/blob/master/extensions/treegrid.html",
"plugins": [{
"name": "bootstrap-table-treegrid",
"url": "https://github.com/wenzhixin/bootstrap-table/tree/master/src/extensions/treegrid"
}],
"author": {
"name": "foreveryang321",
"image": "https://avatars0.githubusercontent.com/u/5868190"
}
}

View File

@@ -0,0 +1,790 @@
/**
* @author Dustin Utecht
* https://github.com/wenzhixin/bootstrap-table/
*/
.bootstrap-table .fixed-table-toolbar::after {
content: "";
display: block;
clear: both;
}
.bootstrap-table .fixed-table-toolbar .bs-bars,
.bootstrap-table .fixed-table-toolbar .search,
.bootstrap-table .fixed-table-toolbar .columns {
position: relative;
margin-top: 10px;
margin-bottom: 10px;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group {
display: inline-block;
margin-left: -1px !important;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group > .btn {
border-radius: 0;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group:first-child > .btn {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group:last-child > .btn {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.bootstrap-table .fixed-table-toolbar .columns .dropdown-menu {
text-align: left;
max-height: 300px;
overflow: auto;
-ms-overflow-style: scrollbar;
z-index: 1001;
}
.bootstrap-table .fixed-table-toolbar .columns label {
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.428571429;
}
.bootstrap-table .fixed-table-toolbar .columns-left {
margin-right: 5px;
}
.bootstrap-table .fixed-table-toolbar .columns-right {
margin-left: 5px;
}
.bootstrap-table .fixed-table-toolbar .pull-right .dropdown-menu {
right: 0;
left: auto;
}
.bootstrap-table .fixed-table-container {
position: relative;
clear: both;
}
.bootstrap-table .fixed-table-container .table {
width: 100%;
margin-bottom: 0 !important;
}
.bootstrap-table .fixed-table-container .table th,
.bootstrap-table .fixed-table-container .table td {
vertical-align: middle;
box-sizing: border-box;
}
.bootstrap-table .fixed-table-container .table thead th {
vertical-align: bottom;
padding: 0;
margin: 0;
}
.bootstrap-table .fixed-table-container .table thead th:focus {
outline: 0 solid transparent;
}
.bootstrap-table .fixed-table-container .table thead th.detail {
width: 30px;
}
.bootstrap-table .fixed-table-container .table thead th .th-inner {
padding: 0.75rem;
vertical-align: bottom;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bootstrap-table .fixed-table-container .table thead th .sortable {
cursor: pointer;
background-position: right;
background-repeat: no-repeat;
padding-right: 30px !important;
}
.bootstrap-table .fixed-table-container .table thead th .both {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC");
}
.bootstrap-table .fixed-table-container .table thead th .asc {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==");
}
.bootstrap-table .fixed-table-container .table thead th .desc {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ");
}
.bootstrap-table .fixed-table-container .table tbody tr.selected td {
background-color: #fafafa;
}
.bootstrap-table .fixed-table-container .table tbody tr.no-records-found td {
text-align: center;
}
.bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: flex;
}
.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-title {
font-weight: bold;
display: inline-block;
min-width: 30%;
width: auto !important;
text-align: left !important;
}
.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-value {
width: 100% !important;
}
.bootstrap-table .fixed-table-container .table .bs-checkbox {
text-align: center;
}
.bootstrap-table .fixed-table-container .table .bs-checkbox label {
margin-bottom: 0;
}
.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type="radio"],
.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type="checkbox"] {
margin: 0 auto !important;
}
.bootstrap-table .fixed-table-container .table.table-sm .th-inner {
padding: 0.3rem;
}
.bootstrap-table .fixed-table-container.fixed-height:not(.has-footer) {
border-bottom: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height.has-card-view {
border-top: 1px solid #dbdbdb;
border-bottom: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height .fixed-table-border {
border-left: 1px solid #dbdbdb;
border-right: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height .table thead th {
border-bottom: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height .table-dark thead th {
border-bottom: 1px solid #32383e;
}
.bootstrap-table .fixed-table-container .fixed-table-header {
overflow: hidden;
}
.bootstrap-table .fixed-table-container .fixed-table-body {
overflow-x: auto;
overflow-y: auto;
height: 100%;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading {
align-items: center;
background: #fff;
display: flex;
justify-content: center;
position: absolute;
bottom: 0;
width: 100%;
z-index: 1000;
transition: visibility 0s, opacity 0.15s ease-in-out;
opacity: 0;
visibility: hidden;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.open {
visibility: visible;
opacity: 1;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap {
align-items: baseline;
display: flex;
justify-content: center;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .loading-text {
margin-right: 6px;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap {
align-items: center;
display: flex;
justify-content: center;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::before {
content: "";
animation-duration: 1.5s;
animation-iteration-count: infinite;
animation-name: LOADING;
background: #363636;
border-radius: 50%;
display: block;
height: 5px;
margin: 0 4px;
opacity: 0;
width: 5px;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot {
animation-delay: 0.3s;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after {
animation-delay: 0.6s;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark {
background: #363636;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-dot,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::after,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::before {
background: #fff;
}
.bootstrap-table .fixed-table-container .fixed-table-footer {
overflow: hidden;
}
.bootstrap-table .fixed-table-pagination::after {
content: "";
display: block;
clear: both;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail,
.bootstrap-table .fixed-table-pagination > .pagination {
margin-top: 10px;
margin-bottom: 10px;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .pagination-info {
line-height: 34px;
margin-right: 5px;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .page-list {
display: inline-block;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .page-list .btn-group {
position: relative;
display: inline-block;
vertical-align: middle;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .page-list .btn-group .dropdown-menu {
margin-bottom: 0;
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination {
margin: 0;
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.page-intermediate a {
color: #c8c8c8;
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.page-intermediate a::before {
content: '\2B05';
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.page-intermediate a::after {
content: '\27A1';
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.disabled a {
pointer-events: none;
cursor: default;
}
.bootstrap-table.fullscreen {
position: fixed;
top: 0;
left: 0;
z-index: 1050;
width: 100% !important;
background: #fff;
height: calc(100vh);
overflow-y: scroll;
}
.bootstrap-table.bootstrap4 .pagination-lg .page-link, .bootstrap-table.bootstrap5 .pagination-lg .page-link {
padding: .5rem 1rem;
}
.bootstrap-table.bootstrap5 .float-left {
float: left;
}
.bootstrap-table.bootstrap5 .float-right {
float: right;
}
/* calculate scrollbar width */
div.fixed-table-scroll-inner {
width: 100%;
height: 200px;
}
div.fixed-table-scroll-outer {
top: 0;
left: 0;
visibility: hidden;
width: 200px;
height: 150px;
overflow: hidden;
}
@keyframes LOADING {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
to {
opacity: 0;
}
}
@font-face {
font-family: 'bootstrap-table';
src: url("fonts/bootstrap-table.eot?gmdfsp");
src: url("fonts/bootstrap-table.eot") format("embedded-opentype"), url("fonts/bootstrap-table.ttf") format("truetype"), url("fonts/bootstrap-table.woff") format("woff"), url("fonts/bootstrap-table.svg") format("svg");
font-weight: normal;
font-style: normal;
font-display: block;
}
[class^="icon-"],
[class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'bootstrap-table', sans-serif !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-arrow-down-circle:before {
content: "\e907";
}
.icon-arrow-up-circle:before {
content: "\e908";
}
.icon-chevron-left:before {
content: "\e900";
}
.icon-chevron-right:before {
content: "\e901";
}
.icon-clock:before {
content: "\e90c";
}
.icon-copy:before {
content: "\e909";
}
.icon-download:before {
content: "\e90d";
}
.icon-list:before {
content: "\e902";
}
.icon-maximize:before {
content: "\1f5ce";
}
.icon-minus:before {
content: "\e90f";
}
.icon-move:before {
content: "\e903";
}
.icon-plus:before {
content: "\e90e";
}
.icon-printer:before {
content: "\e90b";
}
.icon-refresh-cw:before {
content: "\e904";
}
.icon-search:before {
content: "\e90a";
}
.icon-toggle-right:before {
content: "\e905";
}
.icon-trash-2:before {
content: "\e906";
}
.icon-sort-amount-asc:before {
content: "\ea4c";
}
.bootstrap-table * {
box-sizing: border-box;
}
.bootstrap-table input.form-control,
.bootstrap-table select.form-control,
.bootstrap-table .btn {
border-radius: 4px;
background-color: #fff;
border: 1px solid #ccc;
padding: 9px 12px;
}
.bootstrap-table select.form-control {
height: 35px;
}
.bootstrap-table .btn {
outline: none;
cursor: pointer;
}
.bootstrap-table .btn.active {
background-color: #ebebeb;
}
.bootstrap-table .btn:focus, .bootstrap-table .btn:hover {
background-color: whitesmoke;
}
.bootstrap-table .caret {
display: inline-block;
width: 0;
height: 0;
margin-left: 2px;
vertical-align: middle;
border-top: 4px dashed;
border-top: 4px solid;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
}
.bootstrap-table .detail-icon {
text-decoration: none;
color: #3679e4;
}
.bootstrap-table .detail-icon:hover {
color: #154a9f;
}
.bootstrap-table .fixed-table-toolbar .columns,
.bootstrap-table .fixed-table-toolbar .columns .btn-group {
display: inline-block;
}
.bootstrap-table .fixed-table-toolbar .columns > .btn:not(:first-child):not(:last-child),
.bootstrap-table .fixed-table-toolbar .columns > .btn:not(:first-child):not(:last-child) > .btn,
.bootstrap-table .fixed-table-toolbar .columns > .btn-group:not(:first-child):not(:last-child),
.bootstrap-table .fixed-table-toolbar .columns > .btn-group:not(:first-child):not(:last-child) > .btn {
border-radius: 0;
}
.bootstrap-table .fixed-table-toolbar .columns > .btn:not(:last-child):not(.dropdown-toggle),
.bootstrap-table .fixed-table-toolbar .columns > .btn:not(:last-child) > .btn,
.bootstrap-table .fixed-table-toolbar .columns > .btn-group:not(:last-child):not(.dropdown-toggle),
.bootstrap-table .fixed-table-toolbar .columns > .btn-group:not(:last-child) > .btn {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: none;
}
.bootstrap-table .fixed-table-toolbar .columns > .btn:not(:first-child):not(.dropdown-toggle),
.bootstrap-table .fixed-table-toolbar .columns > .btn:not(:first-child) > .btn,
.bootstrap-table .fixed-table-toolbar .columns > .btn-group:not(:first-child):not(.dropdown-toggle),
.bootstrap-table .fixed-table-toolbar .columns > .btn-group:not(:first-child) > .btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.bootstrap-table .fixed-table-toolbar .columns label {
padding: 5px 12px;
}
.bootstrap-table .fixed-table-toolbar .columns input[type="checkbox"] {
vertical-align: middle;
}
.bootstrap-table .fixed-table-toolbar .columns .dropdown-divider {
border-bottom: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-toolbar .search .input-group .search-input {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: none;
}
.bootstrap-table .fixed-table-toolbar .search .input-group button[name="search"],
.bootstrap-table .fixed-table-toolbar .search .input-group button[name="clearSearch"] {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.bootstrap-table .fixed-table-toolbar .search .input-group button[name="search"]:not(:last-child),
.bootstrap-table .fixed-table-toolbar .search .input-group button[name="clearSearch"]:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: none;
}
.bootstrap-table .open.dropdown-menu {
display: block;
}
.bootstrap-table .dropdown-menu-up .dropdown-menu {
top: auto;
bottom: 100%;
}
.bootstrap-table .dropdown-menu {
display: none;
background-color: #fff;
position: absolute;
right: 0;
min-width: 120px;
margin-top: 2px;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: 0 3px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.175);
}
.bootstrap-table .dropdown-menu .dropdown-item {
color: #363636;
text-decoration: none;
display: block;
padding: 5px 12px;
white-space: nowrap;
}
.bootstrap-table .dropdown-menu .dropdown-item:hover {
background-color: whitesmoke;
}
.bootstrap-table .dropdown-menu .dropdown-item.active {
background-color: #3679e4;
color: #fff;
}
.bootstrap-table .dropdown-menu .dropdown-item.active:hover {
background-color: #1b5fcc;
}
.bootstrap-table .columns-left .dropdown-menu {
left: 0;
right: auto;
}
.bootstrap-table .pagination-detail {
float: left;
}
.bootstrap-table .pagination-detail .dropdown-item {
min-width: 45px;
text-align: center;
}
.bootstrap-table table {
border-collapse: collapse;
}
.bootstrap-table table th {
text-align: inherit;
}
.bootstrap-table table.table-bordered thead tr th,
.bootstrap-table table.table-bordered tbody tr td {
border: 1px solid #dbdbdb;
}
.bootstrap-table table.table-bordered tbody tr td {
padding: 0.75rem;
}
.bootstrap-table table.table-hover tbody tr:hover {
background: #fafafa;
}
.bootstrap-table .float-left {
float: left;
}
.bootstrap-table .float-right {
float: right;
}
.bootstrap-table .pagination {
padding: 0;
align-items: center;
display: flex;
justify-content: center;
text-align: center;
list-style: none;
}
.bootstrap-table .pagination .page-item {
border: 1px solid #dbdbdb;
background-color: #fff;
border-radius: 4px;
margin: 2px;
padding: 5px 2px 5px 2px;
}
.bootstrap-table .pagination .page-item:hover {
background-color: whitesmoke;
}
.bootstrap-table .pagination .page-item .page-link {
padding: 6px 12px;
line-height: 1.428571429;
color: #363636;
text-decoration: none;
outline: none;
}
.bootstrap-table .pagination .page-item.active {
background-color: #3679e4;
border: 1px solid #206ae1;
}
.bootstrap-table .pagination .page-item.active .page-link {
color: #fff;
}
.bootstrap-table .pagination .page-item.active:hover {
background-color: #1b5fcc;
}
.bootstrap-table .pagination .btn-group {
display: inline-block;
}
.bootstrap-table .pagination .btn-group .btn:not(:first-child):not(:last-child),
.bootstrap-table .pagination .btn-group input:not(:first-child):not(:last-child) {
border-radius: 0;
}
.bootstrap-table .pagination .btn-group .btn:first-child:not(:last-child):not(.dropdown-toggle),
.bootstrap-table .pagination .btn-group input:first-child:not(:last-child):not(.dropdown-toggle) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.bootstrap-table .pagination .btn-group .btn:last-child:not(:first-child),
.bootstrap-table .pagination .btn-group input:last-child:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.bootstrap-table .pagination .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.bootstrap-table .filter-control {
display: flex;
}
.bootstrap-table .page-jump-to input,
.bootstrap-table .page-jump-to .btn {
padding: 8px 12px;
}
.modal {
position: fixed;
display: none;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.modal.show {
display: flex;
}
.modal .btn {
border-radius: 4px;
background-color: #fff;
border: 1px solid #ccc;
padding: 6px 12px;
outline: none;
cursor: pointer;
}
.modal .btn.active {
border-color: black;
}
.modal .modal-background {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 998;
background-color: rgba(10, 10, 10, 0.86);
}
.modal .modal-content {
position: relative;
width: 600px;
margin: 30px auto;
z-index: 999;
}
.modal .modal-content .box {
background-color: #fff;
border-radius: 6px;
display: block;
padding: 1.25rem;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="bootstrap-table" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="chevron-left" d="M670.165 200.832l-225.835 225.835 225.835 225.835c16.683 16.683 16.683 43.691 0 60.331s-43.691 16.683-60.331 0l-256-256c-16.683-16.683-16.683-43.691 0-60.331l256-256c16.683-16.683 43.691-16.683 60.331 0s16.683 43.691 0 60.331z" />
<glyph unicode="&#xe901;" glyph-name="chevron-right" d="M414.165 140.502l256 256c16.683 16.683 16.683 43.691 0 60.331l-256 256c-16.683 16.683-43.691 16.683-60.331 0s-16.683-43.691 0-60.331l225.835-225.835-225.835-225.835c-16.683-16.683-16.683-43.691 0-60.331s43.691-16.683 60.331 0z" />
<glyph unicode="&#xe902;" glyph-name="list" d="M341.333 640h554.667c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667h-554.667c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667zM341.333 384h554.667c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667h-554.667c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667zM341.333 128h554.667c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667h-554.667c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667zM170.667 682.667c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667 19.115-42.667 42.667-42.667 42.667 19.115 42.667 42.667zM170.667 426.667c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667 19.115-42.667 42.667-42.667 42.667 19.115 42.667 42.667zM170.667 170.667c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667 19.115-42.667 42.667-42.667 42.667 19.115 42.667 42.667z" />
<glyph unicode="&#xe903;" glyph-name="move" d="M469.333 750.336v-281.003h-281.003l55.168 55.168c16.683 16.683 16.683 43.691 0 60.331s-43.691 16.683-60.331 0l-128-128c-0.043-0.043-0.085-0.128-0.171-0.171-4.011-4.053-7.040-8.704-9.088-13.653-4.309-10.453-4.309-22.229 0-32.683 2.048-4.949 5.077-9.643 9.088-13.653 0.043-0.043 0.085-0.128 0.171-0.171l128-128c16.683-16.683 43.691-16.683 60.331 0s16.683 43.691 0 60.331l-55.168 55.168h281.003v-281.003l-55.168 55.168c-16.683 16.683-43.691 16.683-60.331 0s-16.683-43.691 0-60.331l128-128c4.096-4.096 8.832-7.168 13.867-9.259 5.12-2.091 10.539-3.2 15.957-3.243 5.675-0.043 11.349 1.024 16.64 3.243 5.035 2.091 9.771 5.163 13.867 9.259l128 128c16.683 16.683 16.683 43.691 0 60.331s-43.691 16.683-60.331 0l-55.168-55.168v281.003h281.003l-55.168-55.168c-16.683-16.683-16.683-43.691 0-60.331s43.691-16.683 60.331 0l128 128c4.096 4.096 7.168 8.832 9.259 13.867 2.091 5.12 3.2 10.539 3.243 15.957 0.043 5.675-1.024 11.349-3.243 16.64-2.091 5.035-5.163 9.771-9.259 13.867l-128 128c-16.683 16.683-43.691 16.683-60.331 0s-16.683-43.691 0-60.331l55.168-55.168h-281.003v281.003l55.168-55.168c16.683-16.683 43.691-16.683 60.331 0s16.683 43.691 0 60.331l-128 128c-0.043 0.043-0.128 0.085-0.171 0.171-4.053 4.011-8.704 7.040-13.653 9.088-10.453 4.309-22.229 4.309-32.683 0-4.949-2.048-9.643-5.077-13.653-9.088-0.043-0.043-0.128-0.085-0.171-0.171l-128-128c-16.683-16.683-16.683-43.691 0-60.331s43.691-16.683 60.331 0z" />
<glyph unicode="&#xe904;" glyph-name="refresh-cw" d="M189.995 540.416c15.445 43.648 38.827 82.133 67.883 114.432 30.208 33.579 66.645 60.587 106.88 79.744s84.096 30.549 129.237 32.939c43.392 2.304 88.021-3.755 131.669-19.2 50.603-17.92 94.123-46.421 127.275-80.213l120.704-113.451h-148.309c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667h256c0.171 0 0.299 0 0.469 0 5.845 0.043 11.435 1.323 16.469 3.499 5.205 2.261 9.856 5.504 13.739 9.515 0.555 0.597 1.152 1.195 1.664 1.835 3.072 3.541 5.547 7.637 7.296 12.032 1.749 4.352 2.773 9.045 2.944 13.952 0.085 0.64 0.085 1.237 0.085 1.835v256c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667v-157.397l-124.843 117.291c-42.325 43.093-96.896 78.635-159.701 100.864-54.4 19.243-110.208 26.837-164.608 23.979-56.491-2.987-111.317-17.195-161.493-41.131s-95.701-57.643-133.547-99.669c-36.437-40.491-65.664-88.619-84.907-143.061-7.851-22.229 3.755-46.592 25.984-54.443s46.592 3.755 54.443 25.984zM85.333 242.688l126.080-118.485c39.851-39.893 86.955-70.784 137.259-91.648 52.224-21.632 107.861-32.469 163.456-32.469s111.232 10.795 163.456 32.384c50.347 20.821 97.451 51.669 138.283 92.501 47.104 47.104 81.109 102.699 100.736 159.787 7.68 22.272-4.181 46.549-26.496 54.229s-46.549-4.181-54.229-26.496c-15.403-44.8-42.368-89.216-80.341-127.189-32.768-32.725-70.4-57.387-110.592-73.984-41.728-17.28-86.272-25.941-130.816-25.899s-89.045 8.704-130.773 25.984c-40.149 16.64-77.781 41.301-111.488 74.965l-119.467 112.299h148.267c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667h-256c-0.171 0-0.299 0-0.469 0-5.845-0.043-11.435-1.323-16.469-3.499-5.205-2.261-9.899-5.547-13.781-9.6-0.555-0.555-1.067-1.152-1.579-1.749-3.072-3.584-5.589-7.68-7.339-12.117-1.707-4.352-2.731-9.003-2.944-13.909-0.085-0.597-0.085-1.195-0.085-1.792v-256c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667z" />
<glyph unicode="&#xe905;" glyph-name="toggle-right" d="M341.333 768c-46.165 0-90.283-9.173-130.56-25.856-41.813-17.323-79.36-42.667-110.805-74.112s-56.789-69.035-74.112-110.805c-16.683-40.277-25.856-84.395-25.856-130.56s9.173-90.283 25.856-130.56c17.323-41.813 42.667-79.36 74.112-110.805s69.035-56.789 110.805-74.112c40.277-16.683 84.395-25.856 130.56-25.856h341.333c46.165 0 90.283 9.173 130.56 25.856 41.813 17.323 79.36 42.667 110.805 74.112s56.789 69.035 74.112 110.805c16.683 40.277 25.856 84.395 25.856 130.56s-9.173 90.283-25.856 130.56c-17.323 41.813-42.667 79.36-74.112 110.805s-69.035 56.789-110.805 74.112c-40.277 16.683-84.395 25.856-130.56 25.856zM341.333 682.667h341.333c34.773 0 67.797-6.912 97.877-19.371 31.275-12.971 59.477-31.957 83.115-55.595s42.667-51.84 55.595-83.115c12.501-30.123 19.413-63.147 19.413-97.92s-6.912-67.797-19.371-97.877c-12.971-31.275-31.957-59.477-55.595-83.115s-51.84-42.667-83.115-55.595c-30.123-12.501-63.147-19.413-97.92-19.413h-341.333c-34.773 0-67.797 6.912-97.877 19.371-31.275 12.971-59.477 31.957-83.115 55.595s-42.667 51.84-55.595 83.115c-12.501 30.123-19.413 63.147-19.413 97.92s6.912 67.797 19.371 97.877c12.971 31.275 31.957 59.477 55.595 83.115s51.84 42.667 83.115 55.595c30.123 12.501 63.147 19.413 97.92 19.413zM853.333 426.667c0 23.040-4.608 45.099-12.928 65.28-8.661 20.907-21.333 39.68-37.035 55.381s-34.475 28.373-55.381 37.035c-20.224 8.363-42.283 12.971-65.323 12.971s-45.099-4.608-65.28-12.928c-20.907-8.661-39.68-21.333-55.381-37.035s-28.373-34.475-37.035-55.381c-8.363-20.224-12.971-42.283-12.971-65.323s4.608-45.099 12.928-65.28c8.661-20.907 21.333-39.68 37.035-55.381s34.475-28.373 55.381-37.035c20.224-8.363 42.283-12.971 65.323-12.971s45.099 4.608 65.28 12.928c20.907 8.661 39.68 21.333 55.381 37.035s28.373 34.475 37.035 55.381c8.363 20.224 12.971 42.283 12.971 65.323zM768 426.667c0-11.648-2.304-22.613-6.443-32.64-4.309-10.411-10.667-19.797-18.56-27.733-7.893-7.893-17.323-14.251-27.733-18.56-9.984-4.096-20.949-6.4-32.597-6.4s-22.613 2.304-32.64 6.443c-10.411 4.309-19.797 10.667-27.733 18.56s-14.251 17.323-18.56 27.733c-4.096 9.984-6.4 20.949-6.4 32.597s2.304 22.613 6.443 32.64c4.309 10.411 10.667 19.797 18.56 27.733s17.323 14.251 27.733 18.56c9.984 4.096 20.949 6.4 32.597 6.4s22.613-2.304 32.64-6.443c10.411-4.309 19.797-10.667 27.733-18.56 7.893-7.893 14.251-17.323 18.56-27.733 4.096-9.984 6.4-20.949 6.4-32.597z" />
<glyph unicode="&#xe906;" glyph-name="trash-2" d="M768 640v-554.667c0-5.845-1.152-11.349-3.2-16.299-2.133-5.205-5.333-9.899-9.301-13.867s-8.661-7.125-13.867-9.301c-4.949-2.048-10.453-3.2-16.299-3.2h-426.667c-5.845 0-11.349 1.152-16.299 3.2-5.205 2.133-9.899 5.333-13.867 9.301s-7.125 8.661-9.301 13.867c-2.048 4.949-3.2 10.453-3.2 16.299v554.667zM725.333 725.334v42.667c0 17.28-3.456 33.835-9.728 48.981-6.485 15.701-16 29.781-27.776 41.557s-25.856 21.291-41.557 27.776c-15.104 6.229-31.659 9.685-48.939 9.685h-170.667c-17.28 0-33.835-3.456-48.981-9.728-15.659-6.485-29.739-16-41.515-27.776s-21.291-25.856-27.776-41.515c-6.272-15.147-9.728-31.701-9.728-48.981v-42.667h-170.667c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667h42.667v-554.667c0-17.28 3.456-33.835 9.728-48.981 6.485-15.701 16-29.781 27.776-41.557s25.856-21.291 41.557-27.776c15.104-6.229 31.659-9.685 48.939-9.685h426.667c17.28 0 33.835 3.456 48.981 9.728 15.701 6.485 29.781 16 41.557 27.776s21.291 25.856 27.776 41.557c6.229 15.104 9.685 31.659 9.685 48.939v554.667h42.667c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667zM384 725.334v42.667c0 5.845 1.152 11.349 3.2 16.299 2.133 5.205 5.333 9.899 9.301 13.867s8.661 7.125 13.867 9.301c4.949 2.048 10.453 3.2 16.299 3.2h170.667c5.845 0 11.349-1.152 16.299-3.2 5.205-2.133 9.899-5.333 13.867-9.301s7.125-8.661 9.301-13.867c2.048-4.949 3.2-10.453 3.2-16.299v-42.667zM384 469.334v-256c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667v256c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667zM554.667 469.334v-256c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667v256c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667z" />
<glyph unicode="&#xe907;" glyph-name="arrow-down-circle" d="M981.333 426.667c0 63.488-12.629 124.16-35.541 179.499-23.808 57.472-58.667 109.141-101.888 152.363s-94.891 78.123-152.363 101.888c-55.381 22.955-116.053 35.584-179.541 35.584s-124.16-12.629-179.499-35.541c-57.472-23.808-109.141-58.667-152.363-101.931s-78.123-94.891-101.931-152.363c-22.912-55.339-35.541-116.011-35.541-179.499s12.629-124.16 35.541-179.499c23.808-57.472 58.667-109.141 101.888-152.363s94.891-78.123 152.363-101.888c55.381-22.955 116.053-35.584 179.541-35.584s124.16 12.629 179.499 35.541c57.472 23.808 109.141 58.667 152.363 101.888s78.123 94.891 101.888 152.363c22.955 55.381 35.584 116.053 35.584 179.541zM896 426.667c0-52.096-10.368-101.675-29.056-146.859-19.456-46.976-47.957-89.259-83.413-124.672s-77.739-63.957-124.672-83.413c-45.184-18.688-94.763-29.056-146.859-29.056s-101.675 10.368-146.859 29.056c-46.976 19.456-89.259 47.957-124.672 83.413-35.456 35.456-63.957 77.739-83.413 124.672-18.688 45.184-29.056 94.763-29.056 146.859s10.368 101.675 29.056 146.859c19.456 46.976 47.957 89.259 83.413 124.672s77.739 63.957 124.672 83.413c45.184 18.688 94.763 29.056 146.859 29.056s101.675-10.368 146.859-29.056c46.976-19.456 89.259-47.957 124.672-83.413 35.456-35.456 63.957-77.739 83.413-124.672 18.688-45.184 29.056-94.763 29.056-146.859zM469.333 597.334v-238.336l-97.835 97.835c-16.683 16.683-43.691 16.683-60.331 0s-16.683-43.691 0-60.331l170.667-170.667c4.096-4.096 8.832-7.168 13.867-9.259 5.12-2.091 10.539-3.2 15.957-3.243 0.213 0 0.469 0 0.683 0 5.419 0.043 10.88 1.109 15.957 3.243 5.035 2.091 9.771 5.163 13.867 9.259l170.667 170.667c16.683 16.683 16.683 43.691 0 60.331s-43.691 16.683-60.331 0l-97.835-97.835v238.336c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667z" />
<glyph unicode="&#xe908;" glyph-name="arrow-up-circle" d="M981.333 426.667c0 63.488-12.629 124.16-35.541 179.499-23.808 57.472-58.667 109.141-101.888 152.363s-94.891 78.123-152.363 101.888c-55.381 22.955-116.053 35.584-179.541 35.584s-124.16-12.629-179.499-35.541c-57.472-23.808-109.141-58.667-152.363-101.931s-78.123-94.891-101.931-152.363c-22.912-55.339-35.541-116.011-35.541-179.499s12.629-124.16 35.541-179.499c23.808-57.472 58.667-109.141 101.888-152.363s94.891-78.123 152.363-101.888c55.381-22.955 116.053-35.584 179.541-35.584s124.16 12.629 179.499 35.541c57.472 23.808 109.141 58.667 152.363 101.888s78.123 94.891 101.888 152.363c22.955 55.381 35.584 116.053 35.584 179.541zM896 426.667c0-52.096-10.368-101.675-29.056-146.859-19.456-46.976-47.957-89.259-83.413-124.672s-77.739-63.957-124.672-83.413c-45.184-18.688-94.763-29.056-146.859-29.056s-101.675 10.368-146.859 29.056c-46.976 19.456-89.259 47.957-124.672 83.413-35.456 35.456-63.957 77.739-83.413 124.672-18.688 45.184-29.056 94.763-29.056 146.859s10.368 101.675 29.056 146.859c19.456 46.976 47.957 89.259 83.413 124.672s77.739 63.957 124.672 83.413c45.184 18.688 94.763 29.056 146.859 29.056s101.675-10.368 146.859-29.056c46.976-19.456 89.259-47.957 124.672-83.413 35.456-35.456 63.957-77.739 83.413-124.672 18.688-45.184 29.056-94.763 29.056-146.859zM554.667 256v238.336l97.835-97.835c16.683-16.683 43.691-16.683 60.331 0s16.683 43.691 0 60.331l-170.667 170.667c-0.085 0.085-0.128 0.128-0.213 0.213-4.053 3.968-8.661 6.997-13.611 9.045-10.453 4.309-22.229 4.309-32.683 0-4.949-2.048-9.557-5.077-13.611-9.045-0.085-0.085-0.128-0.128-0.213-0.213l-170.667-170.667c-16.683-16.683-16.683-43.691 0-60.331s43.691-16.683 60.331 0l97.835 97.835v-238.336c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667z" />
<glyph unicode="&#xe909;" glyph-name="copy" d="M469.333 597.334c-17.28 0-33.835-3.456-48.981-9.728-15.659-6.485-29.739-16-41.515-27.776s-21.291-25.856-27.776-41.515c-6.272-15.147-9.728-31.701-9.728-48.981v-384c0-17.28 3.456-33.835 9.728-48.981 6.485-15.701 16-29.781 27.776-41.557s25.856-21.291 41.557-27.776c15.104-6.229 31.659-9.685 48.939-9.685h384c17.28 0 33.835 3.456 48.981 9.728 15.701 6.485 29.781 16 41.557 27.776s21.291 25.856 27.776 41.557c6.229 15.104 9.685 31.659 9.685 48.939v384c0 17.28-3.456 33.835-9.728 48.981-6.485 15.701-16 29.781-27.776 41.557s-25.856 21.291-41.557 27.776c-15.104 6.229-31.659 9.685-48.939 9.685zM469.333 512h384c5.845 0 11.349-1.152 16.299-3.2 5.205-2.133 9.899-5.333 13.867-9.301s7.125-8.661 9.301-13.867c2.048-4.949 3.2-10.453 3.2-16.299v-384c0-5.845-1.152-11.349-3.2-16.299-2.133-5.205-5.333-9.899-9.301-13.867s-8.661-7.125-13.867-9.301c-4.949-2.048-10.453-3.2-16.299-3.2h-384c-5.845 0-11.349 1.152-16.299 3.2-5.205 2.133-9.899 5.333-13.867 9.301s-7.125 8.661-9.301 13.867c-2.048 4.949-3.2 10.453-3.2 16.299v384c0 5.845 1.152 11.349 3.2 16.299 2.133 5.205 5.333 9.899 9.301 13.867s8.661 7.125 13.867 9.301c4.949 2.048 10.453 3.2 16.299 3.2zM213.333 341.334h-42.667c-5.845 0-11.349 1.152-16.299 3.2-5.205 2.133-9.899 5.333-13.867 9.301s-7.125 8.661-9.301 13.867c-2.048 4.949-3.2 10.453-3.2 16.299v384c0 5.845 1.152 11.349 3.2 16.299 2.133 5.205 5.333 9.899 9.301 13.867s8.661 7.125 13.867 9.301c4.949 2.048 10.453 3.2 16.299 3.2h384c5.845 0 11.349-1.152 16.299-3.2 5.205-2.133 9.899-5.333 13.867-9.301s7.125-8.661 9.301-13.867c2.048-4.949 3.2-10.453 3.2-16.299v-42.667c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667v42.667c0 17.28-3.456 33.835-9.728 48.981-6.485 15.701-16 29.781-27.776 41.557s-25.856 21.291-41.557 27.776c-15.104 6.229-31.659 9.685-48.939 9.685h-384c-17.28 0-33.835-3.456-48.981-9.728-15.659-6.485-29.739-16-41.515-27.776s-21.291-25.856-27.776-41.515c-6.272-15.147-9.728-31.701-9.728-48.981v-384c0-17.28 3.456-33.835 9.728-48.981 6.485-15.701 16-29.781 27.776-41.557s25.856-21.291 41.557-27.776c15.104-6.229 31.659-9.685 48.939-9.685h42.667c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667z" />
<glyph unicode="&#xe90a;" glyph-name="search" d="M684.416 262.144c-1.451-1.109-2.859-2.347-4.224-3.712s-2.56-2.731-3.712-4.224c-26.752-25.771-58.24-46.549-93.013-60.971-35.072-14.507-73.6-22.571-114.133-22.571s-79.061 8.064-114.219 22.613c-36.523 15.104-69.419 37.291-96.981 64.896s-49.749 60.459-64.896 96.981c-14.507 35.115-22.571 73.643-22.571 114.176s8.064 79.061 22.613 114.219c15.104 36.48 37.291 69.419 64.853 96.981s60.501 49.749 96.981 64.853c35.157 14.549 73.685 22.613 114.219 22.613s79.061-8.064 114.219-22.613c36.523-15.104 69.419-37.291 96.981-64.896s49.749-60.459 64.896-96.981c14.507-35.115 22.571-73.643 22.571-114.176s-8.064-79.061-22.613-114.219c-14.421-34.773-35.2-66.261-60.971-93.013zM926.165 72.832l-156.8 156.8c22.4 27.989 40.96 59.179 54.869 92.843 18.773 45.312 29.099 94.933 29.099 146.859s-10.325 101.547-29.099 146.859c-19.456 47.019-48 89.301-83.371 124.672s-77.653 63.915-124.672 83.371c-45.312 18.773-94.933 29.099-146.859 29.099s-101.547-10.325-146.859-29.099c-47.019-19.456-89.301-48-124.672-83.371s-63.915-77.653-83.371-124.672c-18.773-45.312-29.099-94.933-29.099-146.859s10.325-101.547 29.099-146.859c19.456-47.019 48-89.301 83.371-124.672s77.653-63.915 124.672-83.371c45.312-18.773 94.933-29.099 146.859-29.099s101.547 10.325 146.859 29.099c33.621 13.952 64.853 32.512 92.843 54.869l156.8-156.8c16.683-16.683 43.691-16.683 60.331 0s16.683 43.691 0 60.331z" />
<glyph unicode="&#xe90b;" glyph-name="printer" d="M725.333 597.334h-426.667v213.333h426.667zM213.333 128v-128c0-23.552 19.115-42.667 42.667-42.667h512c23.552 0 42.667 19.115 42.667 42.667v128h42.667c17.28 0 33.835 3.456 48.981 9.728 15.701 6.485 29.781 16 41.557 27.776s21.291 25.856 27.776 41.557c6.229 15.104 9.685 31.659 9.685 48.939v213.333c0 17.28-3.456 33.835-9.728 48.981-6.485 15.701-16 29.781-27.776 41.557s-25.856 21.291-41.557 27.776c-15.104 6.229-31.659 9.685-48.939 9.685h-42.667v256c0 23.552-19.115 42.667-42.667 42.667h-512c-23.552 0-42.667-19.115-42.667-42.667v-256h-42.667c-17.28 0-33.835-3.456-48.981-9.728-15.659-6.485-29.739-16-41.515-27.776s-21.291-25.856-27.776-41.515c-6.272-15.147-9.728-31.701-9.728-48.981v-213.333c0-17.28 3.456-33.835 9.728-48.981 6.485-15.701 16-29.781 27.776-41.557s25.856-21.291 41.557-27.776c15.104-6.229 31.659-9.685 48.939-9.685zM256 384c-23.552 0-42.667-19.115-42.667-42.667v-128h-42.667c-5.845 0-11.349 1.152-16.299 3.2-5.205 2.133-9.899 5.333-13.867 9.301s-7.125 8.661-9.301 13.867c-2.048 4.949-3.2 10.453-3.2 16.299v213.333c0 5.845 1.152 11.349 3.2 16.299 2.133 5.205 5.333 9.899 9.301 13.867s8.661 7.125 13.867 9.301c4.949 2.048 10.453 3.2 16.299 3.2h682.667c5.845 0 11.349-1.152 16.299-3.2 5.205-2.133 9.899-5.333 13.867-9.301s7.125-8.661 9.301-13.867c2.048-4.949 3.2-10.453 3.2-16.299v-213.333c0-5.845-1.152-11.349-3.2-16.299-2.133-5.205-5.333-9.899-9.301-13.867s-8.661-7.125-13.867-9.301c-4.949-2.048-10.453-3.2-16.299-3.2h-42.667v128c0 23.552-19.115 42.667-42.667 42.667zM298.667 298.667h426.667v-256h-426.667z" />
<glyph unicode="&#xe90c;" glyph-name="clock" d="M981.333 426.667c0 63.488-12.629 124.16-35.541 179.499-23.808 57.472-58.667 109.141-101.888 152.363s-94.891 78.123-152.363 101.888c-55.381 22.955-116.053 35.584-179.541 35.584s-124.16-12.629-179.499-35.541c-57.472-23.808-109.141-58.667-152.363-101.931s-78.123-94.891-101.931-152.363c-22.912-55.339-35.541-116.011-35.541-179.499s12.629-124.16 35.541-179.499c23.808-57.472 58.667-109.141 101.888-152.363s94.891-78.123 152.363-101.888c55.381-22.955 116.053-35.584 179.541-35.584s124.16 12.629 179.499 35.541c57.472 23.808 109.141 58.667 152.363 101.888s78.123 94.891 101.888 152.363c22.955 55.381 35.584 116.053 35.584 179.541zM896 426.667c0-52.096-10.368-101.675-29.056-146.859-19.456-46.976-47.957-89.259-83.413-124.672s-77.739-63.957-124.672-83.413c-45.184-18.688-94.763-29.056-146.859-29.056s-101.675 10.368-146.859 29.056c-46.976 19.456-89.259 47.957-124.672 83.413-35.456 35.456-63.957 77.739-83.413 124.672-18.688 45.184-29.056 94.763-29.056 146.859s10.368 101.675 29.056 146.859c19.456 46.976 47.957 89.259 83.413 124.672s77.739 63.957 124.672 83.413c45.184 18.688 94.763 29.056 146.859 29.056s101.675-10.368 146.859-29.056c46.976-19.456 89.259-47.957 124.672-83.413 35.456-35.456 63.957-77.739 83.413-124.672 18.688-45.184 29.056-94.763 29.056-146.859zM469.333 682.667v-256c0-16.597 9.472-31.019 23.595-38.144l170.667-85.333c21.077-10.539 46.72-2.005 57.259 19.072s2.005 46.72-19.072 57.259l-147.115 73.515v229.632c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667z" />
<glyph unicode="&#xe90d;" glyph-name="download" d="M853.333 298.667v-170.667c0-5.845-1.152-11.349-3.2-16.299-2.133-5.205-5.333-9.899-9.301-13.867s-8.661-7.125-13.867-9.301c-4.949-2.048-10.453-3.2-16.299-3.2h-597.333c-5.845 0-11.349 1.152-16.299 3.2-5.205 2.133-9.899 5.333-13.867 9.301s-7.125 8.661-9.301 13.867c-2.048 4.949-3.2 10.453-3.2 16.299v170.667c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667v-170.667c0-17.28 3.456-33.835 9.728-48.981 6.485-15.701 16-29.781 27.776-41.557s25.856-21.291 41.557-27.776c15.104-6.229 31.659-9.685 48.939-9.685h597.333c17.28 0 33.835 3.456 48.981 9.728 15.701 6.485 29.781 16 41.557 27.776s21.291 25.856 27.776 41.557c6.229 15.104 9.685 31.659 9.685 48.939v170.667c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667zM554.667 401.664v409.003c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667v-409.003l-140.501 140.501c-16.683 16.683-43.691 16.683-60.331 0s-16.683-43.691 0-60.331l213.333-213.333c0.085-0.085 0.171-0.171 0.256-0.256 4.053-3.968 8.661-6.955 13.568-9.003 5.12-2.133 10.624-3.2 16.085-3.243 0.171 0 0.341 0 0.469 0 5.461 0.043 10.965 1.109 16.085 3.243 5.035 2.091 9.728 5.163 13.824 9.259l213.333 213.333c16.683 16.683 16.683 43.691 0 60.331s-43.691 16.683-60.331 0z" />
<glyph unicode="&#xe90e;" glyph-name="plus" d="M213.333 384h256v-256c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667v256h256c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667h-256v256c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667v-256h-256c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667z" />
<glyph unicode="&#xe90f;" glyph-name="minus" d="M213.333 384h597.333c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667h-597.333c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667z" />
<glyph unicode="&#xea4c;" glyph-name="sort-amount-asc" d="M320 192v768h-128v-768h-160l224-224 224 224h-160zM448 384h576v-128h-576v128zM448 576h448v-128h-448v128zM448 768h320v-128h-320v128zM448 960h192v-128h-192v128z" />
<glyph unicode="&#x1f5ce;" glyph-name="maximize" d="M341.333 853.334h-128c-17.28 0-33.835-3.456-48.981-9.728-15.659-6.485-29.739-16-41.515-27.776s-21.291-25.856-27.776-41.515c-6.272-15.147-9.728-31.701-9.728-48.981v-128c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667v128c0 5.845 1.152 11.349 3.2 16.299 2.133 5.205 5.333 9.899 9.301 13.867s8.661 7.125 13.867 9.301c4.949 2.048 10.453 3.2 16.299 3.2h128c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667zM938.667 597.334v128c0 17.28-3.456 33.835-9.728 48.981-6.485 15.701-16 29.781-27.776 41.557s-25.856 21.291-41.557 27.776c-15.104 6.229-31.659 9.685-48.939 9.685h-128c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667h128c5.845 0 11.349-1.152 16.299-3.2 5.205-2.133 9.899-5.333 13.867-9.301s7.125-8.661 9.301-13.867c2.048-4.949 3.2-10.453 3.2-16.299v-128c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667zM682.667-0h128c17.28 0 33.835 3.456 48.981 9.728 15.701 6.485 29.781 16 41.557 27.776s21.291 25.856 27.776 41.557c6.229 15.104 9.685 31.659 9.685 48.939v128c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667v-128c0-5.845-1.152-11.349-3.2-16.299-2.133-5.205-5.333-9.899-9.301-13.867s-8.661-7.125-13.867-9.301c-4.949-2.048-10.453-3.2-16.299-3.2h-128c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667zM85.333 256v-128c0-17.28 3.456-33.835 9.728-48.981 6.485-15.701 16-29.781 27.776-41.557s25.856-21.291 41.557-27.776c15.104-6.229 31.659-9.685 48.939-9.685h128c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667h-128c-5.845 0-11.349 1.152-16.299 3.2-5.205 2.133-9.899 5.333-13.867 9.301s-7.125 8.661-9.301 13.867c-2.048 4.949-3.2 10.453-3.2 16.299v128c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1,440 @@
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
* https://github.com/wenzhixin/bootstrap-table/
* theme: https://github.com/jgthms/bulma/
*/
.bootstrap-table .fixed-table-toolbar::after {
content: "";
display: block;
clear: both;
}
.bootstrap-table .fixed-table-toolbar .bs-bars,
.bootstrap-table .fixed-table-toolbar .search,
.bootstrap-table .fixed-table-toolbar .columns {
position: relative;
margin-top: 10px;
margin-bottom: 10px;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group {
display: inline-block;
margin-left: -1px !important;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group > .btn {
border-radius: 0;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group:first-child > .btn {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.bootstrap-table .fixed-table-toolbar .columns .btn-group > .btn-group:last-child > .btn {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.bootstrap-table .fixed-table-toolbar .columns .dropdown-menu {
text-align: left;
max-height: 300px;
overflow: auto;
-ms-overflow-style: scrollbar;
z-index: 1001;
}
.bootstrap-table .fixed-table-toolbar .columns label {
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.428571429;
}
.bootstrap-table .fixed-table-toolbar .columns-left {
margin-right: 5px;
}
.bootstrap-table .fixed-table-toolbar .columns-right {
margin-left: 5px;
}
.bootstrap-table .fixed-table-toolbar .pull-right .dropdown-menu {
right: 0;
left: auto;
}
.bootstrap-table .fixed-table-container {
position: relative;
clear: both;
}
.bootstrap-table .fixed-table-container .table {
width: 100%;
margin-bottom: 0 !important;
}
.bootstrap-table .fixed-table-container .table th,
.bootstrap-table .fixed-table-container .table td {
vertical-align: middle;
box-sizing: border-box;
}
.bootstrap-table .fixed-table-container .table thead th {
vertical-align: bottom;
padding: 0;
margin: 0;
}
.bootstrap-table .fixed-table-container .table thead th:focus {
outline: 0 solid transparent;
}
.bootstrap-table .fixed-table-container .table thead th.detail {
width: 30px;
}
.bootstrap-table .fixed-table-container .table thead th .th-inner {
padding: 0.75rem;
vertical-align: bottom;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bootstrap-table .fixed-table-container .table thead th .sortable {
cursor: pointer;
background-position: right;
background-repeat: no-repeat;
padding-right: 30px !important;
}
.bootstrap-table .fixed-table-container .table thead th .both {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC");
}
.bootstrap-table .fixed-table-container .table thead th .asc {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==");
}
.bootstrap-table .fixed-table-container .table thead th .desc {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ");
}
.bootstrap-table .fixed-table-container .table tbody tr.selected td {
background-color: #fafafa;
}
.bootstrap-table .fixed-table-container .table tbody tr.no-records-found td {
text-align: center;
}
.bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: flex;
}
.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-title {
font-weight: bold;
display: inline-block;
min-width: 30%;
width: auto !important;
text-align: left !important;
}
.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-value {
width: 100% !important;
}
.bootstrap-table .fixed-table-container .table .bs-checkbox {
text-align: center;
}
.bootstrap-table .fixed-table-container .table .bs-checkbox label {
margin-bottom: 0;
}
.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type="radio"],
.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type="checkbox"] {
margin: 0 auto !important;
}
.bootstrap-table .fixed-table-container .table.table-sm .th-inner {
padding: 0.3rem;
}
.bootstrap-table .fixed-table-container.fixed-height:not(.has-footer) {
border-bottom: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height.has-card-view {
border-top: 1px solid #dbdbdb;
border-bottom: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height .fixed-table-border {
border-left: 1px solid #dbdbdb;
border-right: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height .table thead th {
border-bottom: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-container.fixed-height .table-dark thead th {
border-bottom: 1px solid #32383e;
}
.bootstrap-table .fixed-table-container .fixed-table-header {
overflow: hidden;
}
.bootstrap-table .fixed-table-container .fixed-table-body {
overflow-x: auto;
overflow-y: auto;
height: 100%;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading {
align-items: center;
background: #fff;
display: flex;
justify-content: center;
position: absolute;
bottom: 0;
width: 100%;
z-index: 1000;
transition: visibility 0s, opacity 0.15s ease-in-out;
opacity: 0;
visibility: hidden;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.open {
visibility: visible;
opacity: 1;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap {
align-items: baseline;
display: flex;
justify-content: center;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .loading-text {
margin-right: 6px;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap {
align-items: center;
display: flex;
justify-content: center;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::before {
content: "";
animation-duration: 1.5s;
animation-iteration-count: infinite;
animation-name: LOADING;
background: #363636;
border-radius: 50%;
display: block;
height: 5px;
margin: 0 4px;
opacity: 0;
width: 5px;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot {
animation-delay: 0.3s;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after {
animation-delay: 0.6s;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark {
background: #363636;
}
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-dot,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::after,
.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::before {
background: #fff;
}
.bootstrap-table .fixed-table-container .fixed-table-footer {
overflow: hidden;
}
.bootstrap-table .fixed-table-pagination::after {
content: "";
display: block;
clear: both;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail,
.bootstrap-table .fixed-table-pagination > .pagination {
margin-top: 10px;
margin-bottom: 10px;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .pagination-info {
line-height: 34px;
margin-right: 5px;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .page-list {
display: inline-block;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .page-list .btn-group {
position: relative;
display: inline-block;
vertical-align: middle;
}
.bootstrap-table .fixed-table-pagination > .pagination-detail .page-list .btn-group .dropdown-menu {
margin-bottom: 0;
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination {
margin: 0;
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.page-intermediate a {
color: #c8c8c8;
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.page-intermediate a::before {
content: '\2B05';
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.page-intermediate a::after {
content: '\27A1';
}
.bootstrap-table .fixed-table-pagination > .pagination ul.pagination li.disabled a {
pointer-events: none;
cursor: default;
}
.bootstrap-table.fullscreen {
position: fixed;
top: 0;
left: 0;
z-index: 1050;
width: 100% !important;
background: #fff;
height: calc(100vh);
overflow-y: scroll;
}
.bootstrap-table.bootstrap4 .pagination-lg .page-link, .bootstrap-table.bootstrap5 .pagination-lg .page-link {
padding: .5rem 1rem;
}
.bootstrap-table.bootstrap5 .float-left {
float: left;
}
.bootstrap-table.bootstrap5 .float-right {
float: right;
}
/* calculate scrollbar width */
div.fixed-table-scroll-inner {
width: 100%;
height: 200px;
}
div.fixed-table-scroll-outer {
top: 0;
left: 0;
visibility: hidden;
width: 200px;
height: 150px;
overflow: hidden;
}
@keyframes LOADING {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
to {
opacity: 0;
}
}
.box {
background-color: #fff;
border-radius: 6px;
color: #4a4a4a;
display: block;
padding: 1.25rem;
}
.bootstrap-table .float-left {
float: left;
}
.bootstrap-table .float-right {
float: right;
}
.bootstrap-table .fixed-table-toolbar .search input {
width: auto;
}
.bootstrap-table .fixed-table-toolbar .columns {
margin-right: 0;
}
.bootstrap-table .fixed-table-toolbar .button.dropdown {
padding: 0;
border: 0;
}
.bootstrap-table .fixed-table-toolbar .button.dropdown .button {
margin: 0;
}
.bootstrap-table .fixed-table-toolbar .button.dropdown:not(:first-child) .button {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.bootstrap-table .fixed-table-toolbar .button.dropdown:last-child .button {
border-bottom-right-radius: 4px;
border-top-right-radius: 4px;
}
.bootstrap-table .fixed-table-toolbar .button.dropdown .dropdown-content {
box-shadow: none;
border: 1px solid #dbdbdb;
}
.bootstrap-table .fixed-table-toolbar .button.dropdown label.dropdown-item {
padding: 5px 20px;
}
.bootstrap-table .fixed-table-pagination .ui.dropdown {
vertical-align: middle;
}
.bootstrap-table .fixed-table-pagination .is-up .fa-angle-down:before {
content: "\f106";
}
.bootstrap-table .fixed-table-pagination .pagination-link.disabled {
background-color: #dbdbdb;
border-color: #dbdbdb;
box-shadow: none;
color: #7a7a7a;
opacity: .5;
cursor: not-allowed;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More