Compare commits

...

2037 Commits
0.1.1 ... 0.2.0

Author SHA1 Message Date
Oliver
7c9ad3f406 Update version.py 2021-04-11 15:39:16 +10:00
Oliver
4cf0339393 Update README.md 2021-04-11 15:38:52 +10:00
Oliver
a2ff3e3474 Merge pull request #1398 from SchrodingersGat/django-q
Django q
2021-04-11 15:38:20 +10:00
Oliver Walters
c2f85b0447 docker-compose tweaks 2021-04-11 15:25:32 +10:00
Oliver Walters
8f07efa4e3 Add dockerhub badge 2021-04-11 15:15:11 +10:00
Oliver Walters
b490c5d035 Add new docker workflow for publising docker images on release 2021-04-11 15:08:13 +10:00
Oliver Walters
f9449da576 Merge remote-tracking branch 'upstream/master' into django-q
# Conflicts:
#	InvenTree/InvenTree/version.py
2021-04-11 15:03:33 +10:00
Oliver
34e95ab70c Update version.py 2021-04-11 14:49:41 +10:00
Oliver Walters
5f9236d280 Updates to docker files 2021-04-11 14:46:40 +10:00
Oliver Walters
44fe5721e0 Disgusting hack for tasks.py 2021-04-11 14:05:55 +10:00
Oliver Walters
f6f3815f31 Include worker status in main API call 2021-04-11 13:58:59 +10:00
Oliver Walters
78bcbe271a Update supervisor conf file 2021-04-11 13:45:56 +10:00
Oliver Walters
2e8d3b6424 Fix for tasks.py (??) 2021-04-11 13:22:16 +10:00
Oliver Walters
c9021fe991 Simplify docker build workflow 2021-04-10 22:48:23 +10:00
Oliver Walters
0e1b647e7b Remove mariadb test (uses the same backend as mysql!) 2021-04-10 22:47:30 +10:00
Oliver Walters
b74d365529 Merge remote-tracking branch 'upstream/master' into django-q 2021-04-10 22:46:20 +10:00
Oliver Walters
3da5505b58 Fix build workflow 2021-04-10 22:44:37 +10:00
Oliver Walters
5a168abbfe Separated docker file into separate directory 2021-04-10 22:42:08 +10:00
Oliver Walters
8f626d305e Fix location of entrypoint scripts 2021-04-10 22:35:10 +10:00
Oliver Walters
5d9e273559 Adds nxinx service 2021-04-10 22:25:07 +10:00
Oliver Walters
91b6f98f95 Update directory structure to match docker config 2021-04-10 22:08:36 +10:00
Oliver Walters
2f1db486a0 Do not use python virtual environment inside container 2021-04-10 21:40:27 +10:00
Oliver Walters
823f84e46a Simplified volume management in docker-compose 2021-04-10 20:58:51 +10:00
Oliver Walters
178715ce61 Auto create config file in specified location if it does not exist 2021-04-10 20:57:56 +10:00
Oliver Walters
e787c853e5 Update logger context 2021-04-10 20:08:13 +10:00
Oliver Walters
5e54b0f5cf Auto-generate key file if it does not exist! 2021-04-10 19:01:02 +10:00
Oliver Walters
9086c8a3bf Simplify external directory structure
- All InvenTree data now in a single subdir
- Copy default config file (if it does not exist)
- Config file is accessible from outside world
- Update start_server and start_worker scripts
2021-04-10 17:36:19 +10:00
Oliver
e011faa9b7 Merge pull request #1450 from SchrodingersGat/company-description-optional
Company description is no longer a required field
2021-04-10 16:19:30 +10:00
Oliver Walters
e6bd91c9e2 Company description is no longer a required field 2021-04-10 15:29:44 +10:00
Oliver Walters
1372343bd5 Updates to docker-compose file
- Note: not ready yet!
2021-04-10 15:27:50 +10:00
Oliver Walters
8eb571bddf Update dockerfile 2021-04-10 15:08:10 +10:00
Oliver
c7e1ac5648 Merge pull request #1449 from eeintech/fix_stock_ops
Fixed transfer stock action in template
2021-04-10 09:19:43 +10:00
Oliver
6bf3cc9e01 Merge pull request #1446 from eeintech/bom_yaml_export
Replace normalize with integer wrapper for quantity field
2021-04-10 09:17:23 +10:00
eeintech
6bf4140e5a Fixed transfer stock action in template 2021-04-09 16:55:05 -04:00
eeintech
afddf12339 Changed int to float 2021-04-08 22:04:26 -04:00
Oliver
6a1bb0a806 Merge pull request #1445 from eeintech/simple_stock_table_view
Simplified stock table view in Part and SupplierPart detail pages
2021-04-09 11:58:33 +10:00
eeintech
97e1bc0a67 Added missing part_detail reference 2021-04-08 21:46:11 -04:00
eeintech
cbddda6640 Remove normalize import 2021-04-08 14:41:06 -04:00
eeintech
7491cda313 Replace normalize with integer wrapper for quantity field 2021-04-08 14:35:47 -04:00
eeintech
b5a5f5b409 Simplified stock table view in Part and SupplierPart detail pages 2021-04-08 13:42:35 -04:00
Oliver Walters
47a93bc4cb More environment variables for config.yaml 2021-04-08 21:01:52 +10:00
Oliver Walters
3381945e14 Add newline 2021-04-08 17:10:48 +10:00
Oliver Walters
3926276fd1 Greatly simplified "wait_for_db" command 2021-04-08 00:37:34 +10:00
Oliver Walters
71cac6e269 Simplify waiting for db 2021-04-08 00:09:51 +10:00
Oliver Walters
ed304f571a Better configuration of github repo 2021-04-08 00:05:37 +10:00
Oliver Walters
14aead038e Adds docker_compose file 2021-04-07 23:46:30 +10:00
Oliver Walters
d4d9263131 Add option to specify config file via environment variable 2021-04-07 23:46:03 +10:00
Oliver Walters
9c38d67b52 Merge remote-tracking branch 'upstream/master' into django-q
# Conflicts:
#	InvenTree/InvenTree/status.py
#	InvenTree/templates/about.html
2021-04-07 22:29:47 +10:00
Oliver Walters
4a3ca4638c Dockerfile updates 2021-04-07 22:27:55 +10:00
Oliver Walters
d91531720b Unit testing for task scheduling 2021-04-07 22:17:24 +10:00
Oliver
5e0e364b6c Merge pull request #1441 from SchrodingersGat/missing-git
Hide git information if there is an error
2021-04-07 22:09:38 +10:00
Oliver
da63ec5351 Merge pull request #1437 from matmair/translation_improv
Translation improvements
2021-04-07 20:57:47 +10:00
Oliver Walters
6412cf1c87 Hide git information if there is an error 2021-04-07 20:55:44 +10:00
Matthias
32eaf48c12 fixed styling 2021-04-06 18:33:57 +02:00
Matthias
530b90042a added german(de) translations 2021-04-04 22:51:16 +02:00
Matthias
2c053eae4c added translations 2021-04-04 22:49:47 +02:00
Matthias
ef64d1e61d added label to DatePickerFormField 2021-04-04 22:49:17 +02:00
Matthias
adcb211572 set language in the used js scripts 2021-04-04 22:48:36 +02:00
Matthias
efd14fca64 made translation lazy 2021-04-04 22:47:01 +02:00
Matthias
20c455384e added more translation-strings 2021-04-04 22:44:14 +02:00
Matthias
c68220a597 migrations for all the translated models, totally forgot that 2021-04-03 14:11:28 +02:00
Matthias
cd7724d490 added german(de) translations for the new stuff 2021-04-03 13:48:02 +02:00
Matthias
f67210b20f added translation files for changes 2021-04-03 04:11:40 +02:00
Matthias
1854da380b made filters.js dynamic for translation 2021-04-03 04:07:27 +02:00
Matthias
0547e1c03b added more translations in html / js 2021-04-03 04:05:59 +02:00
Matthias
446bc06c1b switched translation methode to lazy 2021-04-03 04:01:40 +02:00
Matthias
2de6fcbfa4 added missing translation fields #753 2021-04-03 03:59:09 +02:00
Matthias
698b946403 activated translations for settings 2021-04-02 23:03:24 +02:00
Oliver Walters
00c4519d28 Simplify dockerfile 2021-04-02 00:54:29 +11:00
Oliver Walters
2436b1f2c9 Entrypoint script - start.sh 2021-04-02 00:40:47 +11:00
Oliver Walters
8d3b9e2ca4 Updates to settings.py
- Create secret_key.txt if it does not exist
- Copy default settings file if it does not exist
2021-04-02 00:06:17 +11:00
Oliver Walters
be41be3981 Add "wait_for_db" management command 2021-04-02 00:03:56 +11:00
Oliver Walters
8e7e36089b Fix venv 2021-04-01 21:11:59 +11:00
Oliver Walters
47ba0599eb Reference environment variables in supervisor conf file 2021-04-01 20:44:27 +11:00
Oliver Walters
db858b3cfc Install packages inside venv 2021-04-01 20:44:13 +11:00
Oliver Walters
148600a9c4 Copy gunicorn.conf.py 2021-04-01 20:38:18 +11:00
Oliver Walters
839c29117d Dockerfile updates
- Pipe supervisor logs to stdout (so they are passed to the docker instance)
- Fix supervisor service
- Expose home dir and port as env vars
2021-04-01 20:30:51 +11:00
Oliver Walters
d446f8ddd1 Add supervisor conf file specific to docker 2021-04-01 20:14:31 +11:00
Oliver Walters
08a1a6cf43 Add configuration options for the Dockerfile 2021-04-01 20:14:17 +11:00
Oliver Walters
76ab38a06b Add docker info 2021-04-01 11:35:03 +11:00
Oliver Walters
38b9655ad9 Remove unused workflow 2021-04-01 08:43:58 +11:00
Oliver Walters
b9e81c3c0e Start supervisord
Ref: https://advancedweb.hu/supervisor-with-docker-lessons-learned/
2021-03-31 23:39:16 +11:00
Oliver Walters
b9f9b26ca5 Sudo not required, I guess? 2021-03-31 23:32:03 +11:00
Oliver Walters
7683cc1aaa APK not APT 2021-03-31 23:27:01 +11:00
Oliver Walters
ff6b127f1b Typo fixin' 2021-03-31 23:22:17 +11:00
Oliver Walters
8b227ce297 More required packages, I guess... 2021-03-31 23:20:32 +11:00
Oliver Walters
286cf9b102 gcc required 2021-03-31 23:12:27 +11:00
Oliver Walters
24d36e0b66 Getting there... 2021-03-31 23:09:24 +11:00
Oliver Walters
251ec7a02f Fix lib names 2021-03-31 23:06:54 +11:00
Oliver Walters
61f8b982ce lib name fix 2021-03-31 23:03:13 +11:00
Oliver Walters
1f881dd041 Run as root 2021-03-31 23:00:22 +11:00
Oliver Walters
42b400e619 typo fix 2021-03-31 22:58:32 +11:00
Oliver Walters
601aff8283 Install git 2021-03-31 22:55:44 +11:00
Oliver Walters
58bfc80f79 Alpine uses different commands 2021-03-31 22:54:17 +11:00
Oliver Walters
2746396d11 Fix tag name 2021-03-31 22:50:41 +11:00
Oliver Walters
6017cad6b3 So apparently I cannot spell... 2021-03-31 22:48:58 +11:00
Oliver Walters
1a7b6e2613 Fix 2021-03-31 22:47:41 +11:00
Oliver Walters
ab57fd3b76 Build docker image 2021-03-31 22:45:42 +11:00
Oliver Walters
c0a0ca4588 PEP fix 2021-03-31 22:35:48 +11:00
Oliver Walters
3f257279ee Specify directories for CI 2021-03-31 22:31:50 +11:00
Oliver Walters
731ec25b24 Merge remote-tracking branch 'inventree/master' into django-q
# Conflicts:
#	.github/workflows/style.yaml
#	.travis.yml
#	InvenTree/InvenTree/settings.py
2021-03-31 22:17:38 +11:00
Oliver
53c9475e6d Update README.md 2021-03-31 22:11:01 +11:00
Oliver
9ccff64679 Update README.md 2021-03-31 22:10:12 +11:00
Oliver
de3395ed26 Update README.md 2021-03-31 22:09:39 +11:00
Oliver
16433f49c6 Merge pull request #1433 from SchrodingersGat/coverage-workflow
Add workflow for code coverage
2021-03-31 22:08:08 +11:00
Oliver Walters
73e032e1d0 Specify database name 2021-03-31 21:54:13 +11:00
Oliver Walters
82b6c48946 Specify database name 2021-03-31 21:48:54 +11:00
Oliver Walters
566c3af39e Environment variables take preference! 2021-03-31 21:40:19 +11:00
Oliver Walters
5d141e3568 Always print database config 2021-03-31 21:24:14 +11:00
Oliver Walters
83cd24961d INFO level debug 2021-03-31 21:18:17 +11:00
Oliver Walters
737a378515 Extra debug output for tests 2021-03-31 21:17:17 +11:00
Oliver Walters
f71ebc20ec Remove travis script 2021-03-31 21:07:16 +11:00
Oliver Walters
ac9753e72c Add data import/export step 2021-03-31 20:58:30 +11:00
Oliver Walters
dc94376f6d Fix workflows 2021-03-31 20:46:26 +11:00
Oliver Walters
c846e2e65a Use env variables rather than custom ci scripts 2021-03-31 20:39:22 +11:00
Oliver Walters
608f47837f Update README.md with badges 2021-03-31 20:26:47 +11:00
Oliver Walters
2f6ee330de Add CI check against MariaDB 2021-03-31 20:20:10 +11:00
Oliver Walters
c66dddc03f Force TCP for postgres 2021-03-31 20:14:57 +11:00
Oliver Walters
48cbd3be97 Remove (old) docs 2021-03-31 20:13:12 +11:00
Oliver Walters
6b99808c52 Run as root 2021-03-31 20:12:45 +11:00
Oliver Walters
61d14a0eda Database naming fix 2021-03-31 20:07:42 +11:00
Oliver Walters
5aea35f8fa Force TCP 2021-03-31 20:04:18 +11:00
Oliver Walters
3cc0530419 Root password 2021-03-31 20:01:02 +11:00
Oliver Walters
cef75aabc5 Update 2021-03-31 19:59:23 +11:00
Oliver Walters
09693d0d09 Start service 2021-03-31 19:54:37 +11:00
Oliver Walters
70703f8588 Try localhost 2021-03-31 19:48:20 +11:00
Oliver Walters
67a4c5a9a2 Try pointing to different host 2021-03-31 19:45:58 +11:00
Oliver Walters
db8d93e2e9 Create mysql database manually 2021-03-31 17:54:42 +11:00
Oliver Walters
af52f0eace Typo fix 2021-03-31 17:45:57 +11:00
Oliver Walters
631e41e22a Fix postgres workflow 2021-03-31 17:40:37 +11:00
Oliver Walters
f8d29b7b3b Typo 2021-03-31 17:36:33 +11:00
Oliver Walters
9e4218d02f Mysql fixes 2021-03-31 17:34:12 +11:00
Oliver Walters
d09483f30c Workflow fixes 2021-03-31 17:28:30 +11:00
Oliver Walters
d1a42f55a2 Fix flake issues 2021-03-31 17:20:12 +11:00
Oliver Walters
bdd5fa96e7 Add tests for mysql and postgresql 2021-03-31 17:18:04 +11:00
Oliver Walters
4f87c848a5 Ensure flake8 fails 2021-03-31 17:17:40 +11:00
Oliver Walters
d20c3bb733 GITHUB_TOKEN 2021-03-31 17:08:24 +11:00
Oliver Walters
ae72224ece Fix coveralls 2021-03-31 16:57:44 +11:00
Oliver Walters
fd43f8dc64 Merge remote-tracking branch 'inventree/master' into coverage-workflow
# Conflicts:
#	.github/workflows/style.yaml
2021-03-31 16:26:02 +11:00
Oliver Walters
6b32142725 run on pull request 2021-03-31 16:24:33 +11:00
Oliver Walters
01e6635032 Add workflow for code coverage 2021-03-31 13:06:22 +11:00
Oliver
88a021f165 Merge pull request #1432 from SchrodingersGat/style-checks
Update style worfdlow
2021-03-31 13:05:59 +11:00
Oliver Walters
b16f85de65 Update style worfdlow 2021-03-31 12:41:39 +11:00
Oliver
865436c42a Merge pull request #1431 from SchrodingersGat/workflows
Add code style workflow
2021-03-30 22:41:27 +11:00
Oliver Walters
db994fd908 Add code style workflow 2021-03-30 21:56:17 +11:00
Oliver Walters
83f8afe113 Add github actions 2021-03-30 21:33:49 +11:00
Oliver Walters
e7ed4c4eab Travis fixes 2021-03-30 21:24:06 +11:00
Oliver Walters
39b2c5f943 Reintroduce default database config 2021-03-30 21:18:09 +11:00
Oliver Walters
3ddbb6a6cd Check for empty values 2021-03-30 20:53:26 +11:00
Oliver
fd01e23245 Merge pull request #1430 from SchrodingersGat/missing-permission-fix
Emit warning rather than raise error
2021-03-30 10:28:54 +11:00
Oliver Walters
1a288168b7 PEP fixes 2021-03-30 10:00:43 +11:00
Oliver
f288b906ad Merge pull request #1426 from SchrodingersGat/assign-by-sn
Assign by sn
2021-03-30 09:29:49 +11:00
Oliver Walters
58c30f48d5 Remove extra whitespace 2021-03-30 09:28:02 +11:00
Oliver Walters
bfbdd72306 Remove unused import 2021-03-30 08:43:09 +11:00
Oliver Walters
0b78f3d931 Add unit testing for migrations 2021-03-30 08:42:44 +11:00
Oliver Walters
32cfe1b954 Emit warning rather than raise error
- All calling functions check for None anyway
2021-03-30 08:25:51 +11:00
Oliver
67f06d6e5d Merge pull request #1428 from inventree/dependabot/pip/pygments-2.7.4
Bump pygments from 2.2.0 to 2.7.4
2021-03-30 08:16:21 +11:00
Oliver Walters
408b9d5e5b Fix for unit testing 2021-03-30 08:08:55 +11:00
dependabot[bot]
49bb5634da Bump pygments from 2.2.0 to 2.7.4
Bumps [pygments](https://github.com/pygments/pygments) from 2.2.0 to 2.7.4.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.2.0...2.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-29 19:20:11 +00:00
Oliver Walters
709bfb1bd2 Remove "unique" constraint for part / order relationship 2021-03-30 00:14:47 +11:00
Oliver Walters
217097c9d3 Add custom form template 2021-03-30 00:10:28 +11:00
Oliver Walters
19059ea4cf Tweaks 2021-03-29 23:38:38 +11:00
Oliver Walters
d64dd68403 Agk, working out forms is hard 2021-03-29 23:32:41 +11:00
Oliver Walters
bd87f4c733 Adds form to assign stock item by serial numbers 2021-03-29 23:10:36 +11:00
Oliver
19c03e1472 Merge pull request #1424 from SchrodingersGat/notes-css
HTML / CSS fixes
2021-03-29 17:01:23 +11:00
Oliver Walters
cffe2ba84b Add a separate form for creating a sales order allocation 2021-03-29 16:44:01 +11:00
Oliver Walters
7a4b90649a HTML / CSS fixes 2021-03-29 16:36:27 +11:00
Oliver
88c1bc79d7 Merge pull request #1423 from matmair/translation-de
german translations
2021-03-29 09:12:45 +11:00
Matthias
a3ab70b05d finished german translation, small corrections 2021-03-28 18:09:35 +02:00
Matthias
c558a04162 updated translation reference 2021-03-28 18:08:07 +02:00
Oliver
1ffd3a0070 Merge pull request #1409 from eeintech/fix_stock_ops
Template fix for stock actions
2021-03-28 20:42:14 +11:00
Oliver
5a5e76e0a6 Merge pull request #1414 from inventree/dependabot/pip/djangorestframework-3.11.2
Bump djangorestframework from 3.10.3 to 3.11.2
2021-03-25 17:29:43 +11:00
Oliver Walters
3a0c68bf5c Add invoke task to start background worker 2021-03-24 22:42:04 +11:00
Oliver Walters
df0ab2359f Remove invoke tasks which perform system commands
- tasks.py is now for InvenTree specific tasks only
2021-03-24 22:24:47 +11:00
Oliver Walters
ce64feb79d Update supervisor conf file 2021-03-24 08:32:00 +11:00
Oliver Walters
e3f49b8996 Install invoke and gunicorn as part of requirements.txt 2021-03-24 08:31:53 +11:00
Oliver Walters
edbbfff1af Reduce frequency of heartbeat 2021-03-23 19:58:29 +11:00
Oliver Walters
8fd666e662 Improvements for "check for updates" task
- Let it throw an error if something fails
- Errors are caught as "unsuccessful tasks"
2021-03-22 11:20:09 +11:00
dependabot[bot]
f25c83226f Bump djangorestframework from 3.10.3 to 3.11.2
Bumps [djangorestframework](https://github.com/encode/django-rest-framework) from 3.10.3 to 3.11.2.
- [Release notes](https://github.com/encode/django-rest-framework/releases)
- [Commits](https://github.com/encode/django-rest-framework/compare/3.10.3...3.11.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-19 22:23:09 +00:00
Oliver Walters
b7718d9c6c Specify user and logfile 2021-03-19 22:08:11 +11:00
Oliver Walters
283663633a First pass at a supervisor.conf file 2021-03-19 21:52:36 +11:00
Oliver
c9464fd393 Merge pull request #1412 from SchrodingersGat/pillow-version
Bump pillow version
2021-03-19 11:25:10 +11:00
Oliver Walters
84aea1d587 Bump pillow version 2021-03-19 10:59:28 +11:00
Oliver
57289fe141 Merge pull request #1410 from SchrodingersGat/image-downloader
Image downloader
2021-03-18 11:10:07 +11:00
Oliver Walters
9c91ba4692 Add image download functionality for company 2021-03-18 09:20:24 +11:00
Oliver Walters
4e7243b999 Add modal image overlay for company 2021-03-17 23:55:21 +11:00
Oliver Walters
e3a5a56371 Add "modal image" display for part thumbnails 2021-03-17 23:44:47 +11:00
Oliver Walters
db47629867 Cleanup 2021-03-17 23:15:48 +11:00
Oliver Walters
8b310d8e47 Check length of response 2021-03-17 23:11:38 +11:00
Oliver Walters
be30933bfa Add custom form template 2021-03-17 23:06:56 +11:00
Oliver Walters
9a710ca28f Fix image download code 2021-03-17 23:02:32 +11:00
Oliver Walters
47a1143570 Catch error when generating company thumbnail images 2021-03-17 11:55:51 +11:00
Oliver Walters
5f19f534fc Catch error if invalid image is uploaded 2021-03-17 09:47:57 +11:00
Oliver
e2e870858d Merge pull request #1400 from eeintech/ipn_edit_setting
Add setting to disable IPN editing after part is created (web only)
2021-03-17 09:47:39 +11:00
Oliver Walters
15678f789c Add global setting to enable download of files / images from remote URL 2021-03-17 08:40:30 +11:00
Oliver Walters
45edb7e802 Add button 2021-03-17 08:28:38 +11:00
Oliver Walters
5b7d35e6f7 add View 2021-03-17 08:28:28 +11:00
Oliver Walters
3900f9b1b6 Add form for submitting image URL 2021-03-17 08:28:12 +11:00
eeintech
8619af9f09 Template fix for stock actions 2021-03-16 12:32:56 -04:00
eeintech
85474516a3 Merge branch 'master' of github.com:inventree/InvenTree into ipn_edit_setting 2021-03-16 10:23:27 -04:00
Oliver Walters
6946abae13 CSS fix for modal error info dialog 2021-03-16 16:42:33 +11:00
Oliver
5e48009241 Merge pull request #1407 from eeintech/bom_match_headers
Split required and part match headers for BOM import
2021-03-16 08:19:32 +11:00
eeintech
64a57128bc Return True for BOM valid flag if part does not have BOM items 2021-03-15 10:37:30 -04:00
eeintech
d39bd88440 Split required and part match headers for BOM import 2021-03-15 09:41:04 -04:00
eeintech
7b81a470b9 Merge branch 'master' of github.com:inventree/InvenTree into ipn_edit_setting 2021-03-15 08:50:31 -04:00
Oliver
247cbe0154 Merge pull request #1406 from SchrodingersGat/part-pricing-form-error
Add option to hide form error message
2021-03-15 21:01:19 +11:00
Oliver Walters
2de879d2ba Add option to hide form error message 2021-03-15 20:30:18 +11:00
Oliver
b17a50bd51 Merge pull request #1405 from SchrodingersGat/css-tweak
Small tweak for breadcrumb div css
2021-03-15 17:52:14 +11:00
Oliver Walters
9918860820 Small tweak for breadcrumb div css 2021-03-15 17:00:14 +11:00
Oliver Walters
c6e154f996 PEP style fixes 2021-03-15 10:15:48 +11:00
Oliver Walters
c1aed51de1 Fix import error 2021-03-15 09:34:32 +11:00
Oliver Walters
24823adc6d Adds unit tests for version number comparison 2021-03-15 08:51:50 +11:00
Oliver Walters
6ea846ce45 Add a #TODO 2021-03-15 08:36:27 +11:00
Oliver Walters
f6dd710d6e Automatically delete old heartbeat messages 2021-03-15 08:35:06 +11:00
Oliver Walters
de85d61451 Directly compare version tuples, rather than converting to primitive 2021-03-15 08:31:19 +11:00
Oliver
5ff18a0a3a Merge pull request #1403 from matmair/translations-de
unified translation scheme
2021-03-15 08:27:24 +11:00
Oliver
82faccc62f Merge pull request #1401 from eeintech/stock_filter_assembly
Stock filter for parts assemblies
2021-03-13 07:48:15 +11:00
Oliver
59e98bc22d Merge pull request #1402 from eeintech/fix_typo
Fixed build typo
2021-03-13 07:46:11 +11:00
eeintech
acb0b2c10a Fixed build typo 2021-03-12 11:46:56 -05:00
eeintech
429f9d0a13 Removed test print 2021-03-12 11:19:20 -05:00
eeintech
89c7c87f1e Add stock filter for parts assemblies 2021-03-12 11:18:19 -05:00
eeintech
b152f7041b Add setting to disable IPN editing after part is created (web only) 2021-03-12 10:30:31 -05:00
Oliver Walters
700effcee7 Remove celery reference 2021-03-12 16:57:27 +11:00
Oliver Walters
18b559fee7 Fix for unit test 2021-03-12 16:28:54 +11:00
Oliver Walters
9d404afec0 Add 'ignore' rules for the django-q tables 2021-03-12 16:00:25 +11:00
Oliver Walters
51616c8aca Merge remote-tracking branch 'upstream/master' into django-q 2021-03-12 15:47:03 +11:00
Oliver Walters
ef4dbda223 Catch errors if the DB is not up 2021-03-12 15:35:55 +11:00
Oliver Walters
006dd10a79 Delete successful tasks more than a month old 2021-03-12 15:35:33 +11:00
Oliver Walters
5b8eb1c530 Newline 2021-03-12 15:27:53 +11:00
Oliver Walters
bfb0cb3b47 Add a "heartbeat" task which runs every 5 minutes
- Allows us to track if the worker is running
- Due to Stat.get_all() not always working
2021-03-12 15:27:28 +11:00
Oliver
ed028aed62 Merge pull request #1397 from SchrodingersGat/order-report
Order report
2021-03-12 14:44:10 +11:00
Oliver Walters
c07f217416 Add "ignore" rules for new report models 2021-03-12 14:01:20 +11:00
Matthias
47c98db8a1 unified translation scheme 2021-03-11 12:44:28 +01:00
Oliver Walters
4925f24ca9 Add "up to date" info to the "about" window 2021-03-11 20:07:59 +11:00
Oliver Walters
18defcff16 Read version number from GitHub 2021-03-11 19:56:22 +11:00
Oliver Walters
3cf5aec289 Refactor 2021-03-11 19:21:28 +11:00
Oliver Walters
1532a0c3a1 Add InvenTree/apps.py 2021-03-11 17:18:57 +11:00
Oliver Walters
5949ccd74f Bug fix 2021-03-11 17:11:57 +11:00
Oliver Walters
f1ba20c3da Basic PO and SO reports 2021-03-11 15:01:25 +11:00
Oliver Walters
eb6310c774 Render company image to report 2021-03-11 15:01:15 +11:00
Oliver Walters
9d321f4833 Removed 2021-03-11 14:47:45 +11:00
Oliver Walters
e1ba0a9a99 Bug fix for tables 2021-03-11 14:24:28 +11:00
Oliver Walters
8e2a2c59bf Add more context data to reports 2021-03-11 14:19:25 +11:00
Oliver Walters
7ccd339b5c Print reports for multiple selected sales orders / purchase orders 2021-03-11 14:15:31 +11:00
Oliver Walters
fa95759a00 Enable printing for PO and SO 2021-03-11 14:09:57 +11:00
Oliver
23e19614a5 Merge pull request #1394 from mosenturm/translation_de
further translation de
2021-03-10 20:35:50 +11:00
Andreas Kaiser
3897166185 fix typo 2021-03-10 09:48:54 +01:00
Oliver Walters
7800664f4b Add printing endpoints 2021-03-10 18:29:22 +11:00
Oliver
448c3cc6f5 Merge pull request #1395 from SchrodingersGat/responsible-user
Responsible user
2021-03-10 18:27:46 +11:00
Oliver Walters
5a6a12604e Add detail endpoints 2021-03-10 17:13:19 +11:00
Oliver Walters
33e176e4e7 Add list view API endpoints 2021-03-10 17:09:37 +11:00
Oliver Walters
9b0595d232 Add serializers 2021-03-10 16:53:02 +11:00
Oliver Walters
7f05485954 Add new reports to the admin interface 2021-03-10 16:50:55 +11:00
Oliver Walters
727fd38978 Add new report models 2021-03-10 16:48:20 +11:00
Oliver Walters
d559d92f58 Display responsible owner for salesorder and purchaseorder 2021-03-10 16:26:20 +11:00
Oliver Walters
39d44ce32f Add "responsible" field to PO and SO models 2021-03-10 16:19:44 +11:00
Oliver Walters
5b68d82fa3 Skeleton for background tasks 2021-03-10 14:03:19 +11:00
Oliver Walters
660fed9196 Remove unused code from settings.py 2021-03-10 14:03:09 +11:00
Andreas Kaiser
6f63b43c1c Merge branch 'master' into translation_de 2021-03-09 11:14:07 +01:00
Andreas Kaiser
ca626ead6c german translation 2021-03-09 00:45:37 +01:00
Oliver
fb096bd65b Merge pull request #1393 from matmair/german-translations
updated german translations
2021-03-09 10:39:39 +11:00
Matthias
a00756ec3a added all obvious translations 2021-03-08 23:50:24 +01:00
Andreas Kaiser
af0c72d338 german translation 2021-03-08 17:45:22 +01:00
Andreas Kaiser
5ae5b9c0d4 german translation 2021-03-08 16:09:36 +01:00
Andreas Kaiser
48cd227f06 german translation, HTML tags refactored 2021-03-06 21:52:57 +01:00
Andreas Kaiser
ae3a0133eb Merge branch 'master' into translation_de 2021-03-06 13:50:39 +01:00
Oliver Walters
45b3c68930 New status info 2021-03-06 21:41:19 +11:00
Oliver Walters
7bec3ff5dd django-q 2021-03-06 20:58:57 +11:00
Oliver
9ea3193ffb Merge pull request #1391 from SchrodingersGat/order-parts-fix
Hacky fix for ordering parts form
2021-03-06 20:20:30 +11:00
Oliver Walters
8061669c70 Hacky fix for ordering parts form 2021-03-06 19:49:49 +11:00
Andreas Kaiser
ade1d36397 updated german translation, change tags bold italics 2021-03-05 01:03:08 +01:00
Oliver
a4257ad9df Update version.py 2021-03-04 22:52:40 +11:00
Oliver
15ca35ca94 Update version.py 2021-03-04 22:51:32 +11:00
Oliver
c46fe354c2 Merge pull request #1390 from SchrodingersGat/CI-fixes
Hide fields rather than pop, to reduce warnings in CI logs
2021-03-04 22:42:17 +11:00
Oliver Walters
d43cfccfc1 Typo fix 2021-03-04 22:11:38 +11:00
Oliver Walters
5ad915a845 More fields 2021-03-04 22:09:46 +11:00
Oliver Walters
d111e7bff0 Hide fields rather than pop, to reduce warnings in CI logs 2021-03-04 21:42:49 +11:00
Oliver
249860fa76 Merge pull request #1387 from SchrodingersGat/null-fix
Bug fix
2021-03-03 22:16:12 +11:00
Oliver Walters
a9e3e46b8a Bug fix
check if self.object.owner is None
2021-03-03 21:52:02 +11:00
Oliver
fb5d7c415b Merge pull request #1385 from SchrodingersGat/order-filtering
Order filtering
2021-03-03 09:27:40 +11:00
Oliver Walters
979f543c3f Add build orders to search results list 2021-03-03 08:44:13 +11:00
Oliver Walters
14000517ce Fixes for build order table 2021-03-03 08:39:14 +11:00
Oliver Walters
4a28fa7fa8 Fixes for company table 2021-03-03 08:36:16 +11:00
Oliver Walters
339a02a6b2 Bug fix for sorting of sales orders 2021-03-03 08:32:57 +11:00
Oliver Walters
558ea98fa1 Add purchase order and sales order to search results 2021-03-03 08:30:20 +11:00
Oliver Walters
0b15b77140 Fix server-side ordering for purchase order table 2021-03-03 08:13:55 +11:00
Oliver
a53aadd466 Merge pull request #1384 from mosenturm/translation_ak
updated german translation (de)
2021-03-03 08:02:40 +11:00
Andreas Kaiser
3a6f13f259 updated german translation (de) 2021-03-02 17:44:53 +01:00
Oliver
3d4cfcf1b6 Merge pull request #1381 from SchrodingersGat/table-name-fix
Fixes incorrect table name
2021-03-02 22:03:51 +11:00
Oliver Walters
e7e2abf3fc Remove debug prints 2021-03-02 21:34:26 +11:00
Oliver Walters
cd01bb0ad7 Refactor HTML view permission
- Introspect database model from View
- Automatically get the permission from the View class
2021-03-02 21:32:32 +11:00
Oliver Walters
753483e6c2 Use app label rather than table name for permission lookup
- For legacy reasons there are some tables that are not named according to their app_label
- Simply use the app_label instead
2021-03-02 19:34:56 +11:00
Oliver
7f6f489463 Merge pull request #1379 from SchrodingersGat/po-bug-fix
Pagination Bug Fix
2021-03-02 17:15:12 +11:00
Oliver
33f195533e Merge pull request #1380 from SchrodingersGat/label-base
Adds body styling to label base
2021-03-02 16:53:05 +11:00
Oliver Walters
42dfda6d07 Merge remote-tracking branch 'inventree/master' into po-bug-fix 2021-03-02 16:29:12 +11:00
Oliver Walters
7cb712f422 Merge remote-tracking branch 'inventree/master' into label-base
# Conflicts:
#	.travis.yml
2021-03-02 16:28:58 +11:00
Oliver
a2f849d663 Merge pull request #1382 from SchrodingersGat/linter-fix
Remove django-migration-linter which was causing strange errors
2021-03-02 16:28:10 +11:00
Oliver Walters
9478da2ad2 Remove django-migration-linter which was causing strange errors 2021-03-02 15:53:56 +11:00
Oliver Walters
f6e982ce81 Fixes incorrect table name 2021-03-02 15:34:45 +11:00
Oliver Walters
bc25e795dd Shorten git hash 2021-03-02 14:34:20 +11:00
Oliver Walters
2cf87c1c30 Adds body styling to label base 2021-03-02 14:05:52 +11:00
Oliver Walters
628e87cb28 search field fixes 2021-03-02 13:08:12 +11:00
Oliver Walters
6f4178acdb Improve server-side pagination for POLineItem 2021-03-02 12:38:37 +11:00
Oliver Walters
1c3b017283 Improve server-side pagination of SalesOrderLineItem 2021-03-02 12:33:41 +11:00
Oliver Walters
4ff1c690cc Bug fix for paginated tables 2021-03-02 12:33:01 +11:00
Oliver
7cf1715e2b Merge pull request #1374 from eeintech/dark-reader
Dark Reader color theme update
2021-03-02 10:45:56 +11:00
Oliver
197682635e Merge pull request #1377 from SchrodingersGat/nav-tree-fix
Fix incorrect javascript call
2021-03-02 10:45:31 +11:00
eeintech
a85ac6161e Removed binary SVG images from CSS 2021-03-01 16:19:16 -05:00
Oliver Walters
478dce449d Fix incorrect javascript call 2021-03-02 08:07:18 +11:00
eeintech
36c7528aeb Removed absolute static URLs 2021-03-01 11:00:42 -05:00
eeintech
374860c914 Updated Dark Reader color theme 2021-03-01 10:48:37 -05:00
Oliver
278466e830 Update README.md 2021-03-01 14:49:13 +11:00
Oliver
7aed696451 Merge pull request #1373 from SchrodingersGat/server-pagination
Server pagination
2021-03-01 13:31:50 +11:00
Oliver Walters
b7cf57c875 PEP fix 2021-03-01 11:38:52 +11:00
Oliver Walters
9f9629edb3 Fix for unit test 2021-03-01 11:21:18 +11:00
Oliver Walters
b157690ae0 Add API version to server info endpoint 2021-03-01 11:15:53 +11:00
Oliver Walters
34def10765 Delete un-needed code 2021-02-28 21:44:10 +11:00
Oliver Walters
04dbfbd892 Fix for stock item tracking table 2021-02-28 20:50:19 +11:00
Oliver Walters
3dad86f004 Actually just enable (optional) pagination for every list endpoint 2021-02-28 20:45:41 +11:00
Oliver Walters
44635d2499 Use server-side pagination for more list endpoints 2021-02-28 20:35:32 +11:00
Oliver Walters
90feb6d210 Server-side paginatino for build orders 2021-02-28 20:31:01 +11:00
Oliver Walters
1239d4af16 Fixes result limiting
- Required for index page
2021-02-28 20:16:05 +11:00
Oliver Walters
487794a938 Server side pagination for the part list 2021-02-28 16:29:25 +11:00
Oliver Walters
8ce7b572cc Optionally paginate the StockList table on the server
- This makes the bootstrap table interface SO FREAKING MUCH FASTER
- Search is now performed on the server too!
2021-02-28 16:18:45 +11:00
Oliver
45791c0257 Merge pull request #1372 from SchrodingersGat/sidenav-fix
Refactor side navigation tree
2021-02-28 13:29:50 +11:00
Oliver Walters
6f2ba71339 Refactor side navigation tree 2021-02-28 11:48:20 +11:00
Oliver
5cdae04c62 Merge pull request #1371 from SchrodingersGat/api-404
Adds "404" response when asking for an API endpoint that does not exist
2021-02-28 07:34:34 +11:00
Oliver Walters
19c76f7842 Include 404 URL in response 2021-02-27 22:44:38 +11:00
Oliver Walters
5069882a7f URL tweaks 2021-02-27 22:41:36 +11:00
Oliver Walters
0b9cb507c7 Redirect invalid API urls to a 404 page 2021-02-27 22:38:08 +11:00
Oliver
732388c7d3 Merge pull request #1370 from SchrodingersGat/stock-adjust-permissions
Fix API permissions for stock adjustment
2021-02-27 22:25:55 +11:00
Oliver Walters
f1c8c48d35 Fix API permissions for stock adjustment 2021-02-27 20:17:52 +11:00
Oliver
d5597a3dca Merge pull request #1363 from SchrodingersGat/api-permissions
Api permissions
2021-02-27 08:39:47 +11:00
Oliver
4b147e86ce Merge pull request #1368 from SchrodingersGat/hide-stock-buttons
Hide stock buttons on top-level stock location display
2021-02-27 08:39:25 +11:00
Oliver Walters
b6d87850dc Hide stock buttons on top-level stock location display 2021-02-27 08:00:00 +11:00
Oliver Walters
b315b958b0 PEP fixes 2021-02-27 07:56:38 +11:00
Oliver Walters
5a536be22d More test refactoring 2021-02-26 22:08:06 +11:00
Oliver Walters
d76b873c00 Refactor build API unit tests 2021-02-26 22:00:22 +11:00
Oliver Walters
9d099c81a7 Refactor API tests for stock 2021-02-26 21:53:54 +11:00
Oliver Walters
ee744be5fe Refactor API unit tests for part 2021-02-26 21:45:37 +11:00
Oliver Walters
6e3cb326fb Use better introspection, no longer required "role_required" 2021-02-26 21:36:40 +11:00
Oliver Walters
0f6cdd0037 Improve unit testing for new role endpoint 2021-02-26 21:04:09 +11:00
Oliver Walters
aad92902f2 Unit tests for new role view 2021-02-26 20:37:12 +11:00
Oliver Walters
2460965fef Add some more context data 2021-02-26 17:55:56 +11:00
Oliver Walters
5c61c18dc4 Add API endpoint which provides list of role permissions available to current user 2021-02-26 17:52:06 +11:00
Oliver Walters
cd5bc395f2 PEP fixes 2021-02-26 16:03:38 +11:00
Oliver Walters
20740035e8 Add role to API endpoints in 'part' app 2021-02-26 14:37:50 +11:00
Oliver Walters
81e9fd7a44 Escape hatch if role not required 2021-02-26 14:26:37 +11:00
Oliver Walters
0e971c468b Remove test code 2021-02-26 14:07:18 +11:00
Oliver Walters
36359fc547 RolePermission is now default for API endpoints 2021-02-26 14:05:26 +11:00
Oliver Walters
cd8c6fa81a Add RolePermission for API endpoints 2021-02-26 13:53:23 +11:00
Oliver Walters
1dfda5b0ed Fix display for top-level category 2021-02-26 13:03:03 +11:00
Oliver
414a981858 Merge pull request #1361 from SchrodingersGat/multi-bom-delete
Refactor multi-bom deletion
2021-02-26 11:15:51 +11:00
Oliver Walters
12c2ea3b37 Refactor multi-bom deletion 2021-02-26 10:54:54 +11:00
Oliver
44f5e0907e Merge pull request #1359 from SchrodingersGat/api-star
Simplify process for marking a part as "starred"
2021-02-25 23:51:45 +11:00
Oliver Walters
f2da1c990b Simplify process for marking a part as "starred" 2021-02-25 23:27:27 +11:00
Oliver
35b9b17167 Merge pull request #1354 from SchrodingersGat/tree-fix
Sidenav Fixes
2021-02-25 09:45:56 +11:00
Oliver Walters
bb03f2bd58 CSS fixes 2021-02-25 09:22:02 +11:00
Oliver Walters
26e80fa0ab Fancify all the menubars 2021-02-25 09:10:20 +11:00
Oliver Walters
fe42d5c54d Cleanup display for part 2021-02-24 21:58:40 +11:00
Oliver Walters
a451de3735 Update translations 2021-02-24 21:53:23 +11:00
Oliver Walters
ef84b98a89 Build view now uses menubar 2021-02-24 21:52:26 +11:00
Oliver Walters
48d2a395de Part Category now uses menubar display 2021-02-24 21:39:45 +11:00
Oliver Walters
a0eec930bb Cleanup 2021-02-24 21:30:55 +11:00
Oliver Walters
89bdfd1c62 StockItem display now uses menubar 2021-02-24 21:27:44 +11:00
Oliver Walters
888fd4116c SupplierPart display now uses menubar display style 2021-02-24 21:12:41 +11:00
Oliver Walters
5525b23b9f Company view now uses menubar 2021-02-24 20:31:48 +11:00
Oliver Walters
3210af31b4 Sales order now uses menubar 2021-02-24 20:17:25 +11:00
Oliver Walters
213851e8aa Purchase Order now uses menu bar 2021-02-24 20:01:05 +11:00
Oliver Walters
bedfaa582c Update "part" display to use new menubar 2021-02-24 17:58:43 +11:00
Oliver Walters
2a7b32d4f4 Part display tweaks 2021-02-24 16:37:32 +11:00
Oliver
3b03d45f1f Merge pull request #1355 from SchrodingersGat/search-fields
Allow searching part by revision field
2021-02-24 13:04:06 +11:00
Oliver Walters
546a1c91cc Allow searching part by revision field 2021-02-24 11:05:52 +11:00
Oliver Walters
a660578262 Move part menu to the left 2021-02-24 11:02:11 +11:00
Oliver Walters
15a59d54ca Abstract template context data for part 2021-02-24 09:05:31 +11:00
Oliver Walters
edb803bf67 Make part menu 'sticky' 2021-02-23 21:58:28 +11:00
Oliver Walters
2e87499fa5 Basic right-side menu for part 2021-02-23 21:51:41 +11:00
Oliver Walters
68f24e97ac Make tree sidenav resizable 2021-02-23 21:09:55 +11:00
Oliver Walters
0016628b41 Keep tree items constrained to a single line 2021-02-23 19:38:28 +11:00
Oliver
8cc904fe8a Merge pull request #1352 from SchrodingersGat/bug-fix
Bug fix for trackable parts
2021-02-23 18:01:56 +11:00
Oliver
2c85d630f7 Merge pull request #1353 from SchrodingersGat/regex-search-fix
Remove regex search functionality from part api
2021-02-23 18:01:48 +11:00
Oliver Walters
15275d24b4 Better CSS for side nav bars 2021-02-23 18:01:42 +11:00
Oliver Walters
a48be3bea9 Remove regex search functionality from part api 2021-02-23 16:57:17 +11:00
Oliver Walters
b64d48544d Bug fix for trackable parts 2021-02-23 16:49:09 +11:00
Oliver
ad7a70f033 Merge pull request #1351 from SchrodingersGat/report-filter-fix
Bug fix for label / report filtering
2021-02-23 16:02:29 +11:00
Oliver Walters
8c9202de21 Bug fix for label / report filtering 2021-02-23 15:40:31 +11:00
Oliver
94c8bb6805 Merge pull request #1350 from SchrodingersGat/recently-updated
Adds "Recently Updated Stock" to index page
2021-02-23 14:47:24 +11:00
Oliver Walters
648d322f54 Style fixes 2021-02-23 14:24:09 +11:00
Oliver Walters
8717be66fc Configure number of "recent items" shown on index page 2021-02-23 14:15:12 +11:00
Oliver Walters
8972a51bd6 Fixes for integer validator for inventree setting 2021-02-23 14:12:16 +11:00
Oliver
333d6dd1b8 Merge pull request #1348 from SchrodingersGat/supplier-part-admin
Adds "admin" button to supplier part page
2021-02-23 13:43:51 +11:00
Oliver
615e2f8271 Merge pull request #1349 from SchrodingersGat/used-in-filter
Enable filtering for "used in" table
2021-02-23 13:43:45 +11:00
Oliver Walters
571a03043e Show recently updated stock items on the index page 2021-02-23 13:43:41 +11:00
Oliver Walters
949a541ee0 Add more options to StockList api
- Limit query results
- Order by various fields
2021-02-23 13:43:26 +11:00
Oliver Walters
66e1b180e4 Add option to stock table to disable grouping at run-time 2021-02-23 13:42:59 +11:00
Oliver Walters
39d4ddd845 Enable filtering for "used in" table 2021-02-23 13:23:23 +11:00
Oliver Walters
5a58e0a298 Adds "admin" button to supplier part page 2021-02-23 13:16:03 +11:00
Oliver
791b14920a Merge pull request #1347 from SchrodingersGat/variant-stock-tab
Display stock tab for virtual parts
2021-02-23 12:23:01 +11:00
Oliver Walters
041f056116 Display stock tab for virtual parts 2021-02-23 10:40:52 +11:00
Oliver
4dc093662d Merge pull request #1344 from SchrodingersGat/sub-build-table
Build: Filter by parent or ancestor in API
2021-02-23 09:46:51 +11:00
Oliver Walters
832a6ef9a2 PEP fixes 2021-02-23 09:01:03 +11:00
Oliver Walters
58863b1924 Show child builds 2021-02-22 22:35:54 +11:00
Oliver Walters
c1dd5b1ca1 Add "child build" page 2021-02-22 22:21:46 +11:00
Oliver Walters
2186a66465 Build: Filter by parent or ancestor in API
- Add unit testing
2021-02-22 22:05:20 +11:00
Oliver
b8327a5531 Merge pull request #1342 from SchrodingersGat/label-improvements
Label improvements
2021-02-22 19:45:11 +11:00
Oliver
613776fbe5 Merge pull request #1343 from SchrodingersGat/part-annotate
Adds 'suppliers' field to Part serializer
2021-02-22 19:45:02 +11:00
Oliver Walters
199ba27031 PEP!!! 2021-02-22 18:44:59 +11:00
Oliver Walters
cf6a03456f Adds 'suppliers' field to Part serializer
- Number of supplier parts associated with the Part object
2021-02-22 18:44:31 +11:00
Oliver Walters
28e9aa4afa More unit fixes 2021-02-22 18:11:40 +11:00
Oliver Walters
9159afe9ce Unit test fix 2021-02-22 17:27:48 +11:00
Oliver
5d1e6981d8 Merge pull request #1341 from SchrodingersGat/variant-table-fix
Fixes weird variant display
2021-02-22 17:21:34 +11:00
Oliver Walters
7582b9ccf4 PEP fixes 2021-02-22 17:02:33 +11:00
Oliver Walters
9fe9cbc795 Fixes weird variant display
- Seems like the double import was at fault (somehow??)
2021-02-22 16:57:33 +11:00
Oliver Walters
7d54997cb8 Tweaks 2021-02-22 16:48:00 +11:00
Oliver Walters
bf51e1bfb1 Update label templates
- New ones are automatically copied across now
2021-02-22 16:39:38 +11:00
Oliver Walters
da715d7381 Refactoring label printing 2021-02-22 16:12:13 +11:00
Oliver Walters
caf4c293d9 Rename "barcode" module to "barcodes" to prevent import shadowing
- Add 'barcode' support
2021-02-22 15:15:25 +11:00
Oliver Walters
23da591c22 Remove old dependency on django_qr_code 2021-02-22 15:00:12 +11:00
Oliver Walters
828b3adc49 Update requirements.txt
- Remove blabel
- Remove django-qr-code
- Add python-barcode
- Add qrcode
2021-02-22 14:40:40 +11:00
Oliver Walters
a742df2c12 Adds 'length' and 'width' fields to label models 2021-02-22 10:10:58 +11:00
Oliver
ad6c69ecc7 Merge pull request #1336 from SchrodingersGat/app-info
Add app info to about dialog
2021-02-22 08:59:23 +11:00
Oliver Walters
89cdcda614 Add app info to about dialog 2021-02-22 01:10:11 +11:00
Oliver
beb155133a Update version.py 2021-02-21 21:50:52 +11:00
Oliver
2ac9eadd13 Update version.py 2021-02-21 21:49:38 +11:00
Oliver
d426e376c4 Merge pull request #1333 from SchrodingersGat/cleaner-homepage
Cleaner homepage
2021-02-21 21:36:28 +11:00
Oliver Walters
2b1101e165 remove unused files 2021-02-21 21:09:55 +11:00
Oliver Walters
afd7199a69 Cleanup search page too 2021-02-21 21:06:52 +11:00
Oliver Walters
745188082b Add more searchable fields to SupplierPart model 2021-02-21 21:06:44 +11:00
Oliver Walters
e53c6e9975 Fancy 2021-02-21 20:29:48 +11:00
Oliver
cc2b672117 Merge pull request #1335 from SchrodingersGat/stock-filter
Add option to filter out variants in stock table
2021-02-21 20:28:30 +11:00
Oliver Walters
d11adf3b34 fade in 2021-02-21 20:18:14 +11:00
Oliver Walters
dffff89e9d Add option to filter out variants in stock table 2021-02-21 20:08:23 +11:00
Oliver Walters
9d12d43574 Cleanup / refactor 2021-02-19 18:10:10 +11:00
Oliver Walters
116ea65160 Show / hide panels 2021-02-19 17:57:38 +11:00
Oliver Walters
6df6a460e4 Add items using javascript 2021-02-19 17:48:32 +11:00
Oliver
b95d6a4ab2 Merge pull request #1327 from SchrodingersGat/installed-test-results
Read test results from installed items
2021-02-19 16:49:51 +11:00
Oliver Walters
6037f1452a Unit testing for new feature 2021-02-19 15:50:32 +11:00
Oliver Walters
beeb94785d Add option for TestReport to include tests for installed items 2021-02-19 15:50:25 +11:00
Oliver
e02fb8c8fa Merge pull request #1332 from SchrodingersGat/destroyed-stock-adjust
Allow adjustment for destroyed (or lost) stock
2021-02-19 15:40:10 +11:00
Oliver Walters
ea4b713eed Allow adjustment for destroyed (or lost) stock 2021-02-19 15:13:56 +11:00
Oliver
ca16e4f35d Merge pull request #1330 from SchrodingersGat/supplier-part-packaging
Display supplier part packaging
2021-02-19 15:02:34 +11:00
Oliver Walters
ba71ce941f Display supplier part packaging 2021-02-19 14:34:21 +11:00
Oliver
5b549b8dea Merge pull request #1329 from SchrodingersGat/stock-packaging
Stock packaging
2021-02-19 12:52:38 +11:00
Oliver Walters
098b494047 Add option to disable stock item grouping 2021-02-19 11:31:38 +11:00
Oliver Walters
e8bacbe45f Edit packaging field 2021-02-19 11:11:22 +11:00
Oliver Walters
644583f636 Display packaging info in stock table 2021-02-19 11:09:24 +11:00
Oliver Walters
556d6455e8 Add "packaging" field for StockItem 2021-02-19 11:08:58 +11:00
Oliver Walters
a9f255be85 Prevent stock item being added as an installed item inside itself 2021-02-18 18:01:41 +11:00
Oliver Walters
ef23ab1abc Adds functionality for traversing "through" installed items to extract test results 2021-02-18 17:59:04 +11:00
Oliver
cdb3dd2aa5 Merge pull request #1325 from SchrodingersGat/build-bom-view
Adds "required parts" tab to build view
2021-02-18 17:58:20 +11:00
Oliver Walters
0c053c6339 Add action buttons to order or build stock 2021-02-18 17:25:39 +11:00
Oliver Walters
bfbcbe252b Adds "required parts" tab to build view 2021-02-18 17:14:57 +11:00
Oliver
8cb3d6ab0a Merge pull request #1321 from SchrodingersGat/next-build-order
Logic fix for "guessing" next build order number
2021-02-18 16:08:58 +11:00
Oliver Walters
43a7359501 Logic fix for "guessing" next build order number 2021-02-18 15:44:43 +11:00
Oliver
d2d842163d Merge pull request #1320 from SchrodingersGat/inherited-bom-used-in
Implement filtering which accommodates new inheritable BOM feature
2021-02-18 15:19:15 +11:00
Oliver Walters
0f60482e09 Add secondary dialog for creating new supplier 2021-02-18 14:59:13 +11:00
Oliver Walters
1b73f56937 modal content wrapper for secondary modal 2021-02-18 14:56:35 +11:00
Oliver Walters
e75b9d04fe PEP fix 2021-02-18 14:38:25 +11:00
Oliver Walters
7a51e6cf78 Implement filtering which accommodates new inheritable BOM feature
- Can no longer filter bom_items by sub_part
- Adds get_used_in_filter() and get_used_in() for part model (returns a query of other part objects)
2021-02-18 14:35:21 +11:00
Oliver
25ada20a19 Merge pull request #1315 from SchrodingersGat/copy-bom-fix
Fix for duplicating BOM
2021-02-18 08:22:05 +11:00
Oliver Walters
07ee27ad9b Another CSS tweak 2021-02-18 00:49:36 +11:00
Oliver Walters
3822b60bb0 CSS tweaks 2021-02-18 00:49:16 +11:00
Oliver Walters
abe1018abe Add new fields to BOM item hash 2021-02-18 00:40:30 +11:00
Oliver Walters
8caf6bad10 Fix for duplicating BOM
- Do not duplicate bom items which are "inherited"
2021-02-18 00:38:40 +11:00
Oliver
bf63005731 Merge pull request #1313 from SchrodingersGat/inherited-bom-items
Inherited bom items
2021-02-18 00:30:52 +11:00
Oliver Walters
3f30421ba9 bug fix 2021-02-17 23:57:45 +11:00
Oliver Walters
ef902fc313 Add bom_items to build order report context 2021-02-17 23:27:09 +11:00
Oliver Walters
bb3440a8a4 Refactor bom item filter
- Also updates a number of part functions to make use of inherited BOM items
2021-02-17 22:53:56 +11:00
Oliver Walters
1eb2456e3d Display inherited rows a bit differenter 2021-02-17 22:25:43 +11:00
Oliver Walters
5b402b6bc0 BOM table formatting
- Display link to external BOM
- Prevent item from being edited to selected
2021-02-17 22:18:32 +11:00
Oliver Walters
43eba3f7ec Add ability to include bom items inherited from parent parts in the API list 2021-02-17 22:05:17 +11:00
Oliver Walters
40d75090a7 Add 'inherited' flag to API 2021-02-17 21:53:26 +11:00
Oliver Walters
d692c18274 Add 'inherited' field to BomItem 2021-02-17 21:53:15 +11:00
Oliver
69708b842c Merge pull request #1309 from SchrodingersGat/order-requirement
Order requirement
2021-02-17 14:42:17 +11:00
Oliver Walters
afc33c59ea bug fix 2021-02-17 14:13:56 +11:00
Oliver Walters
08cc866e74 Add function to make barcode for build order 2021-02-17 13:47:14 +11:00
Oliver Walters
98bd7dfa9a Style fixes 2021-02-17 13:16:15 +11:00
Oliver Walters
fcc35f2260 Fix display of parts currently being built 2021-02-17 13:14:27 +11:00
Oliver Walters
ba542dcbdb Auto-fill build quantity 2021-02-17 13:06:18 +11:00
Oliver Walters
c8650ce34c Bug fix for tables 2021-02-17 13:05:58 +11:00
Oliver Walters
8780b8435a style fix 2021-02-17 12:46:05 +11:00
Oliver Walters
34df19242c Adds more context data 2021-02-17 11:08:11 +11:00
Oliver Walters
28c9c80f54 Calculate quantity required for sales orders
- Cache data going to part detail view
2021-02-17 10:57:17 +11:00
Oliver Walters
cda97829ab Add function for required build order quantity 2021-02-17 10:27:36 +11:00
Oliver
d2c9f759b1 Merge pull request #1305 from SchrodingersGat/incorrect-login-fix
Add message if username / password combo is rejected
2021-02-17 07:37:08 +11:00
Oliver Walters
baa352ca98 Add message if username / password combo is rejected 2021-02-16 22:34:24 +11:00
Oliver
a444f21e64 Merge pull request #1292 from SchrodingersGat/bom-report
BOM report
2021-02-16 21:32:28 +11:00
Oliver Walters
6b48f0db43 Unit test fixes 2021-02-16 20:56:18 +11:00
Oliver Walters
7071ef5a5c Fixes for build report template 2021-02-16 20:53:28 +11:00
Oliver Walters
7d30e75bc6 Display images in report debug mode 2021-02-16 20:40:09 +11:00
Oliver Walters
46f20593c5 Add default build order report
Toot toot refactor tractor
2021-02-16 20:39:07 +11:00
Oliver Walters
f87b15e4ea Refactoring 2021-02-16 20:14:13 +11:00
Oliver Walters
b09e9c0781 Fixes for URL generation 2021-02-16 17:16:36 +11:00
Oliver Walters
fdca3d842d Add report function for generating an internal link 2021-02-16 16:45:13 +11:00
Oliver Walters
81cac0927d Layout tweask 2021-02-16 16:04:24 +11:00
Oliver Walters
a416c56e5a pre-fill 'issued_by' user 2021-02-16 15:55:09 +11:00
Oliver Walters
a722057dab Display responsible and issuing users for build orders 2021-02-16 15:46:18 +11:00
Oliver Walters
31a8c94d2f Adds 'issued_by' and 'responsible' field to BuildOrder
- issued_by is a user
- responsible is a user or a group
2021-02-16 15:40:27 +11:00
Oliver Walters
6cc0880b4a Add INVENTREE_BASE_URL setting
- Also adds callable validator!
2021-02-16 15:31:04 +11:00
Oliver Walters
247c4bdb4b Print multiple build reports 2021-02-16 08:45:28 +11:00
Oliver Walters
b222119653 Add option to print build report 2021-02-16 08:36:04 +11:00
Oliver Walters
e72aaf2e07 PEP fixes 2021-02-16 08:25:52 +11:00
Oliver Walters
a349e77866 Adds model for BuildReport
- List / Detail / Print
2021-02-16 08:25:04 +11:00
Oliver
4431082440 Merge pull request #1294 from SchrodingersGat/login-static-files
Allow access to static files without being logged in
2021-02-13 19:48:27 +11:00
Oliver Walters
e0db833038 Rotated splash image for better handling of portrait view 2021-02-13 16:50:51 +11:00
Oliver Walters
39d9ecffec Add image attribution (need to work out how to make it more obvious) 2021-02-13 13:52:35 +11:00
Oliver Walters
99578e6986 Getting a little bit fancy 2021-02-13 13:49:21 +11:00
Oliver Walters
10e50cf5e4 Allow access to static files without being logged in 2021-02-13 12:19:10 +11:00
Oliver
998620b5f3 Merge pull request #1290 from SchrodingersGat/modal-css-fixes
Modal form CSS fixes
2021-02-12 21:32:46 +11:00
Oliver
16692a2905 Merge pull request #1288 from SchrodingersGat/part-table-fix
Remove code which was causing issue
2021-02-12 21:32:40 +11:00
Oliver
67b6123b70 Merge pull request #1289 from SchrodingersGat/null-units
Hide units when empty
2021-02-12 21:32:33 +11:00
Oliver Walters
e8fd336612 Fix getSubdir function 2021-02-12 21:32:26 +11:00
Oliver Walters
11099676ef Dialog for printing BOM reports 2021-02-12 21:23:56 +11:00
Oliver Walters
4e9b9ee6fd Detail and print view for the BOM report 2021-02-12 21:15:03 +11:00
Oliver Walters
9be2989971 Refactor printing code into ReportPrintMixin 2021-02-12 21:08:33 +11:00
Oliver Walters
a1cf893eb2 List API endpint for BOM reports 2021-02-12 20:55:13 +11:00
Oliver Walters
ba85ff63bf Refactor selectTestReport into selectReport 2021-02-12 20:38:30 +11:00
Oliver Walters
12821b80fb Add BOMReport model 2021-02-12 20:28:12 +11:00
Oliver Walters
19143ed082 Modal form CSS fixes 2021-02-12 20:13:17 +11:00
Oliver Walters
b22b82877d Hide units when empty 2021-02-12 20:01:09 +11:00
Oliver Walters
efc2290613 Remove code which was causing issue 2021-02-12 19:57:44 +11:00
Oliver
b43d6a2ad4 Merge pull request #1284 from eeintech/backup_restore
Added inv restore command
2021-02-11 09:25:49 +11:00
eeintech
d6eae83809 Added inv restore command 2021-02-10 10:55:04 -05:00
Oliver
89adac49f9 Merge pull request #1283 from SchrodingersGat/filter-validation
Wrap custom filter validation in try/except blocks
2021-02-10 21:20:03 +11:00
Oliver Walters
2fa7c8706b Wrap custom filter validation in try/except blocks 2021-02-10 20:40:15 +11:00
Oliver
9385447761 Merge pull request #1279 from SchrodingersGat/default-page-size
Default page size
2021-02-06 18:42:38 +11:00
Oliver Walters
a5c36e2ca8 Update scheme for inventree test report
- Copy across a simpler report which extends the "base" report
- This way the InvenTree report version is always up to date!
2021-02-06 18:07:27 +11:00
Oliver Walters
ef31727ec9 Would you like some PEPper with that? 2021-02-06 17:58:21 +11:00
Oliver Walters
30d95e1511 Add 'REPORT_DEBUG_MODE' setting
- If set, reports are printed in raw HTML
- Not pretty, but useful for debugging output of rendered template
2021-02-06 17:36:22 +11:00
Oliver Walters
dbaa0fc300 Add default page size for reports
- A4 / Legal / Letter
- Use this for the default page size for InvenTree reports
2021-02-06 17:11:20 +11:00
Oliver
2aa2f08658 Merge pull request #1275 from SchrodingersGat/report-revision
Report revision
2021-02-05 14:58:19 +11:00
Oliver Walters
b5e993872f Keep asset and snippet filenames the same (if possible) 2021-02-05 13:51:25 +11:00
Oliver Walters
d686fb5057 Fix typo in js file 2021-02-05 12:31:13 +11:00
Oliver Walters
f458342e5f Add report revision information to the template context 2021-02-05 12:02:16 +11:00
Oliver Walters
33d66182df Add "revision" number to report model
- Auto-increments whenever the model is saved
2021-02-05 12:01:44 +11:00
Oliver
af7a627230 Merge pull request #1271 from SchrodingersGat/migration-unit-test
Migration unit test
2021-02-04 23:56:12 +11:00
Oliver Walters
978ea7cc0b Typo fix 2021-02-04 23:11:19 +11:00
Oliver Walters
3c5169c793 So I learned something today...
In migration files you can access the "historical" pythonic model, and use that, with *all* the helpers,
rather than writing clunky old SQL!!!!

:'(
2021-02-04 23:10:10 +11:00
Oliver Walters
74704a7c1e Mark migrations with data operations "non atomic"
Ref: https://docs.djangoproject.com/en/dev/howto/writing-migrations/#non-atomic-migrations
2021-02-04 22:19:15 +11:00
Oliver
4d91a34136 Merge pull request #1270 from SchrodingersGat/report-templates
Adds "report snippet" class allowing re-usable report snippets
2021-02-04 22:14:38 +11:00
Oliver Walters
140c8b5395 Use integer field instead of boolean literal (not correct SQL) 2021-02-04 21:33:10 +11:00
Oliver Walters
62a7964dda PEP fixes 2021-02-04 21:17:20 +11:00
Oliver Walters
a0e7d37a19 Add setting for enabling / disabling test reports 2021-02-04 21:15:19 +11:00
Oliver Walters
5aec487c12 TestReport name no longer needs to be unique 2021-02-04 21:15:07 +11:00
Oliver Walters
bc36775270 Copy default test report across 2021-02-04 20:25:01 +11:00
Oliver Walters
98d291c2f8 Add model rule for ReportSnippet 2021-02-04 19:26:43 +11:00
Oliver Walters
59904ace1d Revoke support for LaTex reporting 2021-02-04 16:18:28 +11:00
Oliver Walters
264bd625d3 Remove debug string 2021-02-04 16:13:03 +11:00
Oliver Walters
0de284f1aa Unit fixes 2021-02-04 16:06:01 +11:00
Oliver Walters
6ebebe03d4 Simplify report snippet class definition 2021-02-04 15:38:41 +11:00
Oliver Walters
a025b7239d Adds simple test-report template 2021-02-04 15:29:46 +11:00
Oliver Walters
ddbf2a6313 Add margin callouts for report template base 2021-02-04 14:49:11 +11:00
Oliver Walters
cf0c43d899 Add report base template 2021-02-04 13:54:26 +11:00
Oliver Walters
6230fb3614 Add custom report template tags 2021-02-04 13:41:47 +11:00
Oliver Walters
801b945438 Add current date to report context 2021-02-04 13:33:14 +11:00
Oliver Walters
3ccc500e8e Add more context data to report 2021-02-04 12:58:19 +11:00
Oliver Walters
b107c54eb2 PEP fix 2021-02-04 09:13:45 +11:00
Oliver Walters
cabac6614c Add unit test for currency migration 2021-02-04 09:13:23 +11:00
Oliver Walters
e407b99d0d Add initial migration unit test for the 'part' app 2021-02-04 09:13:11 +11:00
Oliver Walters
d811f3c48a Typo fix
(cherry picked from commit c58399206c)
2021-02-04 08:39:27 +11:00
Oliver Walters
93f0dbd4ee Bug fix: add missing line
(cherry picked from commit 2303e03580)
2021-02-04 08:39:20 +11:00
Oliver Walters
ad0b59bf11 Bug fxi
(cherry picked from commit 0e11b722be)
2021-02-04 08:39:14 +11:00
Oliver Walters
b284fe7f2b Remove quotes around column names
(cherry picked from commit 386cb2dd3a)
2021-02-04 08:39:05 +11:00
Oliver Walters
75431f0ee4 Flake errors 2021-02-04 00:51:00 +11:00
Oliver Walters
e417ff2b4d Test migrations for build app 2021-02-04 00:44:37 +11:00
Oliver Walters
29bb735dc4 Helper functions to automatically extract migration file info 2021-02-04 00:25:00 +11:00
Oliver Walters
5c8e65c285 Only run linter checks for *new* migration files 2021-02-04 00:01:16 +11:00
Oliver Walters
f135f11564 Run lint checks on migration files 2021-02-03 23:56:59 +11:00
Oliver Walters
c2b5d96186 Ensure migration files are covered in coverage tests 2021-02-03 23:39:43 +11:00
Oliver Walters
bd9447d9aa Add django-migration-linter to ensure django migrations are tippy-top 2021-02-03 23:29:14 +11:00
Oliver Walters
34dbfe6d28 Test troublesome migration 0019 2021-02-03 23:16:23 +11:00
Oliver Walters
1d317b1ecb Add django-test-migrations package 2021-02-03 23:16:00 +11:00
Oliver Walters
cbadb2a888 Small refactor, and allow editing of ReportAsset in the admin interface 2021-02-03 21:54:11 +11:00
Oliver Walters
90bef69a59 Adds "report snippet" class allowing re-usable report snippets to be uploaded 2021-02-03 16:58:06 +11:00
Oliver
79ddea50f5 Merge pull request #1267 from SchrodingersGat/migration-fixes
Migration fixes
2021-02-03 14:48:21 +11:00
Oliver Walters
5e9097b5e0 PSQL: Upper-case column names *must* be qualified with double-quotes
Ref: https://www.xspdf.com/resolution/53039249.html
2021-02-03 13:16:32 +11:00
Oliver Walters
0e246a7fdf Migration fix (response is different for postgresql) 2021-02-03 13:02:28 +11:00
Oliver Walters
793e5b820e Remove all model references from migration file 2021-02-03 11:56:48 +11:00
Oliver Walters
bc43d14ebf Change model functions to raw SQL 2021-02-03 11:28:43 +11:00
Oliver Walters
f798537c73 Reverse migration company.0024 2021-02-03 09:52:59 +11:00
Oliver
65791a2b9b Merge pull request #1255 from SchrodingersGat/simple-qr-codes
Default to using "simple" QR codes
2021-02-01 13:37:42 +11:00
Oliver Walters
43e03ed023 Update unit tests 2021-02-01 12:26:58 +11:00
Oliver Walters
7d38507785 Merge remote-tracking branch 'inventree/master' into simple-qr-codes 2021-02-01 12:24:16 +11:00
Oliver
3449848682 Merge pull request #1266 from SchrodingersGat/barcode-data-fix
Limit barcode hash to printable characters.
2021-01-31 22:29:19 +11:00
Oliver Walters
97140b19ba Limit barcode hash to printable characters.
This is a dirty filthy hack, as the web-input strips non printable chars when they are typed in (but will accept them if they are copy-pasted)
2021-01-31 21:45:34 +11:00
Oliver
27b8928a10 Merge pull request #1263 from SchrodingersGat/table-translations
Table translations
2021-01-30 09:48:47 +11:00
Oliver
cb81d8b66a Merge pull request #1262 from SchrodingersGat/hide-barcode-button
Hide main QR button if setting is disabled
2021-01-29 13:06:48 +11:00
Oliver Walters
8fda2cf745 Fixes for unit tests 2021-01-29 12:47:46 +11:00
Oliver Walters
4ef6a6dc62 Translations for stock transaction notes 2021-01-29 12:23:22 +11:00
Oliver Walters
282ed0c637 Recompile translations 2021-01-29 12:05:47 +11:00
Oliver Walters
c1a54ddffd Expose bootstrap table strings to translation layer 2021-01-29 12:04:36 +11:00
Oliver Walters
62501ecb93 Hide main QR button if setting is disabled 2021-01-29 09:48:16 +11:00
Oliver
8c7621d4bc Merge pull request #1260 from SchrodingersGat/barcode-scanner
Barcode scanner
2021-01-29 00:42:50 +11:00
Oliver Walters
fc193c26d0 Delete unused function 2021-01-28 22:43:41 +11:00
Oliver Walters
489a15704c Refactoring 2021-01-28 22:41:20 +11:00
Oliver Walters
ae15ce9d0a Update translations 2021-01-28 22:38:47 +11:00
Oliver Walters
e8d73c78eb Fixes for unit tests 2021-01-28 22:37:28 +11:00
Oliver Walters
c61631a380 Refactor tractor 2021-01-28 22:24:06 +11:00
Oliver Walters
5e5bced0c7 Optionally include javascript code based on barcode feature 2021-01-28 21:51:34 +11:00
Oliver Walters
4641123cd8 Allow multiple stock items to be checked into a location using table selection 2021-01-28 21:47:39 +11:00
Oliver Walters
d61ae8532a Dialog for checking multiple items into a stock location 2021-01-28 21:36:57 +11:00
Oliver Walters
7e8def15ed Hide barcode actions if barcode support is disabled 2021-01-28 20:45:42 +11:00
Oliver Walters
51a33e5dca Add setting to enable / disable barcode support
(Default = True)
2021-01-28 20:18:03 +11:00
Oliver
14d24ebe07 Merge pull request #1258 from SchrodingersGat/part-image-fix
Prevent part images from auto deleting
2021-01-28 00:18:44 +11:00
Oliver Walters
220777611a Prevent part images from auto deleting
- Part images can be used for multiple parts
2021-01-27 22:31:21 +11:00
Oliver Walters
5c9dd93ff1 More unit test fix 2021-01-22 12:22:29 +11:00
Oliver Walters
03f7baf87f Unit test fixes 2021-01-22 09:50:30 +11:00
Oliver Walters
2d412e2be1 Default to using "simple" QR codes 2021-01-21 20:55:13 +11:00
Oliver
b90311acea Merge pull request #1250 from SchrodingersGat/url-col
Display link column in part table
2021-01-20 19:30:36 +11:00
Oliver Walters
69362ab960 Display link column in part table 2021-01-20 18:04:08 +11:00
Oliver
71522fa608 Merge pull request #1248 from SchrodingersGat/overdue-unit-test
Adds unit testing for order overdue status
2021-01-20 08:38:44 +11:00
Oliver Walters
82e6b87e1c Adds unit testing for order overdue status 2021-01-20 07:49:14 +11:00
Oliver
914fe15921 Merge pull request #1247 from Pervanovo/pr-fix-misspelled-query-filter
Fix misspelled query filter method name
2021-01-20 07:27:15 +11:00
Daniel Pervan
0d462389b9 Fix misspelled query filter method name 2021-01-19 12:00:30 +01:00
Oliver
d17cb47e3c Update version.py 2021-01-19 11:06:08 +11:00
Oliver
5c2012f873 Update version.py 2021-01-19 11:05:50 +11:00
Oliver
0517fe5073 Merge pull request #1243 from SchrodingersGat/report-filter-validation
Improve filter validation for test report
2021-01-19 11:05:24 +11:00
Oliver Walters
59e37b2526 Improve filter validation for test report 2021-01-19 08:15:50 +11:00
Oliver
ce28b84f34 Merge pull request #1242 from SchrodingersGat/batch-reports
Batch reports
2021-01-18 23:48:19 +11:00
Oliver Walters
f81c154578 Update translation files 2021-01-18 23:25:11 +11:00
Oliver Walters
436207b315 Merge remote-tracking branch 'inventree/master' into batch-reports
# Conflicts:
#	InvenTree/templates/stock_table.html
2021-01-18 23:23:58 +11:00
Oliver
a5aa90cdf2 Merge pull request #1155 from eeintech/stock_owner
Stock Locations and Items Ownership
2021-01-18 22:55:26 +11:00
Oliver Walters
833ba8c472 Template fixes 2021-01-18 22:45:07 +11:00
Oliver Walters
526d81481b Cleanup 2021-01-18 22:25:53 +11:00
Oliver Walters
697a338700 Add a smattering of unit tests 2021-01-18 22:14:38 +11:00
Oliver Walters
6a7c722efc Stock table button cleanup 2021-01-18 21:52:20 +11:00
Oliver Walters
952da19600 Print test report for multiple stock items at once 2021-01-18 21:42:55 +11:00
Oliver Walters
0a566c062d Add click callback on item test tab 2021-01-18 21:36:37 +11:00
Oliver Walters
ef7cc3f78d Replace existing django form views with API request 2021-01-18 21:33:15 +11:00
Oliver Walters
1b835a71df Print one (or more!) report templates via API 2021-01-18 21:17:19 +11:00
Oliver Walters
cbb286e46d Add API for stock item test report 2021-01-18 20:55:30 +11:00
Oliver
873ac9accb Merge pull request #1241 from SchrodingersGat/settings.py
Allow more settings to be specified via environment variables
2021-01-18 20:52:50 +11:00
Oliver Walters
f7079c3bc2 Style fixes 2021-01-18 20:21:19 +11:00
Oliver Walters
3ae4125df3 Allow more settings to be specified via environment variables 2021-01-18 20:17:36 +11:00
Oliver
1d6bd2c6ca Merge pull request #1240 from SchrodingersGat/translation-stats
Translation stats
2021-01-18 20:08:20 +11:00
Oliver Walters
c392bba196 Add script to calculate translation stats 2021-01-18 19:13:52 +11:00
Oliver Walters
c517801c5f Update doc strings for translation scripts 2021-01-18 18:51:10 +11:00
Oliver
2277d225eb Merge pull request #1239 from SchrodingersGat/stock-serial-fix
Stock serial fix
2021-01-18 16:50:54 +11:00
Oliver Walters
2b30df1a70 Fix 2021-01-18 14:41:31 +11:00
Oliver Walters
a7baad33ba Fix form error for creating a new stock item 2021-01-18 14:41:31 +11:00
eeintech
72c7ceb553 Merged master and updated stock_table.html 2021-01-17 13:11:59 -05:00
Oliver
2991ce9317 Merge pull request #1236 from SchrodingersGat/js-fix
Bug fix
2021-01-17 19:58:35 +11:00
Oliver Walters
0dee4df8fb Bug fix 2021-01-15 17:11:46 +11:00
Oliver
69e6006436 Merge pull request #1235 from SchrodingersGat/stock-updated-filter
Stock updated filter
2021-01-15 17:08:21 +11:00
Oliver Walters
4952c95c33 Extra check to prevent JS crash 2021-01-15 16:51:34 +11:00
Oliver Walters
fc32d99327 Add "updated_before" and "updated_after" filter for stock API 2021-01-15 16:39:50 +11:00
Oliver Walters
ef3ac43c4a Add "last updated" date to stock table 2021-01-15 15:27:40 +11:00
Oliver
8f4ae14f2d Merge pull request #1233 from SchrodingersGat/limit-matches
Limit matches to the 5 "most matchy" ones
2021-01-15 12:55:39 +11:00
Oliver Walters
85bce24e30 Limit matches to the 5 "most matchy" ones 2021-01-15 12:32:27 +11:00
Oliver
aada0ca5af Merge pull request #1212 from SchrodingersGat/label-api
Label API
2021-01-15 09:47:34 +11:00
eeintech
7d5571ba5b Merged changes from master 2021-01-14 08:52:56 -05:00
Oliver Walters
a70416abac Update translations 2021-01-15 00:04:31 +11:00
Oliver Walters
0134597747 Merge remote-tracking branch 'inventree/master' into label-api
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
2021-01-14 23:56:23 +11:00
Oliver
449b462bf2 Merge pull request #1232 from SchrodingersGat/purchase-order-target-date
Purchase order target date
2021-01-14 23:26:58 +11:00
Oliver Walters
4fd0d7d8b5 Unit test fix 2021-01-14 23:06:49 +11:00
Oliver Walters
959914c78c Display overdue purchase orders in the calendar view 2021-01-14 22:19:32 +11:00
Oliver Walters
fef5b7548e Increase unit testing for order API 2021-01-14 22:06:53 +11:00
Oliver
af7af395f8 Merge pull request #1219 from rcludwick/secret_key
Fixes #1215.  Allow secret key to come from file.
2021-01-14 21:11:30 +11:00
Rob Ludwick
3cfe358102 Fixes #1215. Allow secret key to come from file. 2021-01-14 01:02:34 -07:00
Oliver Walters
02132fa495 Updated translation files 2021-01-14 17:55:00 +11:00
Oliver Walters
75e1442fce Display overdue purchase orders on the index page 2021-01-14 17:48:16 +11:00
Oliver Walters
e8fd597f29 Adds ability to edit target_date in purchaseorder form 2021-01-14 17:44:21 +11:00
Oliver Walters
21e8ddd1e6 Display overdue status on PurcahseOrder page 2021-01-14 17:42:38 +11:00
Oliver Walters
a8e6d0a89f Display overdue status in purchase order table
- Allow table to be filtered by "overdue" status
2021-01-14 17:37:10 +11:00
Oliver Walters
4d73aab090 Add "overdue" flag to serializer
- Also allow filtering by overdue status in the API
2021-01-14 17:33:24 +11:00
Oliver Walters
834d9ec9a1 Add "target_date" field to PurchaseOrder 2021-01-14 17:28:57 +11:00
Oliver
9efde9de29 Merge pull request #1231 from SchrodingersGat/slow-bom-fix
Add option to show part quantity in various forms
2021-01-14 15:35:39 +11:00
Oliver Walters
1dc2636e45 Add option to show part quantity in various forms
Enabling this option can make BOM item forms *very* slow!
2021-01-14 15:20:42 +11:00
Oliver
8d6b4a2fd3 Merge pull request #1229 from SchrodingersGat/cancel-order-fix
Bug fix for cancelling purchase orders
2021-01-14 15:03:36 +11:00
Oliver Walters
be41741b1e Bug fix for cancelling purchase orders 2021-01-14 14:37:49 +11:00
Oliver
76c938762c Merge pull request #1228 from SchrodingersGat/stock-status-ste
Stock status ste
2021-01-14 14:24:47 +11:00
Oliver
3ec57a7259 Merge pull request #1226 from SchrodingersGat/can-build
Add "Can Build" column in BOM view
2021-01-14 14:04:43 +11:00
Oliver Walters
bb9fe98a7e Set status for multiple stock items at once 2021-01-14 14:04:24 +11:00
Oliver Walters
aac835f634 Add menu item to set stock status for multiple items 2021-01-14 13:41:38 +11:00
Oliver Walters
d459947949 Add "Can Build" column in BOM view 2021-01-14 13:34:51 +11:00
Oliver
a2f9d721f3 Merge pull request #1222 from SchrodingersGat/bom-upload-fix
Fix IPN comparison against null value
2021-01-14 13:17:23 +11:00
Oliver Walters
1cb951bd0b Fix for font-awesome icon 2021-01-14 12:08:54 +11:00
Oliver Walters
df327d4e64 Add stocktake_date field to stock API, and to stock table 2021-01-14 11:29:35 +11:00
Oliver Walters
1316e6bf5b Properly save user data when creating a new StockItem 2021-01-14 11:24:52 +11:00
Oliver Walters
890ce9ef95 Fix IPN comparison against null value 2021-01-14 10:58:29 +11:00
Oliver Walters
df335b683c Add #TODO 2021-01-14 10:54:34 +11:00
eeintech
c5778b6fb6 Added missing migration file (how did it escape?) 2021-01-13 17:33:55 -05:00
eeintech
e92e5dfe8f Merged master 2021-01-13 17:08:01 -05:00
Oliver
e4b202edd8 Merge pull request #1221 from eeintech/new_rule_sets
Separated category from part permissions and location from stock item permissions
2021-01-14 08:38:44 +11:00
Oliver Walters
b7bbc97218 Add unit test 2021-01-14 08:32:37 +11:00
Oliver Walters
9884fe5c5e Improve validators for 'filters' field 2021-01-14 08:15:05 +11:00
Oliver Walters
88a7b3251d Remove unused import 2021-01-14 08:14:32 +11:00
eeintech
af1abb7129 Added missing migration file 2021-01-13 14:57:16 -05:00
eeintech
59c0a50289 Separated category from part permissions and location from stock item permissions 2021-01-13 13:35:49 -05:00
eeintech
28fb1b5fab Added owner model to admin page and added test cases 2021-01-13 11:38:37 -05:00
Oliver Walters
6e4cf7c092 Catch db integrity errors 2021-01-13 22:07:30 +11:00
Oliver Walters
80c88b4fcc Update translations 2021-01-13 21:53:11 +11:00
Oliver Walters
4e2d3b7da2 Improvement for existing StockItemLabel template 2021-01-13 21:52:16 +11:00
Oliver Walters
e561b3a4fc Add StockItemLabel templates 2021-01-13 21:51:55 +11:00
Oliver
eedd8059d8 Merge pull request #1217 from eeintech/bom_item_delete
Allow user with part.change permission to delete BOM items, part attachments and parameters
2021-01-13 10:16:25 +11:00
eeintech
a1b2347784 Also allow part attachements and parameters to be deleted 2021-01-12 17:43:12 -05:00
eeintech
ba1862478c Allow user with part.change permission to delete BOM items 2021-01-12 17:34:11 -05:00
eeintech
0a0a47a5e4 Added location owner change test case to verify stock item owner in that location is also updated 2021-01-12 17:11:46 -05:00
eeintech
3054c637dd Removed f-string debug 2021-01-12 16:42:09 -05:00
eeintech
5ca03af3e2 Improved Owner.get_owner method and fixed tests (try#2) 2021-01-12 16:36:29 -05:00
eeintech
49c954aa68 Fixed test cases? 2021-01-12 15:02:44 -05:00
eeintech
452d22579a Removed f-string causing build failure 2021-01-12 13:23:14 -05:00
eeintech
b6135fda74 Updated templates and a lot of manual testing 2021-01-12 13:16:04 -05:00
eeintech
9eace09e0e Added owner create method and fixed post_save receiver 2021-01-12 10:53:17 -05:00
eeintech
6f3cbb4e14 Switched to global owner model, need to validate use-cases table and fix tests 2021-01-11 17:41:29 -05:00
eeintech
6a88bdb37d StockLocation owner is now a GenericForeignKey that can be set to user or group models 2021-01-11 12:56:40 -05:00
Oliver Walters
01e27a0d59 Add simplified 'barcode' function for StockItem 2021-01-12 00:22:58 +11:00
Oliver Walters
663a0a6165 Create simple label templates for stocklocation labels 2021-01-11 23:45:25 +11:00
Oliver Walters
d1d243fb14 Update label models 2021-01-11 23:44:11 +11:00
Oliver Walters
b6cd2c215a Adds function to provide simplified barcode for stock location 2021-01-11 21:32:31 +11:00
Oliver Walters
1368b06afa PEP fix 2021-01-11 19:46:17 +11:00
Oliver Walters
d91700fd39 StockLocation labels are now printable 2021-01-11 18:41:57 +11:00
Oliver Walters
af47b211fd Add dialog for selection of stock location labels 2021-01-11 17:22:04 +11:00
Oliver Walters
79b63e6d30 Update translation 2021-01-09 22:23:51 +11:00
Oliver Walters
a3c5ea1f2b Typo fix 2021-01-09 22:02:33 +11:00
Oliver Walters
21d5440f98 Remove unused views 2021-01-09 21:55:05 +11:00
Oliver Walters
e133fff03e Download PDF for labels 2021-01-09 21:50:42 +11:00
Oliver Walters
bdc7367e29 Add endpoint for printing labels 2021-01-09 20:43:48 +11:00
Oliver Walters
44e60a705e Add detail endpoints for the StockItemLabel and StockLocationLabel models 2021-01-09 08:20:29 +11:00
Oliver Walters
a0d1f95171 Add exception for new database table 2021-01-09 08:10:04 +11:00
eeintech
587bf26d94 Fixed style 2021-01-08 14:23:35 -05:00
eeintech
2f78c7c036 Updated stock tests quantities 2021-01-08 14:05:53 -05:00
eeintech
d25a719724 Merge branch 'stock_owner' of github.com:eeintech/InvenTree into stock_owner 2021-01-08 13:51:49 -05:00
Oliver Walters
7c7a67fcc6 Add filterable API for StockLocation labels 2021-01-08 23:08:30 +11:00
Oliver Walters
f0fa092c66 Add model for StockLocation label 2021-01-08 23:08:00 +11:00
Oliver Walters
80c7ee6dab Add ability to filter label by StockItem 2021-01-08 22:47:47 +11:00
Oliver Walters
446c744462 Expose stock items labels to the API 2021-01-08 22:19:52 +11:00
Oliver
ab9a6bd3c4 Merge pull request #1211 from SchrodingersGat/attachment-api
Filter PartAttachment API list by Part reference
2021-01-08 12:22:59 +11:00
Oliver Walters
59bb5d15c8 Filter PartAttachment API list by Part reference 2021-01-08 08:43:00 +11:00
eeintech
67bc86c159 Updated stock owners migration file 2021-01-07 14:05:43 -05:00
eeintech
f26f1c38a2 Merged master 2021-01-07 13:50:29 -05:00
Oliver
5666db6b7a Merge pull request #1208 from SchrodingersGat/calendar
Add fullcalendar javascript library
2021-01-08 00:04:16 +11:00
Oliver Walters
75f31ecc63 Update translations 2021-01-07 23:50:34 +11:00
Oliver Walters
47b0f40e97 Calendar view for build orders 2021-01-07 23:41:54 +11:00
Oliver Walters
76c86e7b2f Calendar view for purchase orders 2021-01-07 23:04:00 +11:00
Oliver Walters
38b6367453 PEP fixes 2021-01-07 22:34:17 +11:00
Oliver Walters
b7203f0ebb Switch between calendar and list view for sales orders 2021-01-07 22:32:17 +11:00
Oliver Walters
5f6442ba6b Render sales orders to a calendar view 2021-01-07 18:47:29 +11:00
Oliver Walters
b4277e09e8 Add fullcalendar javascript library 2021-01-07 14:21:32 +11:00
Oliver
c377fb7b0c Merge pull request #1205 from SchrodingersGat/hide-report-button
Rearrange button options for StockItem
2021-01-07 00:34:23 +11:00
Oliver Walters
bb72658e76 Rearrange button options for StockItem 2021-01-07 00:18:18 +11:00
Oliver
735a3d2eb2 Merge pull request #1202 from SchrodingersGat/stock-expiry
StockItem expiry date
2021-01-06 23:51:18 +11:00
Oliver Walters
7ac7e8f969 Fixed unit test 2021-01-06 23:38:01 +11:00
Oliver Walters
a8e3e6c8db Update translation 2021-01-06 23:12:52 +11:00
Oliver Walters
e5b346e7fa PEP fixes 2021-01-06 23:09:26 +11:00
Oliver Walters
1d6a049c5a Annotate stock queryset with stale status 2021-01-06 23:06:49 +11:00
Oliver Walters
a5b18640af Display stale stock on index page 2021-01-06 22:30:12 +11:00
Oliver Walters
e62873a650 Display "stale" status on StockItem info page 2021-01-06 22:21:18 +11:00
Oliver Walters
ba915da22b Filter StockItem API by staleness 2021-01-06 22:20:54 +11:00
Oliver Walters
33d6396a4e Exclude expired stock from builds 2021-01-06 21:00:45 +11:00
Oliver Walters
580e7599a0 Prevent expired stock from being added to a sales order 2021-01-06 20:22:56 +11:00
Oliver Walters
9b086560cb Hide "expiry_date" column in Stock table if feature not enabled 2021-01-06 12:09:48 +11:00
Oliver Walters
d0fb69e67d Add option to enable / disable stock expiry feature
- Simply hides fields in form views
2021-01-05 08:50:07 +11:00
Oliver Walters
1335c85de1 Edit new stock settings on settings page 2021-01-05 00:59:10 +11:00
Oliver Walters
855098e30b Merge conflicting migration files 2021-01-05 00:58:48 +11:00
Oliver Walters
e715ea5d79 Merge remote-tracking branch 'inventree/master' into stock-expiry
# Conflicts:
#	InvenTree/common/models.py
2021-01-05 00:58:32 +11:00
Oliver Walters
213d6550d3 Add new setock settings 2021-01-05 00:54:05 +11:00
Oliver Walters
9a30108b75 Auto-update the expiry date in the StockItem form when switching Part selection 2021-01-05 00:37:42 +11:00
Oliver Walters
9dc9c0fcb7 Auto-populate expiry date for stockitem when created via the API
(Now with unit testing!)
2021-01-05 00:21:26 +11:00
Oliver Walters
da02ab3eac Add unit testing for view 2021-01-05 00:01:44 +11:00
Oliver Walters
7d7d5d24cc Pre-fill stockitem expiry date in CreateStockItem form 2021-01-04 23:40:51 +11:00
Oliver Walters
37dcf1c1cf Add "default_expiry" field to Part model 2021-01-04 23:36:11 +11:00
Oliver Walters
692cee113c Display "expiry date" column in stock table 2021-01-04 23:11:35 +11:00
Oliver Walters
4d7c60a130 Add "expired stock" table to index page 2021-01-04 09:46:14 +11:00
Oliver Walters
d1ce0f062e Improve unit testing for StockItem API 2021-01-04 01:22:43 +11:00
Oliver Walters
a0c95579b4 Display expiry status on StockItem page
- Also adds ability to filter Stock table by expired status
2021-01-04 00:21:47 +11:00
Oliver Walters
39b9dcfec9 Add 'expired' flag to StockItem serializer 2021-01-04 00:21:21 +11:00
Oliver Walters
1a930f7f80 Add ability to edit expiry_date for StockItem 2021-01-04 00:20:02 +11:00
Oliver Walters
6d4c81e68b Add ability to filter by 'expired' status in API 2021-01-04 00:19:48 +11:00
Oliver Walters
07cda765f0 Add "expiry_date" field to StockItem model
- Also adds "is_expired" function
2021-01-03 23:56:35 +11:00
Oliver
bc72cd612e Merge pull request #1201 from SchrodingersGat/settings
Settings Improvements
2021-01-03 23:47:35 +11:00
Oliver Walters
0f9c4703cf Update unit testing 2021-01-03 23:33:47 +11:00
Oliver Walters
b05504e1c4 Add PART_VIRTUAL setting 2021-01-03 23:13:58 +11:00
Oliver
fe3d4a9867 Merge pull request #1200 from SchrodingersGat/supplier-part-import
SupplierPart import/export fixes
2021-01-03 23:08:05 +11:00
Oliver Walters
0aeeba808c PEP fixes 2021-01-03 23:07:21 +11:00
Oliver Walters
6c7b648133 Implement global settings for assembly and template values of Part model 2021-01-03 23:06:51 +11:00
Oliver Walters
9fa37a9156 Improve visualisation of global settings 2021-01-03 22:57:39 +11:00
Oliver Walters
8e9c976e99 Update translations 2021-01-03 22:18:08 +11:00
Oliver Walters
2a91bb0c87 Update SupplierPart model to allow data importing
- django-import-export plugin seems to require null=True for char fields
- yes, this goes against django "best practice"
- Hopefully a better solution can be found
2021-01-03 22:16:32 +11:00
Oliver
bdc3a9ef02 Merge pull request #1198 from SchrodingersGat/stock-item-form-fix
Fix for StockItem create / edit forms
2021-01-03 14:15:56 +11:00
Oliver Walters
2ad090c224 pop purchase_price field for StockItemEdit form 2021-01-03 13:15:42 +11:00
Oliver Walters
fe0d356675 pops the purchase_price field instead of using a HiddenInput
Using a HiddenInput on a MoneyFormField causes a validation error, for some reason...
2021-01-03 13:13:14 +11:00
Oliver
11c6248b06 Merge pull request #1197 from SchrodingersGat/bom-fix
Fix variable scope issue
2021-01-03 10:30:47 +11:00
Oliver Walters
298e9cae65 Fix variable scope issue 2021-01-03 10:07:38 +11:00
Oliver
2dfa4d1acd Merge pull request #1196 from SchrodingersGat/target-date-optional
Target date optional
2021-01-03 09:00:46 +11:00
Oliver Walters
725a70327a Add some unit testing 2021-01-02 22:21:37 +11:00
Oliver Walters
b2a732197b Fix target date form field for SalesOrder 2021-01-02 21:54:07 +11:00
Oliver Walters
2b57ffeb08 Custom date picker field
- Prevents picker from being "required" by the form
2021-01-02 21:50:10 +11:00
Oliver Walters
03276629c2 CSS tweaks 2021-01-02 21:41:47 +11:00
eeintech
3ff76fbdab Merging master and resolved conflict 2020-12-18 17:08:37 -05:00
Oliver
7560b7e167 Merge pull request #1177 from SchrodingersGat/sales-order-overdue
Sales order overdue
2020-12-18 20:06:48 +11:00
Oliver Walters
08a8556fe7 Fix unit testing 2020-12-18 19:46:02 +11:00
Oliver Walters
13e924cc05 Fix default value for PO and SO codes 2020-12-18 16:10:55 +11:00
Oliver Walters
8e13a7b470 Add "overdue sales orders" to index page 2020-12-18 12:45:42 +11:00
Oliver Walters
c34196538b Filter API by overdue status 2020-12-18 12:40:47 +11:00
Oliver Walters
b21c6f0b99 Add overdue filter for salesorder table 2020-12-18 12:27:08 +11:00
Oliver Walters
c6134b54ab Add "overdue" status to SalesOrder serializer 2020-12-18 12:26:58 +11:00
Oliver Walters
000348f70f Add 'target_date' field to SalesOrder model 2020-12-18 12:19:16 +11:00
Oliver
8bb4683bbe Merge pull request #1175 from eeintech/fix_stock_template
Keep 'stock actions' button enabled when on children tab
2020-12-18 12:02:39 +11:00
Oliver
d38d9b21a9 Merge pull request #1174 from eeintech/fix_category_parameter_url
Fixed category parameter templates settings view
2020-12-18 12:00:51 +11:00
eeintech
1a48405491 Keep 'stock actions' button enabled when on children tab 2020-12-17 17:37:54 -05:00
eeintech
bcae1d09a8 Fixed category parameter templates settings view 2020-12-17 17:25:10 -05:00
Oliver
a8c6e79bc0 Merge pull request #1172 from SchrodingersGat/duplicate-ipn-fix
Bugfix for duplicate IPN checks when blank IPN is used
2020-12-16 21:53:14 +11:00
Oliver Walters
06d9f4f982 Bugfix for duplicate IPN checks when blank IPN is used 2020-12-16 21:02:53 +11:00
Oliver
7df25df2af Merge pull request #1168 from SchrodingersGat/order-date
Build Order Target Date
2020-12-16 19:36:10 +11:00
Oliver Walters
464d76a819 Update form title strings 2020-12-16 19:09:53 +11:00
Oliver Walters
447f0b0ed7 Update translations 2020-12-16 19:03:04 +11:00
Oliver Walters
0500036d0a settings.py - typo fix 2020-12-16 16:58:40 +11:00
Oliver Walters
261a9af4f5 Typo fix 2020-12-16 16:32:20 +11:00
Oliver
04336dd039 Merge pull request #1169 from SchrodingersGat/parent-test-link
Render link rather than just text
2020-12-16 16:29:54 +11:00
Oliver Walters
a9310d4a39 Add a #TODO in code 2020-12-16 16:16:07 +11:00
Oliver Walters
a8704a05d6 PEP style fixes 2020-12-16 16:15:39 +11:00
Oliver Walters
597bf8be73 Add date input to build target_date 2020-12-16 16:13:38 +11:00
Oliver Walters
6ef4325eac Javascript formatting 2020-12-16 15:55:42 +11:00
Oliver Walters
1a07ae0936 Render link rather than just text 2020-12-16 15:48:41 +11:00
Oliver
bf3b5bdd7f Merge pull request #1167 from SchrodingersGat/login-page
Improve rendering for login page
2020-12-15 23:34:32 +11:00
Oliver Walters
17d23fa47c Add overdue builds to the index page 2020-12-15 23:34:28 +11:00
Oliver Walters
c8c50af54b Filter builds by "overdue" status 2020-12-15 23:31:19 +11:00
Oliver Walters
51da26d21d Filter builds by "overdue" status 2020-12-15 23:27:59 +11:00
Oliver Walters
802dd5174c Add "target_date" for Build model
- Add "overdue" status to Build serializer
2020-12-15 23:24:37 +11:00
Oliver Walters
f11348c965 Improve rendering for login page 2020-12-15 22:39:57 +11:00
Oliver
a7d825158c Merge pull request #1164 from SchrodingersGat/stock-report-filter
Stock report filter
2020-12-15 13:32:13 +11:00
Oliver Walters
297bfd776c Pre-select a template if only one matching one exists 2020-12-15 12:31:02 +11:00
Oliver Walters
ef032d406f Bugfix for stock report filter 2020-12-15 11:57:52 +11:00
Oliver
980cb9522b Merge pull request #1162 from SchrodingersGat/gunicorn-conf
Update default gunicorn conf file
2020-12-14 11:00:57 +11:00
Oliver Walters
55b7cd3d6a PEP fix 2020-12-14 10:44:38 +11:00
Oliver
70cac17138 Merge pull request #1163 from SchrodingersGat/hide-purchase-price
Hide purchase price field for non-purchaseable parts
2020-12-14 10:43:21 +11:00
Oliver Walters
648595cf18 Hide purchase price field for non-purchaseable parts 2020-12-14 09:55:39 +11:00
Oliver Walters
d609e881c2 Update default gunicorn conf file 2020-12-14 09:43:07 +11:00
Oliver
1c168452a4 Merge pull request #1159 from eeintech/roles_overview
Display permission levels for each ruleset in Group admin list view
2020-12-11 10:03:56 +11:00
eeintech
1ef5a2b481 Display permission levels for each ruleset in Group admin list view 2020-12-10 15:38:48 -05:00
eeintech
33dfecfdef Added create view test cases for stock ownership 2020-12-03 13:29:59 -05:00
eeintech
3aad5111b5 Stock ownership: test case for edit stock location and item 2020-12-03 11:56:45 -05:00
eeintech
f99c83f69d Added test case for stock location ownership 2020-12-03 07:32:01 -05:00
eeintech
5c6939429a Improved handling of stock location owner 2020-12-02 17:19:41 -05:00
eeintech
1a7a460ba8 Hidden owner field when ownership control is disabled 2020-12-02 14:05:45 -05:00
eeintech
de1dfdcc38 Improved naming of new setting and variables 2020-12-02 13:38:53 -05:00
eeintech
2bdd1305ed Fix style 2020-12-02 13:26:26 -05:00
eeintech
c66ac2579e Updated StockItem create/edit view with ownership control 2020-12-02 13:25:33 -05:00
eeintech
2d7461f609 Updated StockLocation create/edit view with ownership control 2020-12-02 12:05:00 -05:00
eeintech
c9b3c16c6f Added help text on owner fields 2020-12-01 17:46:11 -05:00
eeintech
8dac6bb982 Updated template stock item logic and added to stock locations 2020-12-01 17:41:03 -05:00
eeintech
4104e7df8e Fixed template logic 2020-12-01 16:08:27 -05:00
eeintech
2c38be2d13 Added global setting and updated stock item templates 2020-12-01 15:54:05 -05:00
eeintech
e1fb7e5d98 Added owner field to both stock item and location tables and forms 2020-12-01 13:45:01 -05:00
Oliver
9dae7c1566 Merge pull request #1154 from SchrodingersGat/build-delete-fix
Change delete behaviour for parent build item
2020-12-01 12:36:24 +11:00
Oliver Walters
47d38e1cca Change delete behaviour for parent build item
- was causing database integrity errors when a parent build existed
2020-12-01 10:24:51 +11:00
Oliver
28a5ee32c4 Merge pull request #1152 from elmo2k3/fix-stocklist-sidebar
Fix sidenav in stocklist
2020-12-01 08:56:41 +11:00
Bjoern Biesenbach
95f62d529f Fix sidenav in stocklist 2020-11-30 18:30:51 +01:00
Oliver
a8f605c2e6 Merge pull request #1149 from SchrodingersGat/bom-upload-speed
Vastly improved speed of BOM upload
2020-11-27 15:25:46 +11:00
Oliver Walters
ea2f5009c8 Vastly improved speed of BOM upload
- Was calculating the stock levels for *every* part, for *every* drop down
- Many many many calls were being made
- Just remove stock count entirely from the drop-down menus
2020-11-27 14:40:30 +11:00
Oliver
a5e6ac2300 Merge pull request #1148 from SchrodingersGat/order-parts
Order parts
2020-11-27 12:28:04 +11:00
Oliver
b150c9c6bc Merge pull request #1147 from SchrodingersGat/form-fixes
Fixes for 'non field' errors in forms
2020-11-27 12:27:53 +11:00
Oliver Walters
50a88e4826 Revert "Add extra context to SupplierPartCreate form"
This reverts commit 5f8f0232a9.
2020-11-27 11:19:16 +11:00
Oliver Walters
6c68197e61 Allow part ordering from build view 2020-11-27 11:18:58 +11:00
Oliver Walters
7068f70811 Fixes for 'order parts' form
- Sometimes the part pk was not being retrieved properly
2020-11-27 11:18:45 +11:00
Oliver Walters
607cc90ce0 Add extra context to SupplierPartCreate form
(cherry picked from commit 5f8f0232a9)
2020-11-27 11:18:23 +11:00
Oliver Walters
5f8f0232a9 Add extra context to SupplierPartCreate form 2020-11-27 11:17:55 +11:00
Oliver Walters
56f05e2604 Fixes for 'non field' errors in forms
- Fixes issue where non-model fields would not show error text
2020-11-27 10:42:01 +11:00
Oliver
aacc7119bd Merge pull request #1144 from SchrodingersGat/bom-fixes
Bom fixes
2020-11-24 22:28:20 +11:00
Oliver Walters
083d7671d0 Bug fix for BOM table
If the BOM for part included a BomItem with the same PK as the top-level part,
the bootstrap-tree-grid library borked

Probably for good reason, too!

So we now ensure that the top-level key is unique
2020-11-24 21:19:19 +11:00
Oliver Walters
28333c1a21 Add a simple "shell" task 2020-11-24 21:18:00 +11:00
Oliver Walters
e3231bbedb Hide "pricing" information in the BOM table 2020-11-24 20:58:18 +11:00
Oliver
3ff0759bb9 Merge pull request #1142 from SchrodingersGat/bom-form-fixes
Bom form fixes
2020-11-24 14:23:04 +11:00
Oliver Walters
b5d75d6e6a PEP fixes 2020-11-24 11:56:51 +11:00
Oliver Walters
ce82579930 Cleanup getRequiredParts function 2020-11-24 10:18:07 +11:00
Oliver Walters
371ec582e1 Cleanup queryset for BomItemEdit view 2020-11-24 09:43:49 +11:00
Oliver Walters
3391db506a Cleanup queryset for BomItemCreate view 2020-11-24 09:43:32 +11:00
Oliver Walters
af9b88de11 Fix for BomItem clean function
Handle the case where the sub_part does not exist
2020-11-24 09:33:26 +11:00
Oliver
73259c0bcb Merge pull request #1140 from SchrodingersGat/request-frequency
Reduce duplicate function calls in custom context parser
2020-11-20 11:40:10 +11:00
Oliver
a0168515c3 Merge pull request #1139 from eeintech/fix_supplierpart_edit_form
Fix for SupplierPart edit form validation
2020-11-20 09:40:00 +11:00
Oliver Walters
20e8161038 Reduce duplicate function calls in custom context parser 2020-11-20 08:29:06 +11:00
eeintech
11745ebd6c Removed one too many indent 2020-11-19 15:32:42 -05:00
eeintech
4768c9cbb3 Fixed validation of SupplierPart edit form by forcing the value of single_pricing field 2020-11-19 15:31:39 -05:00
Oliver
6b104fbb8b Merge pull request #1136 from SchrodingersGat/warning-icon
Add framework for "health checks"
2020-11-19 13:30:17 +11:00
Oliver Walters
4049c8e915 Adds framework for "server health" display
- Adds global context object "system_healthy" (boolean)
- Framework for running system health checks
- Updated system info forms
- Displays warning next to user menu if system health errors exist

(cherry picked from commit ce6d626ab39147fc389de90815ca8baae2385d82)
2020-11-19 12:36:54 +11:00
Oliver
e55f4a2798 Merge pull request #1135 from SchrodingersGat/quoth-the-raven
Fixes for custom SQL queries
2020-11-19 10:34:53 +11:00
Oliver Walters
599220a931 Fixes for custom SQL queries
- Don't use double quotes!
- NO NO NO!
- Single quotes only
2020-11-19 09:15:16 +11:00
Oliver
0594ebaef7 Merge pull request #1133 from SchrodingersGat/stock-table-fix
Smallt tweaks for the Stock table
2020-11-18 15:24:06 +11:00
Oliver Walters
24fd520ec3 Smallt tweaks for the Stock table 2020-11-18 15:03:51 +11:00
Oliver
4daf291619 Merge pull request #1131 from SchrodingersGat/purchase-price-fix
Fix for StockItem creation form
2020-11-17 16:07:31 +11:00
Oliver Walters
6144d7e209 Fix for StockItem creation form
- purchase_price field was required (should not be!)
- Fixed some validation issues
- Cleaned up form implementation
2020-11-17 15:29:44 +11:00
Oliver
9fa718e58d Merge pull request #1130 from eeintech/api_category_parameters
Improved API endpoint for category parameter templates
2020-11-17 09:36:34 +11:00
eeintech
ac2797c7a1 Improved API endpoint for category parameter templates 2020-11-16 16:10:00 -05:00
Oliver
d8e7c2a932 Update version.py 2020-11-15 16:53:27 +11:00
Oliver
20f6964b1f Update version.py 2020-11-15 16:51:50 +11:00
Oliver
771efecaa2 Merge pull request #1127 from SchrodingersGat/settings-view-unit-test
Extra unit testing for settings forms / views
2020-11-14 09:19:31 +11:00
Oliver Walters
2e842503e6 Fix try statement 2020-11-14 07:39:51 +11:00
Oliver Walters
b738f8b143 Try transaction.atomic 2020-11-13 22:22:02 +11:00
Oliver Walters
aae1400929 Mayyyyyyyyyyyyybe? 2020-11-13 21:37:39 +11:00
Oliver Walters
5f9758e85f More fixes 2020-11-13 21:01:30 +11:00
Oliver Walters
03e852f957 Remove custom save method 2020-11-13 20:22:28 +11:00
Oliver
0bb8c0a1e3 Merge pull request #1128 from SchrodingersGat/settings-improvements
Improve settings.py
2020-11-13 15:32:48 +11:00
Oliver Walters
f0777ead92 Removed eprint statements 2020-11-13 14:39:28 +11:00
Oliver Walters
0f42916521 Improve settings.py
- Load database config from either config.yaml or environment variables
- Mix and match, if you want!
- Move to use logging module rather than just printing stuff
- Error if required database parameters are not required
2020-11-13 13:38:01 +11:00
Oliver Walters
ee70e27f7d Change function name 2020-11-13 13:21:43 +11:00
Oliver Walters
01ff562dcd Extra unit testing for settings forms / views 2020-11-13 11:50:58 +11:00
Oliver
1d4b826d03 Merge pull request #1124 from eeintech/fix_nocategory_templates_error
Check that category was selected before fetching templates
2020-11-13 10:41:51 +11:00
Oliver
d777549a1a Merge pull request #1123 from eeintech/fix_form_errors
Fixed disabling of form errors messing-up with global settings validation
2020-11-13 09:59:57 +11:00
Oliver
3130b672b4 Merge pull request #1117 from SchrodingersGat/currency-support
Currency support
2020-11-13 09:13:55 +11:00
eeintech
d4ac35b9aa Check that category was selected before fetching templates 2020-11-12 16:52:22 -05:00
eeintech
80b70fd2df Fixed disabling of form errors messing-up with global settings 2020-11-12 16:38:35 -05:00
Oliver Walters
362437e75e PEP fixes 2020-11-13 07:28:21 +11:00
Oliver Walters
f239c8f8c8 Add missing migration file 2020-11-12 22:04:50 +11:00
Oliver Walters
ae7fbd6112 Add PEP8-naming extension for flake
- Enforcing python naming checks
2020-11-12 21:53:04 +11:00
Oliver Walters
47cbf3071d Add option to add a single-quantity price-break when creating a new SupplierPart object
- Add unit testing!
2020-11-12 21:36:32 +11:00
Oliver Walters
534f43872f Bug fix for SupplierPart table 2020-11-12 20:14:10 +11:00
Oliver Walters
fd79f1ea0e Fixes for 'single pricing' for SupplierPart 2020-11-12 19:46:19 +11:00
Oliver Walters
7879c7565e More fixes to .travis.yml
Database in a strange location?
2020-11-12 19:11:12 +11:00
Oliver Walters
6e7224ee7c Add "purchase price" field to PurchaseOrderLineItem table 2020-11-12 18:05:24 +11:00
Oliver Walters
0988040172 Catch exception where InvenTree setting object is referenced but the database is not migrated yet 2020-11-12 18:04:50 +11:00
Oliver Walters
cb3c86f87a Merge remote-tracking branch 'inventree/master' into currency-support
# Conflicts:
#	InvenTree/InvenTree/settings.py
#	InvenTree/InvenTree/urls.py
#	InvenTree/templates/InvenTree/settings/tabs.html
#	InvenTree/users/models.py
#	requirements.txt

IMPORTANT: Had to merge some migration files due to different migrations applied on the part model tables
2020-11-12 17:24:48 +11:00
Oliver
265a29fa1a Merge pull request #1122 from SchrodingersGat/import-export-fix
Fixes for import / export of data
2020-11-12 17:06:50 +11:00
Oliver Walters
4765065eb0 Make sure to run database migrations first! (DUH) 2020-11-12 16:41:43 +11:00
Oliver Walters
563bfe9bf5 Further fixes to tasks.py 2020-11-12 16:10:00 +11:00
Oliver Walters
96ef5e1bde Travis fixes 2020-11-12 15:37:21 +11:00
Oliver Walters
fe9749ba4f Add missing fixture for settings 2020-11-12 14:54:03 +11:00
Oliver Walters
21315096d4 Further unit testing fixes 2020-11-12 14:53:49 +11:00
Oliver Walters
1738df9042 Update unit tests 2020-11-12 14:48:57 +11:00
Oliver Walters
ec8d8e5a64 Add more invoke commands:
- export-records: Exports all database records to external file
- import-records: Imports database records from external file
- import-fixtures: Fills the database with dummy records
2020-11-12 13:31:27 +11:00
Oliver Walters
4a8170079e Remove code which automatically created settings objects on server launch 2020-11-12 12:31:03 +11:00
Oliver Walters
b7187c5e06 Fixes for purchase order table displays 2020-11-12 12:27:01 +11:00
Oliver Walters
391eeb0e46 Specify default currency when creating a new stock item 2020-11-12 11:50:59 +11:00
Oliver Walters
51d2d85c26 When creating a new price break for a supplier part, default to using the currency code specified for the supplier company 2020-11-12 11:14:50 +11:00
Oliver Walters
1532be9c1e Add 'currency' option for company
- e.g. an external supplier might have a default currency
- Adds a form input which only allows selection of allowed currency codes
- Add unit testing for currency validation
2020-11-12 11:02:10 +11:00
Oliver
643589b4a9 Merge pull request #1096 from eeintech/categories_parameters
Categories parameter templates
2020-11-12 09:32:01 +11:00
eeintech
b4fa56fd96 Fixed PART_CATEGORY_PARAMETERS duplicate (bad merging... oopsy) 2020-11-11 12:40:03 -05:00
eeintech
bfdda847c4 Updated part migration reference in 0054 2020-11-11 11:18:10 -05:00
Francois
a7444a9926 Merge branch 'master' into categories_parameters 2020-11-11 06:40:11 -05:00
Oliver
4430098e98 Merge pull request #1120 from SchrodingersGat/used-in-fix
A little whoopsie-doo:
2020-11-11 16:47:34 +11:00
Oliver Walters
039a7badd1 A little whoopsie-doo:
- Part.clean() was incorrectly referencing a BomItem when it should have been referencing BomItem.part
2020-11-11 16:09:14 +11:00
Oliver
6d5bdaadbd Merge pull request #1118 from SchrodingersGat/log-viewer
Add requirement for django-error-report
2020-11-11 16:00:48 +11:00
Oliver Walters
56765d3f5a Fix for unit testing 2020-11-11 15:19:15 +11:00
Oliver Walters
6c667937c5 Add requirement for django-error-report
- Provides an error log viewer in the admin interface at /admin/error_report/error/
- Allows viewing of error logs even in a remote production environment (i.e. no access to command line)
2020-11-11 14:10:12 +11:00
Oliver Walters
ebac06ebee Add 'single_pricing' form to the EditSupplierPartForm
- Idea here is to automatically create a unit-pricing price-break when a new SupplierPart is created
2020-11-11 13:55:25 +11:00
Oliver Walters
fc89501a62 Fix for SQL cursor query
- What works in SQLite don't necessarily fly with the big boys
2020-11-11 08:06:14 +11:00
Oliver Walters
5567ad07fd Update tests and translations 2020-11-11 00:31:39 +11:00
Oliver Walters
a19cf1f27a PEP fixes 2020-11-11 00:26:59 +11:00
Oliver Walters
4dff18e4a6 Remove common_currency model entirely
- A lot of views / pages / etc needed to be updated too
- Now uses django-money fields entirely
- Create a manual rate exchange backend (needs more work!)
2020-11-11 00:21:06 +11:00
Oliver Walters
1fc2ef5f18 Custom migration for PartSellPriceBreak 2020-11-10 22:31:46 +11:00
Oliver Walters
83582ae87f Add custom migration for the part_supplierpricebreak model
- Copies across existing pricing data
- Yikes
2020-11-10 22:25:05 +11:00
Oliver Walters
e4f2eecb3b Remove defunct 'build_order' field from StockItem model
- This is now handled by the new-and-improved build system, no longer required
2020-11-10 20:12:39 +11:00
Oliver Walters
978fd7c683 Implement default currency selection
- Add 'choices' option to InvenTreeSetting class
- Add support for ChoiceField in InvenTreeSetting form
2020-11-10 17:08:08 +11:00
Oliver Walters
48c20c600a List supported currencies in the configuration template 2020-11-10 16:28:55 +11:00
Oliver Walters
734436b02e Add integration of django-money
- Proper currency support
- Add PurchasePrice field to StockItem model
- This keeps track of both the price and the currency
- Display purchase price on the stockitem detail page
2020-11-10 16:22:42 +11:00
Oliver
9d9ef5fc9c Merge pull request #1116 from SchrodingersGat/duplicate-ipn
Add setting to allow or prohibit duplicate IPN values
2020-11-10 10:52:30 +11:00
Oliver
9ac334ddd2 Merge pull request #1115 from eeintech/fix_form_errors
Fix for #1111 (missing logic to check for model errors)
2020-11-10 10:25:09 +11:00
Oliver Walters
a6028f027a Add setting to allow or prohibit duplicate IPN values 2020-11-10 09:03:26 +11:00
eeintech
b17b8db25c Fix for #1111 (missing logic) 2020-11-09 17:00:12 -05:00
Oliver
eead52a5dd Merge pull request #1114 from SchrodingersGat/part_options
Part options
2020-11-10 08:28:23 +11:00
Oliver Walters
7286281a06 Fix for unit testing 2020-11-10 07:14:38 +11:00
Oliver Walters
c4296ad4f1 Update migrations and translation 2020-11-09 23:47:31 +11:00
Oliver Walters
c95f124578 Add some helper magic for setting objects
- If the setting is defined as a "bool" then the returned value is automatically cast to a bool
- Add some more unit testing
2020-11-09 23:44:54 +11:00
Oliver Walters
75ab7b247b Push part settings into part/settings.py
- Use the user-configurable defaults in the database model itself
- This means they are observed even when using the API / etc
2020-11-09 23:16:04 +11:00
Oliver Walters
e1b70ff68f Add default values for create part form 2020-11-09 22:52:32 +11:00
Oliver Walters
8149759852 Add some more part options which set the default values for the following fields:
- Purchaseable
- Salable
- Trackable
2020-11-09 20:26:19 +11:00
Oliver
826c471179 Merge pull request #1107 from eeintech/fix_postgres_migration
Fix PostGreSQL migration (permissions handler)
2020-11-06 07:58:56 +11:00
Oliver
dadf4d4c13 Merge pull request #1110 from eeintech/order_save_fix
Fixed saving of purchase and sales order create forms
2020-11-06 07:53:41 +11:00
Oliver
d23444a86a Merge pull request #1111 from eeintech/disable_crispy_form_errors
Disable crispy form errors
2020-11-06 07:53:11 +11:00
eeintech
ba2da17f1e Disabled crispy form errors 2020-11-05 14:44:04 -05:00
eeintech
5b3dd63b89 Fixed saving of purchase and sales order forms 2020-11-05 14:38:54 -05:00
eeintech
684db67733 Added check for remove too 2020-11-05 09:37:01 -05:00
eeintech
0b76d1d036 Check if permission is not NoneType before adding to group 2020-11-05 09:34:18 -05:00
Oliver
15ea73a448 Merge pull request #1106 from SchrodingersGat/build-tabs
Rename tabs for build order
2020-11-05 20:39:25 +11:00
Oliver Walters
a35c4a5a95 Rename tabs for build order 2020-11-05 20:07:23 +11:00
Oliver
7e4b84f016 Merge pull request #1105 from SchrodingersGat/build-fix-fixes
Set the specified location of a build output
2020-11-05 18:25:00 +11:00
Oliver Walters
2591d34260 Fixed bug where "New output" button stopped working
- Build status was changing from "PENDING" to "PRODUCTION"
- Created new check for active builds
2020-11-05 15:57:46 +11:00
Oliver Walters
d44092b209 Fix issue with shadowed form field
- Rename "quantity" to "output_quantity" to address this
2020-11-05 15:52:38 +11:00
Oliver Walters
8b7789cdb3 Set the specified location of a build output 2020-11-05 15:46:42 +11:00
Oliver
6c89a2aaeb Merge pull request #1099 from eeintech/fix_related_parts
Fix PartRelated (based on updated AjaxCreateView class)
2020-11-05 09:51:06 +11:00
eeintech
324645b67c Added same level category checkbox and method when adding category template 2020-11-04 12:26:10 -05:00
eeintech
e401bb8e3c Improved tests, fixed admin, improved naming 2020-11-04 12:06:07 -05:00
eeintech
1c14c2237a Moved category templates processing to Part save() method 2020-11-04 09:52:26 -05:00
eeintech
9eba564ff6 Merge branch 'master' of git://github.com/inventree/InvenTree into categories_parameters 2020-11-04 07:52:16 -05:00
eeintech
142cea0cbb Removed custom form save method, remove unused model methods, restored InvenTree CreateAjaxView, improved part related testing 2020-11-04 07:44:06 -05:00
eeintech
853a821497 Merge branch 'master' of git://github.com/inventree/InvenTree into fix_related_parts 2020-11-04 06:46:20 -05:00
Oliver
dc626ed68b Merge pull request #1103 from SchrodingersGat/image-upload-fixes
Bug fix: Part thumbnail API list was not working
2020-11-04 16:24:04 +11:00
Oliver Walters
f560be1a9a Bug fix: Part thumbnail API list was not working
- Part images could not be selected from grid
2020-11-04 15:41:17 +11:00
Oliver
ede7d6dbde Merge pull request #1102 from SchrodingersGat/coveralls-fix
Updated to latest version of coverage and coveralls
2020-11-04 14:12:57 +11:00
Oliver Walters
5f6f722d6c Change from python-coveralls to coveralls 2020-11-04 13:30:17 +11:00
Oliver Walters
f8da15287c Updated to latest version of coverage and coveralls 2020-11-04 09:35:43 +11:00
Oliver
fc99086c8f Merge pull request #1101 from SchrodingersGat/delete-on-deplete-fix
Logic fix for editing stock item creation form
2020-11-04 09:33:52 +11:00
eeintech
4e157fe956 Fixed text for parent categories checkbox 2020-11-03 17:05:08 -05:00
eeintech
279d5a00ce Switched to get_ancestors to transverse all parents categories (not only root) 2020-11-03 16:58:53 -05:00
eeintech
5a5a36083e Finalized implementation when creating new part 2020-11-03 16:54:46 -05:00
Oliver Walters
56b287b2c8 Logic fix for editing stock item creation form 2020-11-04 08:29:09 +11:00
eeintech
72b5a105f8 Made all categories accessible for parameter templates configuration 2020-11-03 14:45:53 -05:00
eeintech
0882528b82 Missing class trailing space 2020-11-03 11:15:16 -05:00
eeintech
32b46cdc2a Added better PartRelated creation test 2020-11-03 11:14:31 -05:00
eeintech
de2b7e5daf Re-added post_save method in AjaxCreateView 2020-11-03 08:03:16 -05:00
eeintech
6b702ef676 Manually merged part migrations 2020-11-03 07:27:51 -05:00
Francois
b1885138de Merge branch 'master' into categories_parameters 2020-11-03 07:01:56 -05:00
Oliver
1e844c642f Merge pull request #1063 from SchrodingersGat/build-fixes
Build system updates
2020-11-03 22:58:38 +11:00
Oliver Walters
2e1a5a85a3 Bug fix for unit testing 2020-11-03 22:14:02 +11:00
Oliver Walters
3ea671986c Merge conflicting migration files 2020-11-03 21:29:25 +11:00
Oliver Walters
083dac1300 Merge remote-tracking branch 'inventree/master' into build-fixes 2020-11-03 21:26:39 +11:00
Oliver
1c503adced Merge pull request #1026 from eeintech/user_unique_group_validation
Added check for multiple groups assigned to user
2020-11-03 21:21:08 +11:00
Oliver
ef2c04baa8 Merge pull request #1048 from eeintech/related_parts
Related Parts
2020-11-03 21:18:27 +11:00
Oliver Walters
897d9b4831 Update translation files 2020-11-03 21:02:31 +11:00
Oliver Walters
5988e847ce Add serial number suggestions 2020-11-03 21:01:14 +11:00
Oliver Walters
8d0845d92b Mark a build as "production" whenever a build output is created 2020-11-03 20:43:49 +11:00
Oliver Walters
ac03dab8de Tweaks 2020-11-03 20:37:33 +11:00
Oliver Walters
2b91f69c7d Fix unit tests 2020-11-03 20:19:24 +11:00
Oliver Walters
b936f67d87 Various form fixes
- Updating forms, a lot has changed!
2020-11-03 16:21:40 +11:00
Oliver Walters
152801f06f Dramatic speed improvements for build completion
- Might still need to be a background task at some point..
2020-11-03 15:56:20 +11:00
Oliver Walters
3f03adba72 Bug fix for stock table
- Grouped rows were not displaying the part name
2020-11-03 15:05:13 +11:00
eeintech
13a07be728 Added PartCategoryParameterTemplate tests 2020-11-02 15:35:54 -05:00
eeintech
6320384ecb Fixed category parameter template edit form 2020-11-02 15:05:37 -05:00
eeintech
43fab8a8b3 Backtracked on setting category choices (fixed failed migration) 2020-11-02 13:28:34 -05:00
eeintech
34b784d1e4 Added setting, checkbox (PartCreateView only) and hook to create part parameters from category templates 2020-11-02 13:14:31 -05:00
eeintech
978b5f869d Added checkbox to add parameter template to all categories 2020-11-02 12:20:29 -05:00
Oliver Walters
05613b9642 Further build tweaks / improvements 2020-11-02 23:47:36 +11:00
Oliver Walters
f5d0d54ded Improve modal error message 2020-11-02 23:02:02 +11:00
Oliver Walters
500da8099b Add forms / views for creating a new build output, and completing the build
- Also some refactoring of how forms are handled and saved
2020-11-02 22:56:26 +11:00
Oliver Walters
b02c87ea50 Lots of work towards multiple build output 2020-11-02 01:24:31 +11:00
Oliver Walters
f1b83f1c17 Update fixtues for unit testing 2020-11-01 15:34:42 +11:00
eeintech
3a347fba21 Added edit/delete for category parameter templates 2020-10-31 12:55:52 -05:00
eeintech
2a563d7370 Added category list of parameter templates table to settings 2020-10-31 09:18:33 -05:00
eeintech
3e5d8d2b2d Added form to select category in settings and update context data 2020-10-31 08:35:47 -05:00
eeintech
5310ce8465 First step into managing Category Parameters to InvenTree settings 2020-10-30 17:17:18 -05:00
eeintech
34ff05d66e Created PartCategoryParameterTemplate model and admin interface 2020-10-30 16:09:27 -05:00
Oliver Walters
95fadf1300 Update unit testing 2020-10-30 23:08:12 +11:00
Oliver Walters
3a702266e6 Merge remote-tracking branch 'inventree/master' into build-fixes
# Conflicts:
#	InvenTree/InvenTree/views.py
#	InvenTree/build/views.py
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/order/views.py
#	InvenTree/part/api.py
#	InvenTree/part/views.py
#	InvenTree/templates/js/bom.js
2020-10-30 22:44:25 +11:00
Oliver
ad90adbc04 Merge pull request #1095 from SchrodingersGat/forms
Refactor how form errors are handled
2020-10-30 22:12:45 +11:00
Oliver Walters
1caa341f8e Fixes for unit tests 2020-10-30 21:34:56 +11:00
Oliver Walters
e049ca1a85 More refactoring 2020-10-30 16:54:05 +11:00
Oliver
87903f27ed Merge pull request #1094 from SchrodingersGat/typo-fix
Fixed a typo in bom.js
2020-10-30 16:23:07 +11:00
Oliver Walters
c533f59405 Refactor how form errors are handled
- Use form.add_error (as the django gods intended)
2020-10-30 16:04:56 +11:00
Oliver Walters
cabbdbb5cf Fixed a typo in bom.js 2020-10-30 15:53:13 +11:00
Oliver
fb28204dfd Merge pull request #1093 from SchrodingersGat/bom-filters
Add filtering for BOM table
2020-10-30 12:45:46 +11:00
Oliver Walters
2428e77969 Add filtering for BOM table 2020-10-30 11:45:54 +11:00
Oliver
1311e5fe58 Merge pull request #1092 from SchrodingersGat/copy-bom
Copy bom
2020-10-30 11:40:06 +11:00
Oliver Walters
5c5641d884 Update calls to post_save 2020-10-30 10:12:42 +11:00
Oliver Walters
2d583d19c2 Adds function to duplicate a BOM from a parent part
- Improves form validation workflow
- More 'djangoesque'
2020-10-30 10:08:06 +11:00
Oliver Walters
90cfb3496a Merge remote-tracking branch 'inventree/master' into build-fixes
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.mo
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/templates/js/bom.js
2020-10-29 15:23:51 +11:00
Oliver
a148cfe593 Merge pull request #1088 from SchrodingersGat/tweaks
Tweaks
2020-10-29 15:16:49 +11:00
Oliver Walters
1d6d1121a7 Add some more icons 2020-10-29 13:58:05 +11:00
Oliver Walters
f1a7ac3187 Add icon badges to bom.js 2020-10-29 13:26:32 +11:00
Oliver Walters
fda0bff14c Tweaks to part.js 2020-10-29 13:20:42 +11:00
Oliver Walters
8246e9c802 Add function makeIconBadge for tables
- Add filters for part variants table
2020-10-29 13:18:45 +11:00
Oliver Walters
b3ac261746 Add filter for supplier part table:
Filter by "active" status
2020-10-29 12:50:17 +11:00
Oliver Walters
60a8ef723b Simplify display of possible conflicting parts
- Round to single digit
- Only show 5 closest matches

(cherry picked from commit ed8be5225d)
2020-10-29 12:42:38 +11:00
Oliver Walters
05ce17f8df Tweaks 2020-10-29 09:45:42 +11:00
Oliver Walters
a263d2fdcd Fixes for "auto allocate" concept 2020-10-29 00:49:01 +11:00
Oliver Walters
551064b3a4 Bugfix: BOM API now works slightly differently 2020-10-29 00:07:51 +11:00
Oliver Walters
544b63cac5 Merge remote-tracking branch 'inventree/master' into build-fixes
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
2020-10-29 00:01:10 +11:00
Oliver Walters
4a7e9a2278 Update translations and PEP fixes 2020-10-28 23:59:18 +11:00
Oliver Walters
ed8be5225d Simplify display of possible conflicting parts
- Round to single digit
- Only show 5 closest matches
2020-10-28 23:48:35 +11:00
Oliver Walters
091a9d9803 Refactor how form errors are handled
- When in doubt, refer to the django docs
- There was a *much* better way (thanks, form.add_error)!
- The anti-pattern was deleted, and lo, there was much rejoicing
- Some other refactoring too
2020-10-28 23:33:33 +11:00
Oliver
6dc5ef0cdc Merge pull request #1085 from SchrodingersGat/more-icons
More template updates
2020-10-28 23:29:15 +11:00
Oliver Walters
d8ada930c8 More template updates
- Add icons to more action buttons
2020-10-28 22:37:58 +11:00
Oliver Walters
d06b4d7c9f Merge remote-tracking branch 'inventree/master' into build-fixes
# Conflicts:
#	InvenTree/InvenTree/urls.py
#	InvenTree/locale/de/LC_MESSAGES/django.mo
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/part/templates/part/bom.html
#	InvenTree/templates/js/build.js
#	InvenTree/templates/js/table_filters.js
#	InvenTree/templates/stock_table.html
#	tasks.py
2020-10-28 22:25:14 +11:00
Oliver
c8ec55a5fe Merge pull request #1084 from SchrodingersGat/used-in-table
Used in table
2020-10-28 21:21:44 +11:00
Oliver Walters
44010fe05b Translation updates 2020-10-28 18:30:50 +11:00
Oliver Walters
d0b7d91ca4 Update multiple templates with fontawesome icons 2020-10-28 18:30:38 +11:00
Oliver Walters
d272eec384 Update translation files 2020-10-28 18:13:19 +11:00
Oliver Walters
5e70d8df7e Rename javascript files from .html to .js 2020-10-28 18:13:02 +11:00
Oliver Walters
c63480c65b Improve table for displaying what parts a particular part is "used in" 2020-10-28 18:12:38 +11:00
Oliver Walters
3ec2396ec1 Updated allocation card view 2020-10-27 23:33:51 +11:00
Oliver Walters
22a5f921b8 Auto-generate build outputs when a build is created 2020-10-27 23:09:17 +11:00
Oliver Walters
170d55d64e Add custom form validation step 2020-10-27 22:52:01 +11:00
Oliver Walters
4055a36db2 Updated modal forms 2020-10-27 22:29:34 +11:00
Oliver Walters
646fe40950 Require either serial or batch number to be set for trackable part 2020-10-27 22:00:38 +11:00
Oliver Walters
54d5d2899e Update javascript callbacks 2020-10-27 21:47:24 +11:00
Oliver
43907fb129 Merge pull request #1082 from jnewlands/typo_fix_external_link
Fix typo in new / edit part forms ("extenel URL")
2020-10-27 16:43:14 +11:00
James Newlands
c61eeca3e4 Even though nothing happened to the database schema, the field description changed 2020-10-27 15:58:05 +11:00
James Newlands
8bf281e153 Fix typo in new / edit part forms ("extenel URL")
Capitalisation consistency in "Create New Part" form title
2020-10-27 14:52:31 +11:00
Oliver Walters
06a3899325 Disable "unallocate" button if there are not any allocations 2020-10-27 09:26:16 +11:00
Oliver Walters
b5e1d3f87a Sorter fixes 2020-10-27 08:58:29 +11:00
Oliver
9ed787b4da Merge pull request #1077 from SchrodingersGat/custom-tag-fix
Bug fix - re-introduce settings_value custom tag
2020-10-27 07:49:12 +11:00
Oliver Walters
4167e1fdb3 Update translation files 2020-10-26 22:51:57 +11:00
Oliver Walters
210d39c8b7 Bug fix - re-introduce settings_value custom tag
(cherry picked from commit 9203f541be)
2020-10-26 22:44:49 +11:00
Oliver Walters
d8a0ab8879 Fix for build table 2020-10-26 22:44:24 +11:00
Oliver Walters
9203f541be Bug fix - re-introduce settings_value custom tag 2020-10-26 22:44:16 +11:00
Oliver Walters
a4f6efc05d Merge remote-tracking branch 'inventree/master' into build-fixes
# Conflicts:
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/templates/js/build.html
2020-10-26 22:38:43 +11:00
Oliver Walters
b38fde85f2 Added some more buttons, etc 2020-10-26 22:34:40 +11:00
Oliver Walters
5e0d1fe25a Allocate "non tracked" parts separately from tracked ones 2020-10-26 18:21:45 +11:00
Oliver Walters
7525bc2ead Attachment functionality for BuildOrder 2020-10-26 17:00:31 +11:00
Oliver Walters
664dd0000c Add database table for storing file attachments against a BuildOrder 2020-10-26 15:21:03 +11:00
Oliver Walters
8f108d42d2 Add ability to filter BOM status by "validated" field 2020-10-26 14:43:43 +11:00
Oliver Walters
24ab48ef4c Filter BOM table by "trackable" status 2020-10-26 13:53:34 +11:00
Oliver Walters
1a4eb3f870 Display which parts are "trackable" in a BOM table 2020-10-26 13:24:17 +11:00
Oliver Walters
815d4bf7eb Add new template_tag for defining variables 2020-10-26 09:11:25 +11:00
Oliver Walters
ffe15763a7 Update validation "rules" for BuildItem
- A BuildItem which points to a trackable part must also point to a build output
- A BuildItem which points to a non-trackable part cannot point to a build output
2020-10-26 08:34:17 +11:00
Oliver Walters
6aaf178f0b Check "trackable" status of part
- Where a BomItem connects a trackable sub_part with a non-trackable part, force the Part to be trackable
2020-10-26 08:29:06 +11:00
Oliver
720579dcd7 Merge pull request #1070 from SchrodingersGat/global-settings
Global settings
2020-10-25 22:22:57 +11:00
Oliver Walters
e978e1df52 Style fixes 2020-10-25 22:11:24 +11:00
Oliver Walters
5908890726 Create setting if it does not exist 2020-10-25 22:07:11 +11:00
Oliver Walters
549f50ac3f Update translations 2020-10-25 21:54:53 +11:00
Oliver Walters
9284837da8 Bug fixing 2020-10-25 21:45:37 +11:00
Oliver Walters
7d95faa4f5 Cleanup code 2020-10-25 21:43:33 +11:00
Oliver Walters
432ecc1d96 Display boolean values as checkboxes 2020-10-25 21:33:13 +11:00
Oliver Walters
3a325399c6 Use a checkbox input when editing a boolean setting 2020-10-25 21:00:06 +11:00
Oliver Walters
f1e8afa314 Add boolean validator 2020-10-25 09:36:58 +11:00
Oliver Walters
73296eafcb Update translation files 2020-10-25 08:18:33 +11:00
Oliver Walters
4d96b385b1 Add page for global settings 2020-10-25 08:17:41 +11:00
Oliver Walters
b57a78dea4 Add some context data to the view for editing a setting 2020-10-25 08:10:52 +11:00
Oliver Walters
e3f5e8fbb1 PEP fixes 2020-10-25 08:04:04 +11:00
Oliver Walters
3e17bf3316 Edit setting directly 2020-10-25 08:02:46 +11:00
Oliver Walters
10758a9626 Improvements for global settings
- Name and description are defined in models.py
- Lookup functions for name / description / units / default
- Shortcut template for rending settings
- More unit testing
2020-10-25 07:49:38 +11:00
Oliver Walters
767ceed698 Update translation files 2020-10-24 22:13:40 +11:00
Oliver Walters
c63a09330f Hide some buttons if row is fully allocated already 2020-10-24 22:05:19 +11:00
Oliver Walters
42c1210fba Calculate required build quantity 2020-10-24 13:16:43 +11:00
Oliver Walters
a3265ef9fd Unallocate stock against a particular line item 2020-10-24 13:15:13 +11:00
Oliver Walters
b7e7543be6 Add some more buttons to build table 2020-10-24 12:59:05 +11:00
Oliver Walters
b45a11aa3d Refactor: Add "makeIconBadge" javascript function 2020-10-24 00:33:30 +11:00
Oliver Walters
ea7b1b65d6 Delete a build output entirely
TODO: Needs to describe in the confirmation dialog what is going to happen!
2020-10-24 00:14:27 +11:00
Oliver Walters
a71a51b848 Build can be "unallocated" against a single build output 2020-10-23 23:52:59 +11:00
Oliver Walters
fb7d9a7edf Move "getAvailableStockItems" to the build model 2020-10-23 23:33:27 +11:00
Oliver Walters
0752df26dc Bug fixes for BuildItemCreate view:
- Add option to calculate required quantity against a particular build output, not just the build
2020-10-23 23:09:22 +11:00
Oliver Walters
076d5c4f7f Cleanup get_required_parts function 2020-10-23 22:49:46 +11:00
Oliver
5e63ccc9f6 Merge pull request #1043 from eeintech/unique_email_company
[Company] Allow duplicate names - Unique name/email pair
2020-10-23 13:23:48 +11:00
Oliver
cd4cb12937 Merge pull request #1064 from eeintech/company_permissions
Company permissions
2020-10-23 13:20:59 +11:00
eeintech
647182237e Merge branch 'master' of git://github.com/inventree/InvenTree into unique_email_company 2020-10-22 12:05:22 -05:00
Oliver Walters
5db043ab4b Launch modal dialog to auto-allocate against a specific build output 2020-10-23 01:05:59 +11:00
Oliver Walters
f4f6253178 Better table sorting for allocation quantity 2020-10-23 00:58:35 +11:00
Oliver Walters
33c454ed5a Add action buttons to each build output 2020-10-23 00:51:01 +11:00
Oliver Walters
6245d65ebc Tweaks 2020-10-23 00:08:40 +11:00
Oliver Walters
23ac83d2a8 Change extension on "dynamic" js files
- Yay, the editor now highlights code properly!
2020-10-22 23:59:21 +11:00
Oliver Walters
ae20db0ec6 Add actions for the sub-table allocation list 2020-10-22 23:57:07 +11:00
Oliver Walters
d37cdd8e50 Improved filtering for stockitems going into a buildallocation 2020-10-22 23:49:23 +11:00
Oliver Walters
fae516b38e Add build output selection to builditem creation form 2020-10-22 23:28:15 +11:00
Oliver Walters
1ca08f8bff Filter builditem API by 'output' stock item 2020-10-22 21:43:53 +11:00
Oliver
5877b9616d Merge pull request #1066 from eeintech/fix_part_null_notes_template
Fixed Part notes template (check for NULL value before mardown render)
2020-10-22 09:53:15 +11:00
eeintech
9131edc43d Company index: swapped 'title' for 'pagetype' for adding company button 2020-10-21 09:34:49 -05:00
eeintech
1ef21700c0 Fixed Part notes template (check for NULL value before mardown render) 2020-10-21 09:26:07 -05:00
Oliver Walters
f989d3b3ec Change to using spinner icon 2020-10-21 17:02:04 +11:00
eeintech
46b889c572 Assigned all user permissions for company tests 2020-10-20 14:52:34 -05:00
eeintech
de65e1631d Updated company templates permissions 2020-10-20 14:46:10 -05:00
eeintech
39eddc7203 Added user permissions on company views 2020-10-20 14:11:40 -05:00
Oliver Walters
96277edcf1 Improvements to progress bar function 2020-10-21 00:49:17 +11:00
Oliver Walters
8ae16a125e Build - Add functions to access build outputs 2020-10-21 00:24:55 +11:00
Oliver Walters
e02536071d Add a "completed" field to the Build model
- Keeps track of how many outputs have been produced
- Will not be directly editable by the user
2020-10-20 23:59:37 +11:00
Oliver Walters
fd6d630037 Improve grouping in Stock table 2020-10-20 23:45:36 +11:00
eeintech
5793839a01 Added UniqueConstraint on name/email pair, renamed migration file 2020-10-20 07:37:07 -05:00
Oliver Walters
3bb247a135 Create an initial stockitem output when a new build is created 2020-10-20 23:27:43 +11:00
eeintech
7bc925d016 Merge branch 'master' of git://github.com/inventree/InvenTree into unique_email_company 2020-10-20 07:19:48 -05:00
Oliver Walters
652c2dbcbe Automagically disable 'serial_numbers' field for StockItemCreate form
- Yay, ajax magic!
2020-10-20 22:37:55 +11:00
Oliver Walters
2e4613e702 Updates to build forms / etc 2020-10-20 22:37:21 +11:00
Oliver Walters
2df0f03a9a Change "ALLOCATED" to "PRODUCTION" 2020-10-20 21:10:36 +11:00
Oliver Walters
ac79e131bc Add "destination" field to BuildOrder 2020-10-20 21:01:51 +11:00
Oliver Walters
28460b3023 Validate that the BuildItem quantity is an integer 2020-10-20 20:42:29 +11:00
Oliver Walters
fdcef7b699 Add "install_into" field for BuildItem
- Points to which output stock item it will be going into
2020-10-20 20:37:57 +11:00
Oliver
bc6f58cf26 Merge pull request #1061 from SchrodingersGat/migration-fix
Except IntegrityError
2020-10-20 20:35:59 +11:00
Oliver Walters
4193d2e7fe Except IntegrityError
- This error may be thrown if the correct migrations have not been applied
2020-10-20 19:52:04 +11:00
Oliver
85ac1bfb95 Merge pull request #1058 from SchrodingersGat/stock-table-ordering
Fix table sorting when groups are used.
2020-10-20 12:07:11 +11:00
Oliver Walters
73a1765a11 Fix table sorting when groups are used.
This is necessary because the field names of the tables are specified like "part_detail.IPN" and multi-level string-based object access is weird.
Luckily someone has worked out the hard part for me.

Ref: https://stackoverflow.com/questions/6393943/convert-javascript-string-in-dot-notation-into-an-object-reference
2020-10-20 11:54:54 +11:00
Oliver
d242e04e64 Merge pull request #1055 from SchrodingersGat/build-reference
Build reference
2020-10-20 09:03:25 +11:00
Oliver Walters
a2ee172058 Updates tables for PurchaseOrder and SalesOrder 2020-10-20 08:45:17 +11:00
Oliver Walters
5a6697866f Update translations 2020-10-20 08:41:13 +11:00
Oliver Walters
406d7bcf80 Load build order prefix setting 2020-10-20 08:41:08 +11:00
Oliver Walters
7aa473712f Remove unused setting page 2020-10-20 08:32:00 +11:00
Oliver Walters
226a91718b Add a simple unit test for the settings model 2020-10-20 08:29:06 +11:00
Oliver Walters
c6e61c20fe Generate default settings for all InvenTreeSetting object 2020-10-20 08:24:23 +11:00
Oliver Walters
98d20bceeb Change "Build Title" to "Description" 2020-10-20 00:26:26 +11:00
Oliver Walters
e8a0095e50 Add some options for the build order settings page
- Not editable yet
2020-10-20 00:24:33 +11:00
Oliver Walters
a5639c380f Add regex validator to build order reference field 2020-10-20 00:13:43 +11:00
Oliver Walters
06040f94ee Remove "description" field from InvenTreeSettings key:value fields 2020-10-20 00:02:54 +11:00
Oliver Walters
92c1e3c1a5 Update settings pages 2020-10-19 23:50:39 +11:00
Oliver Walters
c13cee2407 Fixes for unit testing 2020-10-19 23:31:52 +11:00
Oliver Walters
9b7a9a3ee0 Update formatting of order pages 2020-10-19 23:23:16 +11:00
Oliver Walters
b5d15aab08 Add function to "predict" next build order reference value 2020-10-19 23:22:09 +11:00
Oliver Walters
5405ad566e Add 'reference' to API serializer 2020-10-19 22:53:40 +11:00
Oliver Walters
0b7cf9e7f3 Add "reference" to build order forms 2020-10-19 22:49:28 +11:00
Oliver Walters
a8d47c54f9 Upate admin interface 2020-10-19 22:40:19 +11:00
Oliver Walters
934078a42c Add "Reference" field to Build model 2020-10-19 22:36:14 +11:00
Oliver
416cfb99da Merge pull request #1053 from SchrodingersGat/modal-errors
Modal errors
2020-10-19 22:19:10 +11:00
Oliver Walters
6b99d923d7 Change "status code" to "error code" 2020-10-19 16:44:33 +11:00
Oliver Walters
396b7dba73 Extra error information when a modal dialog fails 2020-10-19 16:42:53 +11:00
Oliver
957c538136 Merge pull request #1052 from SchrodingersGat/barcode-add
Change text for barcode
2020-10-19 16:31:47 +11:00
Oliver Walters
647e2cf64d Change text for barcode 2020-10-19 16:06:18 +11:00
Oliver
ce1cce99bb Merge pull request #1051 from SchrodingersGat/po-stock-list
Display table of items received against a particular purchase order
2020-10-19 11:55:25 +11:00
Oliver Walters
634410294b Display table of items received against a particular purchase order
- Adds new tab to "Purchase Order" view
- Adds ability to filter StockList API by purchase_order ID
2020-10-19 11:40:57 +11:00
Oliver
2dc9109b11 Merge pull request #1047 from eeintech/add_ipn_supplier_part_str
Added IPN to Supplier Part string representation (global)
2020-10-19 11:21:34 +11:00
eeintech
dfa4d3f8ed Display IPN and pipe char only if IPN exists 2020-10-18 14:37:35 -05:00
eeintech
d1df647dde Merge branch 'master' of git://github.com/inventree/InvenTree into add_ipn_supplier_part_str 2020-10-18 14:33:38 -05:00
Oliver
529c4052ff Merge pull request #1038 from mpdgraev/fix_int_barcode
fix error when submitting some non-dict barcodes
2020-10-19 00:01:38 +11:00
Oliver
7edd08035f Merge pull request #1049 from SchrodingersGat/api-default-location
Update creation of StockItem via API
2020-10-18 22:49:09 +11:00
Oliver Walters
3c175a6c8d Update creation of StockItem via API
- If no location is specified, but a default location exists for the part, use that
- If a location is specified (even if it is null) then the specified value is used instead
2020-10-18 22:24:45 +11:00
Oliver
83077514cb Merge pull request #1041 from eeintech/api_default_location
Added part 'default_location' to serializer
2020-10-18 22:01:35 +11:00
Oliver
4d4f0e5cfc Merge pull request #1044 from eeintech/stock_permissions
Fixed insertion of backslash in the Stock barcode button group
2020-10-18 21:11:09 +11:00
eeintech
5a6cac43f5 Updated migration 2020-10-16 15:42:23 -05:00
eeintech
0b26d68d0f Added admin view, improved validation of part related relationship 2020-10-16 15:29:58 -05:00
eeintech
34e4409e7f Functional checkpoint: add/delete related parts from template 2020-10-16 13:50:31 -05:00
eeintech
8579abb9c2 Added related parts urls, views, form and templates
Adding related part relationships work but are still not shown in the part detail page
2020-10-15 16:58:39 -05:00
eeintech
3d9223c2ee Introduced PartRelated model to store part relationships 2020-10-15 14:11:24 -05:00
eeintech
af6b30eaca Added IPN to Supplier Part string representation
Improved Supplier Part templates and fixed 'Order Part' button in supplier_part_orders
2020-10-15 13:09:00 -05:00
eeintech
dbee26aaad Fixed insertion of backslash in the barcode button group 2020-10-13 10:29:34 -05:00
eeintech
70a3b7f891 Improved migration, still fails if email duplicates exist in current DB 2020-10-13 07:43:57 -05:00
eeintech
ac82640c6c Company: allowed duplicate names, made email field unique, custom migration 2020-10-12 17:51:48 -05:00
eeintech
3143242d13 Added category 'default_location' to serializer 2020-10-12 13:14:24 -05:00
eeintech
eb98496a79 Added part 'default_location' to serializer 2020-10-12 07:25:32 -05:00
mpdgraev
f1f31a1338 fix error caused by assumption that json.loads() returns an object with a .keys() function 2020-10-09 16:32:54 +02:00
Oliver
ca8472ac23 Merge pull request #1037 from SchrodingersGat/tz-support
Add support for setting timezone in config.yaml
2020-10-08 21:35:36 +11:00
Oliver Walters
3d60bccae0 Add support for setting timezone in config.yaml 2020-10-08 21:02:38 +11:00
Oliver
26ee3032f6 Merge pull request #1036 from SchrodingersGat/bom-quantity-export
Normalize quantity field when exporting BOM
2020-10-08 14:21:50 +11:00
Oliver Walters
8b16304e84 Custom 404 page 2020-10-08 14:09:08 +11:00
Oliver Walters
b595f3b732 Normalize quantity field when exporting BOM 2020-10-08 14:05:55 +11:00
Oliver
305920d1ac Merge pull request #1030 from eeintech/stock_permissions
Stock permissions
2020-10-07 14:11:52 +11:00
Oliver
ec4bc357df Merge pull request #1031 from eeintech/fix_superuser_permission
Fixed context permissions for superuser with no group assigned
2020-10-07 13:40:59 +11:00
eeintech
01eee4d208 Fixed style 2020-10-06 10:40:58 -05:00
eeintech
8499ced636 Changed from validation error to warning message when group instance is saved 2020-10-06 10:38:06 -05:00
eeintech
19a2326638 Merge branch 'master' of git://github.com/inventree/InvenTree into user_unique_group_validation 2020-10-06 10:04:35 -05:00
eeintech
1ce2166843 Fixed context permissions for superuser with no group assigned 2020-10-06 09:59:51 -05:00
eeintech
5bcf8529ff Only users with Part view permission have part URL shown 2020-10-06 09:16:38 -05:00
eeintech
e4ce19d22a Added Test user and all permissions 2020-10-06 09:02:10 -05:00
eeintech
095cfe9845 Updated Stock permission views and templates 2020-10-06 08:55:40 -05:00
Oliver
279b50d977 Merge pull request #1029 from SchrodingersGat/sales-order-permissions
Sales order permissions
2020-10-06 20:44:01 +11:00
Oliver Walters
8b37229e4b The real translations are the ones we made along the way 2020-10-06 20:31:38 +11:00
Oliver Walters
b80e4302ba Update permissions for build app 2020-10-06 20:29:16 +11:00
Oliver Walters
2325b1e4ba Unit test fixes 2020-10-06 20:10:14 +11:00
Oliver Walters
9abb211cdf Update template permissions 2020-10-06 20:09:55 +11:00
Oliver Walters
1c97aaf87a Set permissions for order views 2020-10-06 19:46:53 +11:00
Oliver
606c62078f Merge pull request #1024 from SchrodingersGat/part-permissions
Permissions
2020-10-06 18:29:05 +11:00
Oliver Walters
ab454e5ba4 More template changes: perms -> roles 2020-10-06 16:46:13 +11:00
Oliver Walters
88f73443ee Yet more style fixes 2020-10-06 16:43:39 +11:00
Oliver Walters
77a2b6de8b Merge branch 'part-permissions' of https://github.com/SchrodingersGat/InvenTree into part-permissions 2020-10-06 16:03:33 +11:00
Oliver Walters
b3e4efd96e Unit testing fixes 2020-10-06 16:03:19 +11:00
Oliver
e076470305 Merge branch 'master' into part-permissions 2020-10-06 12:35:45 +11:00
Oliver Walters
d691b15f4b Fix conflicts 2020-10-06 12:34:30 +11:00
Oliver Walters
11d31960c7 Change modal form permissions to use new "role" strategy 2020-10-06 11:42:16 +11:00
Oliver Walters
c740cce5e4 PEP fixes 2020-10-06 11:31:04 +11:00
Oliver Walters
dc2c9aa662 Add InvenTreeRoleMixin
- Simplifies permission requirements for views
- e.g. 'part.view' rather than 'part.view_partcategory'
2020-10-06 11:29:38 +11:00
Oliver Walters
d2e2e7511f Update templates: Change perms to roles 2020-10-06 10:07:39 +11:00
Oliver Walters
fa21d66c41 Fix logic for global context object 'roles'
- User may be a part of multiple groups
- Roles are additive across groups
2020-10-06 09:54:37 +11:00
Oliver Walters
23aee234f0 Change index page to use roles rather than perms to determine user permissions 2020-10-06 09:32:05 +11:00
Oliver Walters
556ffa1099 Change label for permissions to match django permission names 2020-10-06 09:28:05 +11:00
Oliver Walters
8b2189daca Add global context 'roles'
- Access via template e.g. {% if roles.part.view %}
- Always True if the user is a superuser
2020-10-06 09:27:22 +11:00
Oliver
e74bfb90a5 Merge pull request #1025 from eeintech/fixed_group_redundant_saves
Fixed Group model permissions redundant saves
2020-10-06 07:40:44 +11:00
eeintech
911b23ca24 Added validation logic for user list to Group admin form 2020-10-05 13:12:52 -05:00
eeintech
d980da7247 Fixed permission assign test unit 2020-10-05 10:52:47 -05:00
eeintech
c910307ce5 Only saving Group model rulesets on instance creation and when inlines are saved 2020-10-05 10:04:54 -05:00
Oliver Walters
3f59ce3f93 Update unit tests
- requires the user to actually have the necessary permissions!
2020-10-06 01:30:36 +11:00
Oliver Walters
16d720b62c Update permission requirements for API
- Automatically use model permissions by default!
-
2020-10-06 00:36:55 +11:00
Oliver Walters
8ee16d6f98 update translation files 2020-10-06 00:20:57 +11:00
Oliver Walters
ba4c829b10 Add permission requirements in various part templates 2020-10-06 00:20:45 +11:00
Oliver Walters
afadd51a14 Fix permissions in views.py
Silly, "add" not "create"
2020-10-06 00:19:44 +11:00
Oliver Walters
66bdce3d04 Hide elements on the PartCategory page, based on permissions 2020-10-05 23:53:24 +11:00
Oliver Walters
4d49cb029f Change part views to require permissions
Also adds custom 403 page
2020-10-05 23:49:32 +11:00
Oliver
796e89c921 Merge pull request #1023 from SchrodingersGat/index-permissions
Change what elements the user can see on the index page
2020-10-05 23:19:13 +11:00
Oliver Walters
3e9c7cda21 Change what elements the user can see on the index page, based on permissions! 2020-10-05 23:11:55 +11:00
Oliver
e5960f6ce4 Merge pull request #1022 from SchrodingersGat/permission-fixes
Fixes for role permissions
2020-10-05 23:04:50 +11:00
Oliver Walters
806a7f961d Fixes for role permissions
- Fixed a strange interaction if multiple rulesets referred to the same models
- Order of operations was incorrect.
- Now is good? Yes!
2020-10-05 22:57:05 +11:00
Oliver
731c796254 Merge pull request #1011 from SchrodingersGat/navbar-permissions
Hide main elements of navigation bar based on user permissions
2020-10-05 11:17:41 +11:00
Oliver
dc41231fcc Merge pull request #1018 from SchrodingersGat/group-roles
Roles and Permissions
2020-10-05 11:16:52 +11:00
Oliver
cc05220263 Merge pull request #1020 from SchrodingersGat/stock-building
Add "is_building" field to StockItem model
2020-10-05 10:08:40 +11:00
Oliver Walters
898c604b3b Fix incorrect permission names
- Uses the app_model name, *NOT* the name of the database table
- Adds extra tests to ensure that permissions get assigned and removed correctly
2020-10-05 08:55:15 +11:00
Oliver Walters
095ef51991 Cleanup unit testing 2020-10-05 08:29:36 +11:00
Oliver Walters
bce7eb1aad update translation files 2020-10-05 01:02:36 +11:00
Oliver Walters
13cd8624b2 Fix permissions 2020-10-05 01:01:56 +11:00
Oliver Walters
48e050d317 Add some more unit tests and validation code for the StockItem model
- Ensure that the build part matches the stockitem part!
2020-10-05 00:49:00 +11:00
Oliver Walters
3ee7be1d58 Add "optional" field to BomItem
- Defaults to False
- Indicates that the BomItem is "optional" for a build
- Will be used in the future when calculating if a Build output is fully allocated!
2020-10-05 00:42:09 +11:00
Oliver Walters
c1595396c4 Unit testing: fix PEP issues 2020-10-05 00:29:31 +11:00
Oliver Walters
fe3a72c6cc Add some unit testing 2020-10-05 00:29:06 +11:00
Oliver Walters
26d113e8ad Update IN_STOCK_FILTER to reject stock items which have is_building set to True 2020-10-05 00:14:04 +11:00
Oliver Walters
ee28b4eea5 Add "is_building" field to StockItem model
- This will be set to TRUE until a stock item has been completed
2020-10-05 00:12:42 +11:00
Oliver
7f3ce9b0b1 Merge pull request #1019 from SchrodingersGat/installed-stock-improvements
Improvements for the "Installed Items" tab for StockItem display
2020-10-05 00:09:23 +11:00
Oliver Walters
62734c4b72 Add a custom template for the install item form 2020-10-05 00:01:01 +11:00
Oliver Walters
3fe0886207 Remove a debug statement 2020-10-04 23:49:01 +11:00
Oliver Walters
852da6d696 Fix form validation 2020-10-04 23:48:15 +11:00
Oliver Walters
42a75a8238 Add hidden input to the InstallStockForm form
- keeps track of "part" object
- so we can filter the stock_items queryset if the form validation fails
- Is there a more djangonic way of doing this??
2020-10-04 23:45:52 +11:00
Oliver Walters
46f459b4c7 Better display of stock table 2020-10-04 23:34:02 +11:00
Oliver Walters
b9291c6705 Improve transaction note recording for the StockItem model 2020-10-04 23:33:43 +11:00
Oliver Walters
824ce6778f Progress bar tweaks
- If no maximum value supplied, just show the value (and fill to 100% width)
2020-10-04 23:33:20 +11:00
Oliver Walters
3c5968ef1a Add subrow table to the "installed items" view
Ah, javascript...
2020-10-04 22:58:41 +11:00
Oliver Walters
9c27680202 Finish function to install stock item(s) 2020-10-04 21:32:21 +11:00
Oliver Walters
45c888e13d Custom cleaning for form
Ok, looks like I've been doing this wrong the whole time!
The "djangonic" way is pretty cool
2020-10-04 21:31:44 +11:00
Oliver Walters
a686500df1 Calculate initial values for the view 2020-10-04 21:02:20 +11:00
Oliver Walters
fd22e713ff Filter available stock items by Part reference 2020-10-04 20:50:06 +11:00
Oliver Walters
f04977e7e1 Add form / view for installing a stock item into another stock item 2020-10-04 20:41:28 +11:00
Oliver Walters
b467c8a1ef Add front-end functions to render an "installed stock" table 2020-10-04 15:17:46 +11:00
Oliver Walters
b27f926310 Add ability to filter BOM API by "trackable" status of the sub_part object 2020-10-04 13:51:52 +11:00
Oliver Walters
fb09f53dc9 Add missing migration file 2020-10-04 12:58:45 +11:00
Oliver Walters
929411e49a Remove "general" ruleset 2020-10-04 12:53:24 +11:00
Oliver Walters
31b699d521 Hide "user permissions" view from the admin interface 2020-10-04 12:47:19 +11:00
Oliver Walters
cda52a58e3 Remove manual 'permissions' control from groups admin interface
- Does not actually *do* anything any more as the RuleSet approach overrides it anyway
2020-10-04 12:19:56 +11:00
Oliver Walters
c19c014f55 Add or remove permissions from groups as defined by the RuleSet links
- Only runs when the group is changed
- Does not add permissions if they already exist
- Does not remove permissions if they do not exist
2020-10-04 12:18:31 +11:00
Oliver Walters
d5c0c12d78 Add some more unit testing
- ALL models must be covered by rulesets
- Added a RULESET_IGNORE list for models we do not want permissions for
2020-10-04 11:03:14 +11:00
Oliver Walters
c09b4980ad PEP fixes 2020-10-04 00:43:02 +10:00
Oliver Walters
1ded9e1fc0 Add a warning showing which databases tables are not covered by defined rulesets 2020-10-04 00:38:53 +10:00
Oliver Walters
6c2eb959a6 More unit testing 2020-10-04 00:34:22 +10:00
Oliver Walters
2039100d3e Add some unit testing 2020-10-04 00:24:48 +10:00
Oliver Walters
6bc5fe2497 Tab fix 2020-10-04 00:03:10 +10:00
Oliver Walters
9e4cc73b1c Add migration files 2020-10-04 00:01:18 +10:00
Oliver Walters
16f1b4c784 Add hook to update group permission roles
(doesn't do anything yet)
2020-10-03 23:45:24 +10:00
Oliver Walters
bedda66949 Add custom admin view for the "Group" model
- Ref: https://github.com/Microdisseny/django-groupadmin-users
- Adds ability to edit users within a particular group from the group admin page!
2020-10-03 17:37:20 +10:00
Oliver
d81aa5c051 Merge pull request #1017 from SchrodingersGat/admin-shell
Add shell interface
2020-10-03 16:24:55 +10:00
Oliver Walters
c7403fd512 Add shell interface 2020-10-03 16:18:03 +10:00
Oliver
e6526288cd Merge pull request #1013 from SchrodingersGat/next-available-fix
Fix for "next avilable serial number" string
2020-10-02 14:01:25 +10:00
Oliver Walters
f12f8156bd Fix for "next avilable serial number" string 2020-10-02 13:54:23 +10:00
Oliver
7f3018ebf8 Merge pull request #1008 from eeintech/parametric_part_tables
Add parametric part tables to category detail page
2020-10-02 08:56:05 +10:00
eeintech
496232ed6d Added tests for Category parameters methods, some code clean-up 2020-10-01 13:46:56 -05:00
eeintech
9d3d9a190b Added bootstrap table 'filter-control' extension to use in parametric tables 2020-10-01 12:10:35 -05:00
eeintech
15e1c05791 Fixed 'Part' column sorting 2020-10-01 11:05:08 -05:00
eeintech
b7d25a75c4 Hide part toolbar, nicer part representation, improved parameters prefetching 2020-10-01 10:03:49 -05:00
eeintech
a71b5ef0a0 Merge branch 'master' of git://github.com/inventree/InvenTree into parametric_part_tables 2020-10-01 09:02:21 -05:00
Oliver
7356fc3dfc Merge pull request #1002 from eeintech/empty_search_query
Empty search query returned all elements from database
2020-10-01 09:34:02 +10:00
eeintech
4763f3ea46 Reformulated empty query message 2020-09-30 11:53:14 -05:00
eeintech
87d836617e Merge branch 'master' of git://github.com/inventree/InvenTree into empty_search_query 2020-09-30 11:50:12 -05:00
Oliver
4f648f8787 Merge pull request #1010 from SchrodingersGat/admin-permission-fixes
Update admin links to require specific permissions
2020-10-01 00:37:43 +10:00
Oliver Walters
756f3ddb0f Hide main elements of navigation bar based on user permissions 2020-10-01 00:25:24 +10:00
Oliver Walters
626d0266c8 Add framework for required permissions for any ajax modal forms
- Default permissions of "*" will not immediately change any modal forms
- Set the permission_required attribute of any modal form for this to be implemented
2020-10-01 00:16:04 +10:00
Oliver Walters
56660d52f2 Add "permission denied" message on modal forms 2020-10-01 00:09:21 +10:00
Oliver Walters
81864a6ab8 Fix button layout for stock table 2020-10-01 00:00:37 +10:00
Oliver Walters
27656633df Update admin links to require specific permissions 2020-09-30 23:57:23 +10:00
Oliver
400f183597 Merge pull request #1009 from SchrodingersGat/ipn-filter
Add filtering for parts which have an IPN set
2020-09-30 23:55:27 +10:00
Oliver Walters
a952dc38a3 Add filtering for parts which have an IPN set 2020-09-30 23:35:39 +10:00
Oliver
c4cae02170 Update version.py 2020-09-30 08:06:58 +10:00
Oliver
8ea2c627c4 Update version.py
Bump version number for release
2020-09-30 08:06:37 +10:00
Oliver
064a142d76 Merge pull request #1006 from SchrodingersGat/install_into
UI stuff
2020-09-30 08:03:34 +10:00
Oliver Walters
4f1d087654 PEP fix 2020-09-30 07:56:44 +10:00
eeintech
40d8a07acc Now loading data! Still need to be bonified 2020-09-29 16:49:53 -05:00
eeintech
d05a5978a0 Unique parameters names from category makes it to bootstrap table 2020-09-29 16:13:08 -05:00
eeintech
6b48977e7b Added 'Parametric Table' tab to category detail view, added part_count to 'Parts' tab 2020-09-29 15:16:12 -05:00
Oliver Walters
d1cce7df94 Add direct admin links if the user is staff 2020-09-30 00:02:10 +10:00
Oliver Walters
0e5f10c020 Add some more search terms to the admin interface 2020-09-29 23:41:50 +10:00
Oliver Walters
1f6cbd7408 Add action to uninstall a particular stock item 2020-09-29 23:11:37 +10:00
eeintech
18e19d7920 Empty search query returned all elements from database 2020-09-28 16:34:41 -05:00
Oliver
9e4a599c44 Merge pull request #1001 from SchrodingersGat/index-fix
Change layout for the index page
2020-09-28 22:23:08 +10:00
Oliver Walters
e78e649aa9 Change layout for the index page
- Expanding one table doesn't force the neighbouring one to be expanded also
2020-09-28 22:22:48 +10:00
Oliver
41d6ad2db9 Merge pull request #1000 from SchrodingersGat/installed-in
Installed in
2020-09-28 22:16:07 +10:00
Oliver Walters
38beaff01b peppy 2020-09-28 22:09:09 +10:00
Oliver Walters
d348d90fbe Cleanup errors in unit testing 2020-09-28 22:08:38 +10:00
Oliver Walters
ae55c81dae Updated translation files 2020-09-28 22:04:08 +10:00
Oliver Walters
54bfcff213 CHange "parts" to "items" 2020-09-28 22:03:41 +10:00
Oliver Walters
b2b22762ef style fixes 2020-09-28 22:01:45 +10:00
Oliver Walters
a18886f196 Add some unit tests for the new functions 2020-09-28 22:00:17 +10:00
Oliver Walters
df8d1fb32b Add functions to install and uninstall stock items 2020-09-28 21:52:23 +10:00
Oliver Walters
81ce284264 Select the "default" where we wish to uninstall parts 2020-09-28 21:41:35 +10:00
Oliver Walters
39cfe39172 View / form / url for stock-uninstall form 2020-09-28 21:27:27 +10:00
Oliver Walters
ca6994566d Add better terminal support for invoke server command 2020-09-28 21:26:40 +10:00
Oliver Walters
2ef8464a83 Add buttons to remove installed items from a stock item 2020-09-28 20:27:13 +10:00
Oliver
4de6cc3e4f Merge pull request #999 from SchrodingersGat/build_fix
Fix unit test
2020-09-28 20:20:08 +10:00
Oliver Walters
b58f7d7461 Custom table display for installed stock items 2020-09-28 20:19:56 +10:00
Oliver Walters
d684ed076b Improve table filter naming 2020-09-28 20:10:29 +10:00
Oliver Walters
d8a74ad8b7 Style fixes 2020-09-28 20:08:08 +10:00
Oliver Walters
f253bf1843 Add ability for stock API to be filtered by installed status 2020-09-28 20:07:25 +10:00
Oliver Walters
f409bfd72b More fixes 2020-09-28 19:41:41 +10:00
Oliver Walters
8dd8e69c05 Add "installed parts" tab for stock item 2020-09-28 19:34:43 +10:00
Oliver Walters
97b35d9269 Renamed related name "owned_parts" to "installed_parts" 2020-09-28 19:33:32 +10:00
Oliver Walters
042956ad48 Fix unit test 2020-09-28 19:27:18 +10:00
Oliver
a3f59d8115 Merge pull request #998 from SchrodingersGat/test-report-ordering
Bugfix: Test result ordering was reversed!
2020-09-28 09:02:52 +10:00
Oliver Walters
b76e6a5023 Bugfix: Test result ordering was reversed! 2020-09-28 09:02:17 +10:00
Oliver
3a5014da4b Merge pull request #996 from SchrodingersGat/batch-filtering
Adds ability to filter stock API results by batch code
2020-09-23 09:20:13 +10:00
Oliver Walters
8a4597be6a Adds ability to filter stock API results by batch code 2020-09-23 09:11:46 +10:00
Oliver
fb247c3dd8 Merge pull request #994 from SchrodingersGat/docs-update
Update links to documenation
2020-09-23 08:51:07 +10:00
Oliver
7dd988a7dc Merge pull request #995 from eeintech/stock_to_build_prefetch
Reduced SQL load for 'Require Stock to Complete Build' widget on homepage
2020-09-23 08:45:51 +10:00
eeintech
120a17241e Reduced SQL load for 'Require Stock to Complete Build' widget on homepage 2020-09-22 11:24:09 -05:00
Oliver Walters
07adee3c51 Update links to documenation 2020-09-21 22:44:48 +10:00
Oliver
12e43dcc46 Update README.md
Rearrange headers in README.md
2020-09-21 22:40:02 +10:00
Oliver
bc57845aaa Update README.md
Point to new documentation on readthedocs.io
2020-09-21 22:39:04 +10:00
Oliver
8f1e116c0b Merge pull request #992 from SchrodingersGat/build-table-refresh
Build display improvements
2020-09-21 08:14:25 +10:00
Oliver Walters
5d6e20d897 Build display improvements
- Reload AJAX table instead of entire page
- Clean up auto-allocate page
- Add extra message
2020-09-21 08:05:31 +10:00
Oliver
7dbb6c7c8e Merge pull request #988 from SchrodingersGat/sell-price
Sell price
2020-09-19 23:52:25 +10:00
Oliver
d6bca4d6ca Merge pull request #987 from SchrodingersGat/serial_number_filter
Stock Search
2020-09-19 23:48:11 +10:00
Oliver Walters
f19a727a02 Allow searching by stock item batch code 2020-09-19 23:40:06 +10:00
Oliver Walters
89b3290068 Add search results for stock items 2020-09-19 23:38:33 +10:00
Oliver Walters
083bfe05c0 Add ability to search stock API
- serial number
- part information
2020-09-19 21:49:07 +10:00
Oliver
5f81d650e9 Merge pull request #986 from SchrodingersGat/serial_number_filter
Filter stock tables by serial number
2020-09-19 21:47:40 +10:00
Oliver Walters
2e1388475e Filter stock tables by serial number 2020-09-19 21:39:43 +10:00
Oliver
2389bb9621 Merge pull request #984 from SchrodingersGat/index_page_fixes
Tweaks for new index page
2020-09-19 21:33:25 +10:00
Oliver Walters
b30754f561 Animate hourglass icons 2020-09-19 21:26:34 +10:00
Oliver Walters
b9594db832 Add some hourglass loading icons 2020-09-19 21:23:36 +10:00
Oliver Walters
597ab37ba6 Further cleanup 2020-09-19 21:18:29 +10:00
Oliver Walters
1b6843e72d Cleanup "bom_invalid" filter
- Allow filtering by bom either valid or invalid
- Use "bom_valid" as the filter (positive tense)
2020-09-19 21:03:49 +10:00
Oliver Walters
87d0d872e0 Fix spelling mistakes 2020-09-19 20:45:00 +10:00
Oliver Walters
b8509f7533 Add ability to filter builds by "active" status 2020-09-19 20:42:20 +10:00
Oliver Walters
11a17fb9b1 Implement a "simplified" part table which does not enforce extra filtering 2020-09-19 20:35:30 +10:00
Oliver Walters
eaf42b8abe Instead of creating a custom filter for "latest" parts,
simply make use of the existing "ordering" query as part of DRF
2020-09-19 20:26:17 +10:00
Oliver
a218b6b351 Merge pull request #982 from eeintech/new_homepage_layout
New homepage layout
2020-09-19 20:04:23 +10:00
Oliver Walters
86660a5f17 style fixes 2020-09-19 19:52:48 +10:00
eeintech
6540fb968e Merge branch 'master' of git://github.com/inventree/InvenTree into new_homepage_layout 2020-09-18 11:52:26 -05:00
eeintech
c55fa13cdb Added part list which require more stock to be built 2020-09-18 11:40:50 -05:00
Oliver Walters
ca1281ee10 Adds ajax table for part sale price information 2020-09-18 22:11:51 +10:00
Oliver Walters
ff7570aea4 VIews / forms / etc 2020-09-18 21:49:56 +10:00
Oliver Walters
1a90106bac Add a tab for part sale prices 2020-09-18 21:20:28 +10:00
Oliver Walters
a95dd86540 Limit choices for the 'Part' reference in the new model 2020-09-18 09:16:59 +10:00
Oliver Walters
71c0406cf3 Register new model in the admin interface 2020-09-18 09:16:41 +10:00
eeintech
945c3c214d Added outstanding purchase and sales orders views to homepage 2020-09-17 17:19:19 -05:00
eeintech
3d597cc3c3 Added 'Pending' builds report to homepage, includes builds with 'Allocated' status 2020-09-17 14:36:05 -05:00
Oliver Walters
8f1b018f0a Add table for price breaks for selling a part 2020-09-17 23:22:37 +10:00
Oliver Walters
e51fee081b SupplierPart price break table now uses API rather than django template 2020-09-17 23:19:50 +10:00
Oliver Walters
805e8daa57 Convert SupplierPriceBreak model to use the abstract PriceBreak class 2020-09-17 22:47:31 +10:00
Oliver Walters
95c5c4b575 Fix issues with circular imports 2020-09-17 22:44:17 +10:00
Oliver
25e73db455 Merge pull request #981 from wolffam/build-allocated-no-location-fix
Handle situation where allocated items within a build do not have a location set
2020-09-17 19:33:47 +10:00
alex
d10ba5edc3 handle case where stock item does not have a location set; also show header 2020-09-17 00:55:54 -07:00
alex
6ed604bbb8 fix erroring html 2020-09-17 00:49:17 -07:00
eeintech
28a55f0a58 Merge branch 'master' of git://github.com/inventree/InvenTree into new_homepage_layout 2020-09-16 17:03:59 -05:00
eeintech
a9fffe6a73 Added latest parts and invalid BOMs on homepage 2020-09-16 17:02:24 -05:00
Oliver
4af6b65ac3 Merge pull request #978 from eeintech/fix_navbar_barcode_border
Fixed borders of navbar barcode button
2020-09-17 07:54:28 +10:00
eeintech
472e2d0acd Fixed borders of navbar barcode button 2020-09-16 09:44:12 -05:00
Oliver
303db293b7 Merge pull request #976 from SchrodingersGat/path-fix
Ensure correct path separator is returned
2020-09-13 21:22:15 +10:00
Oliver Walters
d674eacd78 Ensure correct path separator is returned 2020-09-13 21:10:11 +10:00
Oliver
adaaa1e81d Merge pull request #975 from SchrodingersGat/dropdown-css
Dropdown css
2020-09-13 21:05:18 +10:00
Oliver Walters
32cde5d8f1 Fixx css for multiple button groups 2020-09-13 20:56:05 +10:00
Oliver Walters
04c702e1b8 Improve action buttons for part display 2020-09-13 20:42:59 +10:00
Oliver
eaf87294ce Merge pull request #974 from SchrodingersGat/toggle-fix
Fix for weird button toggles (it was a doozy!)
2020-09-13 17:56:08 +10:00
Oliver Walters
aa35c787b2 Fix for weird button toggles (it was a doozy!)
- Turning off autocomplete seems to have done the job
- https://stackoverflow.com/questions/36546775/html-checkboxes-keep-checked-after-refresh#36547079
2020-09-13 17:47:40 +10:00
Oliver
65bc23a516 Merge pull request #973 from SchrodingersGat/multi-bom-item-delete
Multi bom item delete
2020-09-13 00:47:44 +10:00
Oliver Walters
57e395de71 BOM: Allow multiple BOM items to be selected and deleted
(in editing mode)
2020-09-13 00:40:06 +10:00
Oliver Walters
7a7db97914 add inventreeDelete ajax function 2020-09-13 00:39:25 +10:00
Oliver Walters
36ac268b96 BOM Display: Multiple fixes
- Previous multi-level BOM display changes had broken the table in editing mode
- Simplify code
- Re-implement edit / delete / validate buttons
- Re-enable checkboxes in edit mode
2020-09-13 00:13:53 +10:00
Oliver
8c9491f3ca Merge pull request #970 from eeintech/color_themes
Color theme selection added to settings
2020-09-10 09:28:40 +10:00
eeintech
28585644ea Added automatic listing of custom CSS sheets (no more hardcoded), added error message when current selection is not valid and select default theme 2020-09-09 14:55:32 -05:00
eeintech
8198fad6d5 Updated common.colortheme migration 2020-09-08 16:36:58 -05:00
eeintech
35060ce8dc Merge branch 'master' of git://github.com/inventree/InvenTree into color_themes 2020-09-08 16:33:22 -05:00
eeintech
896fa131f0 Moved color themes CSS sheets to own folder, nicer crispy form for selecting theme 2020-09-08 16:24:22 -05:00
Oliver
700d522c3c Merge pull request #962 from eeintech/part_ipn_slug
Added PartDetailFromIPN view (subclass of PartDetail) and url pattern
2020-09-08 09:40:28 +10:00
eeintech
8e2d568a42 Style correction (missing ending new line), removed commented line in ColorThemeSelectForm 2020-09-07 17:01:05 -05:00
eeintech
10dd8fad80 Renamed Theme to ColorTheme, ColorTheme is now a per-user selection 2020-09-07 16:27:23 -05:00
eeintech
2e5ec5d249 Theme change works but applies to all user 2020-09-07 15:15:51 -05:00
eeintech
0548bee8ad Added Color Theme view in settings 2020-09-07 11:29:24 -05:00
eeintech
27241e217f Style correction 2020-09-07 08:46:39 -05:00
eeintech
c5efce36b6 Added PartDetailFromIPN view tests 2020-09-07 08:40:37 -05:00
eeintech
41071f0ed4 Moved IPN url pattern to right before Part index to avoid catching others 2020-09-05 12:03:07 -05:00
eeintech
8198e919b1 Merge branch 'master' of git://github.com/inventree/InvenTree into part_ipn_slug 2020-09-05 11:42:33 -05:00
Oliver
f0713ce01d Merge pull request #966 from SchrodingersGat/stock-item-link
Add link from stock item to base part
2020-09-06 00:01:36 +10:00
Oliver Walters
87f25eacc5 Add link from stock item to base part 2020-09-06 00:01:14 +10:00
Oliver
22e30903b6 Merge pull request #965 from SchrodingersGat/api-stock-fix
Major bugfix for multiple annotations in API querysets
2020-09-05 23:42:25 +10:00
Oliver Walters
46a8107be5 Refactor stock filter 2020-09-05 23:35:48 +10:00
Oliver Walters
2cf40c0e0b Translation updates 2020-09-05 23:32:36 +10:00
Oliver Walters
f7ad38dad5 Add unit tests for new aggregation annotation approach 2020-09-05 23:28:54 +10:00
Oliver Walters
5f2e4c3790 Update serializers for Order model 2020-09-05 23:08:59 +10:00
Oliver Walters
598e15af46 Fix annotations for Company serializers 2020-09-05 23:03:38 +10:00
Oliver Walters
db214dfd73 Update queryset annotation for StockItem
- Query time reduced from 4.1 to 3.5s (for sample data)
2020-09-05 22:50:17 +10:00
Oliver Walters
42967905bc New approach for multiple annotations
- Use the django-sql-utils addon - https://github.com/martsberger/django-sql-utils
- The "distinct=True" flag was not doing what I thought it was doing...
2020-09-05 22:35:19 +10:00
Oliver
a2efac4dbe Merge pull request #964 from SchrodingersGat/new-stock-item-form
Bugfix: CreateStockItem form
2020-09-05 20:51:36 +10:00
Oliver Walters
f737ad2d38 Bugfix: CreateStockItem form
- hide the field rather than popping it
2020-09-05 20:31:18 +10:00
Oliver
2667dc68d7 Merge pull request #963 from SchrodingersGat/variant-form
Allow selection of bom_copy and parameter_copy when making a new variant
2020-09-05 20:26:14 +10:00
Oliver Walters
c4989e59b2 Allow selection of bom_copy and parameter_copy when making a new variant 2020-09-05 20:10:18 +10:00
Oliver
6ef4390e29 Merge pull request #961 from eeintech/parameters_copy
Implemented part parameters copy from template/original part
2020-09-05 20:03:18 +10:00
eeintech
2fa284d37b Added PartDetailFromIPN view (subclass of PartDetail) and url pattern 2020-09-04 17:20:17 -05:00
eeintech
440a5fafea Implemented part parameters copy from template/original part 2020-09-04 14:02:12 -05:00
Oliver
11b751323e Merge pull request #953 from SchrodingersGat/part-import-fix
Part: Alter model fields to fix data import issues
2020-09-03 00:18:26 +10:00
Oliver Walters
34a334236a Part: Alter model fields to fix data import issues
Without setting 'null=True' on fields which may be empty,
the import subsequently fails if these fields are indeed empty
2020-09-03 00:11:20 +10:00
Oliver
81b50312e2 Merge pull request #952 from SchrodingersGat/variant-table
Add ability to filter part list by 'ancestor'
2020-09-03 00:09:53 +10:00
Oliver Walters
b89588ffb7 variant of link links to variants page 2020-09-03 00:00:03 +10:00
Oliver Walters
303572bc03 More translation updates 2020-09-02 23:57:51 +10:00
Oliver Walters
e3d92e1390 Fixes for translation script 2020-09-02 23:54:35 +10:00
Oliver Walters
eaec85398f Treegrid display for part variants 2020-09-02 23:51:28 +10:00
Oliver Walters
62c26c881d Add ability to filter part list by 'ancestor' 2020-09-02 23:18:26 +10:00
Oliver
104b9d2d44 Merge pull request #949 from SchrodingersGat/multi-db-unit-test
Add CI tests for MySQL database
2020-09-02 20:26:51 +10:00
Oliver Walters
36955d6d4f pep fixes 2020-09-02 20:16:46 +10:00
Oliver Walters
92ec849fc1 Add ci settings file for postgresql database 2020-09-02 20:09:11 +10:00
Oliver Walters
bb9e8fa97b Merge remote-tracking branch 'inventree/master' into multi-db-unit-test
# Conflicts:
#	InvenTree/build/test_build.py
2020-09-02 20:02:22 +10:00
Oliver Walters
911727f7b7 Update test fixtures
- Can't assume that pk values will be assigned sensibly!
- Need to hard-code them in
2020-09-02 19:47:07 +10:00
Oliver Walters
bc2f131144 travis fixes 2020-09-01 21:24:19 +10:00
Oliver Walters
b8856476be More CI file changes 2020-09-01 21:21:32 +10:00
Oliver Walters
37a43c8657 Install required PIP packages 2020-09-01 21:13:38 +10:00
Oliver Walters
85f635c975 Darn spelling misterks 2020-09-01 21:08:58 +10:00
Oliver Walters
3af704c453 Fix - tickmark 2020-09-01 21:05:52 +10:00
Oliver Walters
55c1ea750c Add CI tests for MySQL database 2020-09-01 21:01:38 +10:00
Oliver
cae6fb6731 Merge pull request #948 from SchrodingersGat/bcc-feature-non-int-serial
Bcc feature non int serial
2020-09-01 20:31:42 +10:00
Oliver Walters
4613730a19 PEP fixes 2020-09-01 20:24:14 +10:00
Oliver Walters
74f25ee7f9 Part: Extend logic for "latest" serial number
- Return value if it is a string
- Remove 'getNextSerialNumber' function
- Improve functionality of function which returns serial number placeholder string
2020-09-01 20:16:46 +10:00
Oliver Walters
e6c0a04131 Merge branch 'feature-non-int-serial' of git://github.com/bcc/InvenTree into bcc-feature-non-int-serial 2020-09-01 19:41:48 +10:00
Oliver Walters
1eeaa17085 Merge remote-tracking branch 'inventree/master' 2020-09-01 16:41:07 +10:00
Oliver
c3c5a86ea5 Merge pull request #946 from SchrodingersGat/field-focus
Add "focus" option when displaying a modal form
2020-09-01 13:04:02 +10:00
Oliver Walters
ffbdb0317f Add "focus" option when displaying a modal form 2020-09-01 12:43:37 +10:00
Oliver
90d2265dae Merge pull request #945 from SchrodingersGat/template-attachments
Part: add function to get part attachments for *all* parents of a part
2020-08-31 22:38:02 +10:00
Oliver Walters
73892e894e Refactoring 2020-08-31 22:30:38 +10:00
Oliver Walters
cd8214ff4a Part: add function to get part attachments for *all* parents of a part 2020-08-31 22:26:46 +10:00
Oliver
baaabd00d6 Merge pull request #939 from SchrodingersGat/column-remembering
Make checkbox field non-switchable for stock table
2020-08-31 22:08:56 +10:00
Oliver Walters
672936e2d4 Update many tables 2020-08-31 21:55:01 +10:00
Oliver Walters
97ed70502c Fix function which hides table columns based on saved selections 2020-08-31 20:42:11 +10:00
Oliver
35cd3923a5 Merge pull request #944 from SchrodingersGat/stock-item-api-fix
Stock item api fix
2020-08-31 20:13:57 +10:00
Oliver Walters
59e7474f75 Stock: More unit tests
- Add some more tests (would have caught a bug that was there already, darn it)
2020-08-31 20:09:43 +10:00
Oliver Walters
8615cad711 Stock: Fix serializers.py
- Use of read_only PrimaryKeyRelatedField was breaking POST via API
2020-08-31 20:08:07 +10:00
Oliver
fa540c0096 Merge pull request #943 from SchrodingersGat/order-details
Order: Improve help text(s)
2020-08-31 19:32:03 +10:00
Oliver Walters
eabb99053c Update requirements.txt 2020-08-31 19:20:16 +10:00
Oliver Walters
5c4781b5b4 Order: Improve help text(s) 2020-08-31 19:13:24 +10:00
Oliver
406dbc36fa Merge pull request #942 from bcc/bug-invoke-pty
Fix invoke pty error when running 'invoke superuser'
2020-08-30 21:32:17 +10:00
Ben Charlton
07f7b46a8a Fix invoke pty error when running 'invoke superuser' 2020-08-28 20:38:16 +01:00
Ben Charlton
06552832cb Style corrections 2020-08-28 17:30:16 +01:00
Ben Charlton
6b1696f8df Merge branch 'master' into feature-non-int-serial 2020-08-28 17:14:02 +01:00
Oliver Walters
7829e3654c Add callback when a column is shown / hidden 2020-08-28 10:51:55 +10:00
Oliver Walters
9c2e959ab0 Add function to turn a set of visible columns into a settings string for saving to session 2020-08-28 10:50:43 +10:00
Oliver Walters
86e675dbbd Make checkbox field non-switchable for stock table 2020-08-28 10:49:49 +10:00
Oliver Walters
f6d8a3f229 Merge remote-tracking branch 'upstream/master' 2020-08-27 22:50:52 +10:00
Oliver
2c1d585f8b Merge pull request #937 from SchrodingersGat/dynamic-form-fixes
Dynamic form fixes
2020-08-27 08:47:21 +10:00
Oliver Walters
b17c3f6e0f Fix for empty option 2020-08-27 08:41:38 +10:00
Oliver Walters
27f7745231 Follow link to newly created StockItem 2020-08-27 08:37:18 +10:00
Oliver Walters
19329a9627 Merge remote-tracking branch 'inventree/master' 2020-08-27 00:21:42 +10:00
Oliver
ce866c6d30 Merge pull request #934 from SchrodingersGat/reactive-forms
Reactive forms
2020-08-27 00:12:26 +10:00
Oliver Walters
146dae6d43 Toot toot - it's the refactor tractor!
- New function for launching a CreateStockItem form
- Wraps up the previous code improvements into a single function
- Oh, the ease!
2020-08-27 00:08:02 +10:00
Oliver Walters
4be1b2928b PEP fix 2020-08-26 23:50:49 +10:00
Oliver Walters
72899530cf Add helper function to simplify reloading of field options 2020-08-26 23:43:19 +10:00
Oliver Walters
9dcc23ee4e Hide 'supplier part' options if no part is selected in the form 2020-08-26 23:40:15 +10:00
Oliver Walters
3a75682878 Add "pretty" name to the SupplierPart API
- Quick way to ensure the supplier part objects are printed the same way
- Use the pythonic back-end to render the data
2020-08-26 23:23:57 +10:00
Oliver Walters
5aa11063a0 Add function to update the 'options' for a given field in a modal 2020-08-26 23:13:32 +10:00
Oliver Walters
2037474fad Option generation function now returns array, rather than flat text 2020-08-26 23:04:50 +10:00
Oliver Walters
02d17378a6 Add function to programatically generate a list of <option> elements 2020-08-26 23:02:25 +10:00
Oliver Walters
6ab34c3d0e SupplierPart - Improve API
- The default DRF behaviour throws errors if the supplied query params do not conform to the limit_choices_to field
- This is non optimum! Don't want to have to handle these cases
- Do the filtering ourselves!
2020-08-26 22:44:22 +10:00
Oliver Walters
d44ad541eb Add "callback" functionality for modal forms when a given field is changed
- Attach callback function
- Add a function to retrieve a field by name
2020-08-26 22:35:36 +10:00
Oliver
0b4f732160 Merge pull request #933 from SchrodingersGat/report-select-fix
Bugfix: Select test report template
2020-08-26 15:03:39 +10:00
Oliver Walters
54d0c4e8a8 Bugfix: Select test report template
- Actually, two bugs!
2020-08-26 14:29:49 +10:00
Oliver
ee0df29af0 Merge pull request #921 from eeintech/show_potential_bom_items_stock
Show 'available_stock' in Part string representation
2020-08-26 09:36:55 +10:00
Oliver
60c6d6d33e Merge pull request #919 from eeintech/bom_export_parameter_stock
BoM export: added option to export part parameters (#126) and stocks (#793)
2020-08-26 08:41:44 +10:00
eeintech
5d6def75cc BoM export, Part stock: changed 'Location' header to 'Default Location' 2020-08-25 16:02:46 -05:00
eeintech
109307858a Merge branch 'master' of git://github.com/inventree/InvenTree into bom_export_parameter_stock 2020-08-25 15:59:58 -05:00
Ben Charlton
7d6055f06f Merge branch 'master' into feature-non-int-serial 2020-08-25 09:28:42 +01:00
Oliver
788d497e87 Merge pull request #931 from bcc/bug-serialize-no-location
Fix internal server error when serializing stock with no location
2020-08-25 08:38:35 +10:00
Oliver
cd016d3f7d Merge pull request #930 from bcc/feature-custom-authentication
Allow custom authentication/middleware in config.yaml
2020-08-25 08:37:30 +10:00
Ben Charlton
e0a744b01d Remove no-longer-needed cast functions 2020-08-24 20:09:06 +01:00
Ben Charlton
9c2d13b487 test non-numeric serials are handled correctly for ranges 2020-08-24 20:04:10 +01:00
Ben Charlton
0da2682c68 handle non-int serial range suggestions cleanly 2020-08-24 20:00:19 +01:00
Ben Charlton
d5a374f1fd Make serial number suggestion DB independent, handle mixed types more cleanly and test 2020-08-24 19:49:32 +01:00
Ben Charlton
9149aa1536 Fix internal server error when serializing stock with no location 2020-08-24 18:04:22 +01:00
eeintech
946d824995 Switched to ModelChoiceField 2020-08-24 11:41:14 -05:00
eeintech
6f89f7dc7f Merge branch 'master' into show_potential_bom_items_stock 2020-08-24 10:35:59 -05:00
Ben Charlton
b6f9590d55 Add default config example to config template 2020-08-24 15:24:18 +01:00
Ben Charlton
988d263ef1 Allow custom authentication / middleware in config.yaml 2020-08-24 15:05:21 +01:00
Ben Charlton
471ece136e Merge branch 'master' into feature-non-int-serial 2020-08-24 11:12:07 +01:00
Oliver Walters
78826dc20b Merge remote-tracking branch 'inventree/master' 2020-08-23 21:21:18 +10:00
Oliver
2a4b9c6c5c Merge pull request #929 from SchrodingersGat/label-enable
Label enable
2020-08-23 21:18:11 +10:00
Oliver
c3bfcad4df Merge pull request #928 from Kedarius/small-device
Collapse navbar on small screen
2020-08-23 21:12:28 +10:00
Oliver Walters
ca1985e11a PEP fixes 2020-08-23 21:10:45 +10:00
Oliver Walters
9a35293126 Remove PartFilterMixin class 2020-08-23 21:08:41 +10:00
Oliver Walters
ed5ad3c047 Rename 'part_filters' field to 'filters' 2020-08-23 21:05:54 +10:00
Oliver Walters
c849f618d5 Clean up implementation of test report matching 2020-08-23 21:03:29 +10:00
Oliver Walters
b7ae95686e Add field "enabled" to Report template 2020-08-23 20:51:41 +10:00
Radek Hladik
f9149d041e Collapse navbar on small screen 2020-08-23 10:56:29 +02:00
Oliver Walters
116d966d29 Delete "ReportTemplate" class 2020-08-23 09:10:56 +10:00
Oliver Walters
771b2117c4 Remove duplicated function 2020-08-23 09:08:24 +10:00
Oliver Walters
8f1af0f5f9 Add "enabled" field to Label class
- Only list labels which are enabled
- Allows labels to be hidden / disabled without being deleted
2020-08-23 09:07:15 +10:00
Oliver
69a3ad3c5b Merge pull request #927 from bcc/bug-serialized-move
Fix disabled form item from preventing location moves for serialized stock
2020-08-22 09:13:40 +10:00
Ben Charlton
23cc3d9b06 Handle 'next serial' more gracefully 2020-08-21 19:17:58 +01:00
Ben Charlton
c31b30bf83 Fix simple tests 2020-08-21 18:53:51 +01:00
Ben Charlton
f7ed48809c Support non-integer serial numbers 2020-08-21 17:36:49 +01:00
Ben Charlton
eeca3effee Fix disabled form item from preventing stock location moves for items with serial numbers 2020-08-21 16:20:33 +01:00
Oliver Walters
98017cb8bd Merge remote-tracking branch 'inventree/master' 2020-08-21 22:11:02 +10:00
Oliver
de86418ede Merge pull request #925 from SchrodingersGat/make-replace
Change from using "make" to "invoke"
2020-08-21 21:58:19 +10:00
Oliver Walters
017c1ece89 Update docstring 2020-08-21 21:51:22 +10:00
Oliver Walters
d8f9f95cb4 Add command to run the development server 2020-08-21 21:49:03 +10:00
Oliver Walters
ef1e598341 Install PIP requirements as a part of "invoke install" 2020-08-21 21:32:08 +10:00
Oliver Walters
513142d487 Update travis file 2020-08-21 21:27:39 +10:00
Oliver Walters
592e87941d Add more targets
- superuser
- backup
2020-08-21 21:24:02 +10:00
Oliver Walters
f5fd0fc5be Migrate "mysql" and "postgresql" targets 2020-08-21 21:17:38 +10:00
Oliver Walters
af50e29e2c Migrate "translate" command 2020-08-21 21:13:28 +10:00
Oliver Walters
ec1e646de0 Migrate "style" task 2020-08-21 21:12:05 +10:00
Oliver Walters
ab75f85555 Migrate "test" command to invoke 2020-08-21 21:10:14 +10:00
Oliver Walters
05fae4be87 Are more methods to tasks.py:
- static
- update
- install
- key
- coverage

The functionality of setup.py is now included here!
2020-08-21 21:08:04 +10:00
Oliver Walters
f4debeac47 Moving to "invoke" framework
- Add "migrate" test
2020-08-21 20:39:43 +10:00
Oliver
7a0e1e9574 Merge pull request #924 from SchrodingersGat/stocktake-export-fixes
Stocktake export fixes
2020-08-21 20:14:02 +10:00
Oliver Walters
59b3d8b5bc Fix stocktake export
- Exclude MPTT fields
- Fix foreignkey field references
2020-08-21 20:08:47 +10:00
Oliver Walters
25cced3b90 Exclude MPTT fields from Part model resource 2020-08-21 20:08:16 +10:00
eeintech
9fa13aeae3 Show 'available_stock' in Part string representation 2020-08-20 15:38:41 -05:00
eeintech
89e63df1fb Corrected style 2020-08-20 14:53:03 -05:00
eeintech
6fc275ca30 BoM export: added option to export part paremeters (#126) and stocks (#793) 2020-08-20 13:53:27 -05:00
Oliver Walters
142a1462bb Merge remote-tracking branch 'inventree/master' 2020-08-20 16:02:18 +10:00
Oliver
852a680c09 Merge pull request #916 from SchrodingersGat/null-customer
StockItem: Allow customer field to be blank
2020-08-20 14:59:06 +10:00
Oliver Walters
90d34cdfcf StockItem: Allow customer field to be blank 2020-08-20 14:54:55 +10:00
Oliver Walters
2f88cc9fe0 Merge remote-tracking branch 'inventree/master' 2020-08-20 14:48:16 +10:00
Oliver
4f1b469cee Merge pull request #915 from SchrodingersGat/tex-response
Tex response
2020-08-20 14:14:24 +10:00
Oliver Walters
8e0dfa9c6f PEP fix 2020-08-20 14:05:55 +10:00
Oliver Walters
64ae181bf6 Add some more context data 2020-08-20 14:01:41 +10:00
Oliver Walters
5a8804f4bc If LaTeX template errors, return the raw LaTeX! 2020-08-20 13:57:29 +10:00
Oliver Walters
c1956d13b5 Merge remote-tracking branch 'inventree/master' 2020-08-20 09:04:17 +10:00
Oliver
71f3662ebc Merge pull request #914 from SchrodingersGat/recursive-bom
Bugfix: Recursive BOM display
2020-08-20 09:01:26 +10:00
Oliver Walters
0aeb7ddbdf Allow column show/hide on BOM table 2020-08-20 08:57:11 +10:00
Oliver Walters
41c4a5376b Bugfix: Recursive BOM display
- Actually request recursively! (duh)
- Fix the idField and parentIdField for the BOM display (was incredibly wrong)
- Sub-rows are initially displayed in the "collapsed" state
2020-08-20 08:52:22 +10:00
Oliver Walters
6930456e2b Merge remote-tracking branch 'inventree/master' 2020-08-19 14:19:43 +10:00
Oliver
8556bdec6a Merge pull request #913 from SchrodingersGat/supplier-data-in-bom
Supplier data in bom
2020-08-19 14:13:53 +10:00
Oliver Walters
0faba39dfc PEP: Remove unused variable
(cherry picked from commit e49a1c1ad2)
2020-08-19 14:08:52 +10:00
Oliver Walters
7e829e88af Add option for including supplier data for BOM export
(cherry picked from commit d0b5550c86)
2020-08-19 14:08:47 +10:00
Oliver Walters
3d0012a3bf Bugfix: accomodate missing manfufacturer links
If a supplier_part does not have an associated manufacturer, the code would break

(cherry picked from commit 965dba4739)
2020-08-19 14:08:41 +10:00
eeintech
b5bc8935a2 Added manufacturer data to BoM export
(cherry picked from commit c7ddccc4ec)
2020-08-19 14:08:34 +10:00
Oliver Walters
f8bb357e6c Merge remote-tracking branch 'inventree/master' 2020-08-18 21:30:08 +10:00
Oliver Walters
50460ed527 Merge branch 'master' of https://github.com/SchrodingersGat/InvenTree 2020-08-18 21:29:48 +10:00
Oliver
13b64c6a04 Merge pull request #910 from SchrodingersGat/multi-level-bom
Multi level bom
2020-08-18 21:28:47 +10:00
Oliver Walters
1767ef7a3a Fix issues with tree sorting
- Need to set parent ID based on the BOM items
- This is to prevent data duplication that was weird and dumb
2020-08-18 21:24:11 +10:00
Oliver Walters
82903d2bd6 BOM display is now heirarchical 2020-08-18 21:01:22 +10:00
Oliver Walters
4cd54203a2 Add jquery-treegrid plugin 2020-08-18 20:53:50 +10:00
Oliver Walters
37baec2db6 bootstrap-table: Add "extensions" 2020-08-18 20:53:05 +10:00
Oliver Walters
32133fecc7 Merge remote-tracking branch 'upstream/master' 2020-08-18 14:41:03 +10:00
Oliver
316dfe5e38 Merge pull request #909 from SchrodingersGat/bom-import-export
BOM upload: improve generation of "import" template
2020-08-18 14:37:48 +10:00
Oliver Walters
92ac93aac5 More intelligent checking for circular BOM
- Check all the way down a BOM "tree"
- Validate BOM tree before allowing BOM submission
2020-08-18 14:17:59 +10:00
Oliver Walters
ca4d3df287 Update translation files 2020-08-18 14:01:40 +10:00
Oliver Walters
68fb599c73 Major improvements to BOM upload
- Column headings now match the values provided in BOM import template
- Add a new column for part selection, while displaying all imported data
- Better code documentation
- Improve data validation
- Allow decimal quantity (not just integer!)
- Better matching logic
2020-08-18 14:01:01 +10:00
Oliver Walters
7349b396ca Merge remote-tracking branch 'upstream/master' into bom-import-export 2020-08-18 11:50:40 +10:00
Oliver
561516e8d7 Merge pull request #908 from eeintech/bom_upload_part_match_auto_and_ipn
BoM Upload: Automatic Part match using name or IPN
2020-08-18 11:50:10 +10:00
Oliver Walters
476cc5f661 BOM upload: improve generation of "import" template
- Better field naming
- Remove some fields which are not required here
- Better description of what is going to happen
2020-08-18 11:47:27 +10:00
Oliver Walters
badc306f33 Merge remote-tracking branch 'upstream/master' 2020-08-18 10:39:24 +10:00
eeintech
783a94acce Corrected MakeBomTemplate method's queryset 2020-08-17 16:42:28 -05:00
eeintech
84c0ec7937 BoM: added part matching based on IPN 2020-08-17 16:35:38 -05:00
eeintech
303157c586 Added part match auto-selection (if partial_ratio >= 100) to BoM part selection form 2020-08-17 14:10:24 -05:00
eeintech
685a58b807 Merge remote-tracking branch 'origin/master' into bom_dev 2020-08-17 12:05:54 -05:00
Oliver
89c7f72caf Merge pull request #907 from SchrodingersGat/bom-level-int
Make BOM levels integers
2020-08-17 10:43:31 +10:00
Oliver Walters
25d90f643a Make BOM levels integers 2020-08-17 10:39:35 +10:00
Oliver Walters
e67327953d Merge remote-tracking branch 'inventree/master' 2020-08-16 15:10:23 +10:00
Oliver
4dcd6ee136 Update version.py 2020-08-16 14:03:49 +10:00
Oliver
ab62f8fc59 Update version.py
Increment version number
2020-08-16 14:03:20 +10:00
Oliver
b5b882d3b6 Merge pull request #906 from SchrodingersGat/blabel
Label Printing Functionality
2020-08-16 14:02:38 +10:00
Oliver Walters
d52278e423 Icon tweak 2020-08-16 13:45:58 +10:00
Oliver Walters
da079b23dc Fix duplicate label printing menu action 2020-08-16 13:43:59 +10:00
Oliver Walters
ccda637e3c Fixes for barcode decoding 2020-08-16 13:42:27 +10:00
Oliver Walters
a4267f76e8 Fixes for barcode data rendering 2020-08-16 13:39:05 +10:00
Oliver Walters
2bbc65cc59 Add "brief" version of QR codes
- Use this to render to labels (as it contains much less information)
2020-08-16 13:29:38 +10:00
Oliver Walters
2f5e3efada Update translations 2020-08-16 12:11:22 +10:00
Oliver Walters
1807ba4e7b Add form for selecting label template for a StockItem 2020-08-16 12:10:58 +10:00
Oliver Walters
30e24f19d9 PEP fixes 2020-08-16 11:13:17 +10:00
Oliver Walters
cdde0f8c43 Add URL endpoint for downloading PDF labels 2020-08-16 11:12:21 +10:00
Oliver Walters
2b1d6c268c Render to an in-memory PDF 2020-08-16 10:29:03 +10:00
Oliver Walters
18b3fd3256 Add context data to StockItemLabel model 2020-08-16 10:24:15 +10:00
Oliver Walters
aefd70ce49 Add admin interface for StockItemLabel 2020-08-16 09:29:45 +10:00
Oliver
eb2422e6be Merge pull request #905 from SchrodingersGat/bom-depth
Allow user to set "depth" of exported multi-level BOM
2020-08-16 09:29:09 +10:00
Oliver Walters
a45902bd4f Add "label" app 2020-08-16 09:28:12 +10:00
Oliver Walters
dd77cc00b7 Add requirement for "blabel" plugin 2020-08-16 09:07:27 +10:00
Oliver Walters
e5406cae24 More PEP fixes 2020-08-16 09:05:16 +10:00
Oliver Walters
97103207b6 PEP fixes 2020-08-16 08:34:54 +10:00
Oliver Walters
b27ecf54d7 Allow user to set "depth" of exported multi-level BOM 2020-08-16 08:29:36 +10:00
Oliver
318c16f321 Merge pull request #904 from SchrodingersGat/query-speeds
Significant query speed improvements to stock list API
2020-08-15 21:56:55 +10:00
Oliver Walters
f1373e3bea Improve speed of BomItem API queries
- Including the pricing information takes absolutely ages, takes too long!!
2020-08-15 21:52:32 +10:00
Oliver Walters
e1a8772af6 Update serializers for SupplierPart 2020-08-15 21:24:01 +10:00
Oliver Walters
d34383e842 Specify serializer type for part category 2020-08-15 21:20:31 +10:00
Oliver Walters
2f77007dbe Significant query speed improvements to stock list API
- Thanks, django-debug-toolbar!
- Gah, django DRF is the worst. Enforcing a PrimaryKeyRelatedSerializer seems to really improve speed
2020-08-15 21:15:11 +10:00
Oliver
411e7507a3 Merge pull request #903 from SchrodingersGat/debug-toolbar
Debug toolbar
2020-08-15 20:08:04 +10:00
Oliver Walters
3c4cfc9a1b Flake fix 2020-08-15 19:56:02 +10:00
Oliver Walters
2bb669d7de Remove defunct "log_queries" option 2020-08-15 19:52:04 +10:00
Oliver Walters
b8b3a933ab Add django-debug-toolbar plugin
- Must be running in DEBUG mode
- Must set debug_toolbar to True in config file
2020-08-15 19:48:42 +10:00
Oliver Walters
2280558303 Add a method of return raw LaTeX for debugging 2020-08-15 19:27:31 +10:00
Oliver Walters
3b01614a38 Merge remote-tracking branch 'inventree/master' 2020-08-09 21:37:06 +10:00
Oliver
1f5d81ef93 Merge pull request #900 from SchrodingersGat/stock-display-improvements
Stock display improvements
2020-08-09 21:26:26 +10:00
Oliver Walters
cebba6909c Revert thing 2020-08-09 21:21:12 +10:00
Oliver Walters
3336eb9f45 Default stock list behaviour is to only show in_stock items 2020-08-09 21:12:49 +10:00
Oliver Walters
0da9e0f834 Add "sent_to_customer" filter 2020-08-09 21:10:21 +10:00
Oliver Walters
502702b3bc Add some more visual tags to the stock list 2020-08-09 21:04:41 +10:00
Oliver
bb6b3b965d Merge pull request #896 from SchrodingersGat/company-ordering
Add default ordering for Company model
2020-08-08 17:21:21 +10:00
Oliver
fcfd1f82d6 Merge pull request #898 from SchrodingersGat/filter-depleted
Filter depleted
2020-08-08 17:19:28 +10:00
Oliver Walters
19c036f50a Add migration files 2020-08-08 17:16:04 +10:00
Oliver Walters
ad11681369 Custom filter tag for company stock listing 2020-08-08 17:15:08 +10:00
Oliver Walters
bc3fda71a4 Display "depleted" label next to depleted stock 2020-08-08 17:11:50 +10:00
Oliver Walters
96a3f2920d Stock table filters now arranged in alphabetical order 2020-08-08 17:09:22 +10:00
Oliver Walters
099f56e779 Add "depleted" table filter 2020-08-08 17:08:18 +10:00
Oliver Walters
402301e165 Add ability to filter stock items by "depleted" status 2020-08-08 17:06:22 +10:00
Oliver
190610c6c9 Merge pull request #897 from SchrodingersGat/serialized-stock-adjust-fix
Cannot edit quantity for serialized stock when adjusting
2020-08-08 17:05:29 +10:00
Oliver Walters
732405f738 Cannot edit quantity for serialized stock when adjusting 2020-08-08 17:01:29 +10:00
Oliver Walters
a7ee323035 PEP fix 2020-08-08 16:59:48 +10:00
Oliver Walters
ad977d4d26 Add default ordering for Company model
- Now will sort by "name" in choice fields, etc
2020-08-08 16:54:09 +10:00
Oliver Walters
3831a04ce0 Merge remote-tracking branch 'inventree/master' 2020-08-08 09:52:48 +10:00
Oliver
eac53c836c Update README.md 2020-08-08 09:52:14 +10:00
Oliver
2cd6c0b9fc Merge pull request #895 from SchrodingersGat/return-to-stock
Return to stock
2020-08-08 09:48:44 +10:00
Oliver Walters
8d9cfd3678 Migration file for StockStatus codes 2020-08-08 09:44:21 +10:00
Oliver Walters
a2c3c1086c Catch unhandled javascript errors 2020-08-08 09:31:57 +10:00
Oliver Walters
ff71fe6e93 Fix "in_stock" logic for StockItem
- Not in stock if it is at a customer!
2020-08-08 09:20:42 +10:00
Oliver Walters
861a2982db Removed "SHIPPED" stock status code 2020-08-08 09:16:53 +10:00
Oliver Walters
54c1f2d9a2 Upgrade to latest flake8 2020-08-08 09:15:45 +10:00
Oliver Walters
459cc03aae Remove "ASSIGNED_TO_BUILD" status code 2020-08-08 09:08:15 +10:00
Oliver Walters
80173a9d43 Remove ASSIGNED_TO_OTHER_ITEM status code 2020-08-08 09:07:25 +10:00
Oliver Walters
bdea29df04 Add functionality to return stock item from customer 2020-08-08 09:05:33 +10:00
Oliver Walters
7b332d93ee Rearrange button layouts 2020-08-08 08:48:27 +10:00
Oliver
518ad3eb60 Merge pull request #892 from SchrodingersGat/import-fix
Allow default_keywords to be  null
2020-08-04 11:35:25 +10:00
Oliver Walters
0f199556df Add migration file 2020-08-04 11:21:27 +10:00
Oliver Walters
3a266cf322 Allow default_keywords to be null 2020-08-04 11:10:24 +10:00
Oliver Walters
d65d76653c Merge remote-tracking branch 'inventree/master' 2020-08-03 20:49:33 +10:00
Oliver
08bab0a1b9 Merge pull request #891 from SchrodingersGat/security-fix
Update requirements.txt
2020-08-03 19:53:34 +10:00
Oliver Walters
481eeb8338 Update requirements.txt 2020-08-03 19:36:41 +10:00
Oliver
e0e82dabf3 Merge pull request #889 from SchrodingersGat/allow-empty-stock
Allow creation of a stock item with zero quantity
2020-07-30 21:09:57 +10:00
Oliver Walters
10691b3d03 Allow creation of a stock item with zero quantity 2020-07-30 21:05:37 +10:00
Oliver
8a1f358505 Merge pull request #888 from SchrodingersGat/allow-staff-delete
Allow staff delete
2020-07-30 20:29:57 +10:00
Oliver Walters
b7f30ee136 Update translations 2020-07-30 20:26:14 +10:00
Oliver Walters
d90edab59f Staff users are allowed to delete stock items that otherwise are not able to be deleted 2020-07-30 20:23:46 +10:00
Oliver Walters
d1d5b45073 Merge remote-tracking branch 'inventree/master' 2020-07-22 14:52:57 +10:00
Oliver
daab81fa2c Merge pull request #887 from eeintech/allow_api_thumbnail_update
Allowing Part thumbnail (image) update via API
2020-07-22 09:19:43 +10:00
eeintech
f386039d5a Added validation method for uploaded file using imghdr library 2020-07-21 16:01:17 -05:00
eeintech
af70dd5dfe Allowing Part thumbnail (image) update via API 2020-07-20 16:16:26 -05:00
eeintech
51c194fb8f Merge branch 'master' of github.com:eeintech/InvenTree into bom_dev 2020-07-19 15:05:07 -05:00
Oliver Walters
6994af411d Merge remote-tracking branch 'inventree/master' 2020-07-18 13:31:07 +10:00
Oliver
5209a7a1b0 Merge pull request #884 from SchrodingersGat/fix-filters
Adds table filters for stock assigned to a particular customer
2020-07-14 16:05:44 +10:00
Oliver Walters
0152ae79ef Adds table filters for stock assigned to a particular customer 2020-07-14 15:54:03 +10:00
eeintech
3b98d85143 Merge branch 'master' of github:eeintech/InvenTree into bom_dev 2020-07-09 08:48:41 -05:00
eeintech
46586ba960 Corrected typo in part.models, simplified MakeBomTemplate function 2020-07-09 08:47:52 -05:00
Oliver
cfd1194a6e Merge pull request #883 from eeintech/api_delete_inactive_part
API: Allow part deletion if inactive
2020-07-09 19:42:51 +10:00
eeintech
9b7977a217 API: Allow part deletion if inactive 2020-07-08 10:56:23 -05:00
Oliver Walters
5f2ca784c9 Merge branch 'negative-stock-fix' 2020-06-28 19:26:56 +10:00
Oliver
3d7676e292 Merge pull request #880 from SchrodingersGat/negative-stock-fix
Improve logic of "quantity_to_order" function
2020-06-28 19:23:37 +10:00
Oliver
25b7f0b7ee Merge pull request #879 from SchrodingersGat/star-filter-fix
Fix filter logic for 'starred' parts
2020-06-28 19:14:55 +10:00
Oliver Walters
3d245c7ce3 Improve logic of "quantity_to_order" function 2020-06-28 19:14:51 +10:00
Oliver Walters
134a688e4a Fix filter logic for 'starred' parts 2020-06-28 19:08:13 +10:00
Oliver
8ac23c080f Merge pull request #875 from SchrodingersGat/tweaks
"Active" part toggle is always enabled
2020-06-22 11:33:39 +10:00
Oliver Walters
fa3d2d005a "Active" part toggle is always enabled 2020-06-22 11:27:59 +10:00
Oliver
da70af7ba0 Merge pull request #874 from SchrodingersGat/show_non_stock
Add ability to display "out of stock" items against a part
2020-06-22 10:55:12 +10:00
Oliver Walters
930f903f5d Add ability to display "out of stock" items against a part 2020-06-22 10:48:41 +10:00
Oliver
16bea33695 Merge pull request #867 from SchrodingersGat/name-conventions
Update verbose names for some fields
2020-06-13 20:52:15 +10:00
Oliver Walters
dedc25d681 Update verbose names for some fields 2020-06-13 20:46:19 +10:00
Oliver Walters
82433db1ea Merge remote-tracking branch 'inventree/master' 2020-06-12 18:16:23 +10:00
Oliver
2047b2d7d7 Merge pull request #866 from SchrodingersGat/moar-buttons
Reorganize buttons for "Part" view
2020-06-12 18:16:06 +10:00
Oliver Walters
2e91f64a96 Add (disabled) print-label button for Part display 2020-06-12 18:13:14 +10:00
Oliver Walters
1ad4b8b131 Reorganize buttons for "Part" view 2020-06-12 18:11:57 +10:00
Oliver
a63219466f Merge pull request #865 from SchrodingersGat/barcode-suppor
Barcode support
2020-06-12 17:57:36 +10:00
Oliver Walters
9757fb06db Fix a weird button issue
- reloadTable() was causing the button 'click' handler to fire...
- NFI why this is happening
2020-06-12 16:47:57 +10:00
Oliver Walters
ab4e6548dc Transfer stock items into a stock location using barcode scanning 2020-06-12 16:29:08 +10:00
Oliver Walters
351a55c9ea Add the concept of "action groups" to the buttons for the Stock Location view 2020-06-12 11:14:33 +10:00
Oliver Walters
e1c503836d Improve barcode icon in navbar 2020-06-12 10:56:52 +10:00
Oliver Walters
8cafaa0e62 Make barcode javascript translatable 2020-06-12 10:43:27 +10:00
Oliver Walters
6064c6ceb5 Add dialog for linking a barcode with a stock item 2020-06-12 10:26:23 +10:00
Oliver Walters
b559816dca Update translations 2020-06-12 10:25:07 +10:00
Oliver Walters
ba94b340dd Add function to un-link barcode from a stock item 2020-06-12 10:12:31 +10:00
Oliver Walters
beccbe8583 Flake fixes 2020-06-11 19:46:36 +10:00
Oliver Walters
07be08d0f3 "Simplify" qr code display 2020-06-11 19:40:44 +10:00
Oliver Walters
4bb9c4c559 Prevent barcode data being entered multiple times 2020-06-11 19:27:32 +10:00
Oliver Walters
2d9b75c6ae Include URL data in barcode scan endpoint 2020-06-11 19:21:38 +10:00
Oliver Walters
3aecb110a5 Add qrcode icon as prefix to barcode input 2020-06-11 19:05:55 +10:00
Oliver Walters
503d5a41b1 Add global 'barcode-scan' button 2020-06-11 18:09:43 +10:00
Oliver Walters
e943681baa Add translations for error messages 2020-06-11 18:09:06 +10:00
Oliver Walters
0559946791 Add unit testing framework for barcodes 2020-06-11 14:44:56 +10:00
Oliver Walters
22a8e82108 Add endpoint for assigning a particular barcode to a StockItem 2020-06-11 12:21:33 +10:00
Oliver Walters
a72ed11cb0 Skeleton for DigiKey barcode 2020-06-11 11:16:55 +10:00
Oliver Walters
1a15b46d65 Remove some debug statements 2020-06-11 11:14:02 +10:00
Oliver Walters
0068cd9825 Refactor barcode endoint
- Moved code into 'barcode' directory
2020-06-11 11:09:07 +10:00
Oliver Walters
290c0eb225 Add barcode javascript file 2020-06-11 09:56:59 +10:00
Oliver Walters
bc31cc550e Consolidate buttons for stock item 2020-06-10 15:27:30 +10:00
Oliver Walters
f40a9d1dad Merge remote-tracking branch 'inventree/master' 2020-06-09 16:28:59 +10:00
Oliver
218971e6f1 Merge pull request #864 from SchrodingersGat/translation-fixes
Update translation hooks
2020-06-09 16:28:34 +10:00
Oliver Walters
38dcdcad54 Update translation hooks 2020-06-09 16:18:38 +10:00
Oliver
aeba189c1a Merge pull request #863 from SchrodingersGat/decimalfix
Decimalize display of variant stock
2020-06-09 13:44:47 +10:00
Oliver Walters
09400fd66b Decimalize display of variant stock
(cherry picked from commit 6e45360c4b7a6bc91f584f498fb6e1988593db95)
2020-06-09 13:31:16 +10:00
Oliver
f3e3838782 Merge pull request #862 from SchrodingersGat/stock-buttons-fix
Fix display of buttons for stock item
2020-06-09 13:19:15 +10:00
Oliver Walters
c7586b83e9 Fix display of buttons for stock item
(cherry picked from commit b23017b6bf)
2020-06-09 13:15:12 +10:00
Oliver Walters
b23017b6bf Fix display of buttons for stock item 2020-06-09 13:14:29 +10:00
Oliver Walters
a6a58b299b Merge remote-tracking branch 'inventree/master' 2020-06-06 08:59:28 +10:00
Oliver
b2c302cb2c Merge pull request #858 from SchrodingersGat/stock-table-ipn
Add "IPN" column to stock list table
2020-06-06 08:58:59 +10:00
Oliver Walters
126e42a022 Add "IPN" column to stock list table 2020-06-06 08:47:06 +10:00
Oliver
22b30a0626 Merge pull request #857 from SchrodingersGat/security-fix
Update django version
2020-06-06 08:38:15 +10:00
Oliver Walters
84362ea790 Update django version 2020-06-06 08:27:13 +10:00
Oliver Walters
7be158722f Merge remote-tracking branch 'inventree/master' 2020-06-05 20:04:41 +10:00
Oliver
f563ac0dcb Merge pull request #855 from SchrodingersGat/part-table
Add "IPN" column to part table
2020-06-05 19:38:16 +10:00
Oliver Walters
16d261d956 Make description fields optional 2020-06-05 19:33:32 +10:00
Oliver Walters
15817ce61a Add "IPN" column to part table 2020-06-05 19:26:41 +10:00
Oliver
dedd87f20a Merge pull request #854 from SchrodingersGat/customer-stock-display
Customer stock display
2020-06-05 12:20:25 +10:00
Oliver Walters
fcd588cb01 Filter SalesOrder by status 2020-06-05 12:08:47 +10:00
Oliver Walters
6ebce2b2fd Add ability to filter purchase orders by "outstanding" status 2020-06-05 12:06:28 +10:00
Oliver Walters
544e217347 Add page to show stock which is assigned to a customer 2020-06-05 11:52:07 +10:00
Oliver Walters
9f599546de Use stock status for determining "in stock" 2020-06-05 09:08:46 +10:00
Oliver Walters
408c6a4040 Filter stock list by "customer" 2020-06-05 09:05:57 +10:00
Oliver Walters
2c7e0bd321 Merge remote-tracking branch 'inventree/master' 2020-06-04 20:07:59 +10:00
Oliver
96b79397c2 Merge pull request #852 from SchrodingersGat/send-to-customer
Send to customer
2020-06-04 19:55:57 +10:00
Oliver Walters
ca1526405b PEP fixes 2020-06-04 19:51:43 +10:00
Oliver Walters
80019a3ed8 Add forms/views for manually assigning a stock item to a customer 2020-06-04 19:45:41 +10:00
Oliver Walters
d907136264 Display customer in stock item 2020-06-04 19:13:37 +10:00
Oliver Walters
fbd21827fb Add 'customer' field to StockItem 2020-06-04 19:08:33 +10:00
Oliver Walters
4ddabb82ef Add a button to assign stock item to customer 2020-06-04 11:50:55 +10:00
Oliver
c1da4d5207 Merge pull request #850 from SchrodingersGat/bom-division-fix
Fix for case where BOM item quantity is zero
2020-06-04 11:42:39 +10:00
Oliver Walters
a3c0d35b20 Fix for case where BOM item quantity is zero 2020-06-04 11:37:55 +10:00
Oliver
7c7055c0a0 Merge pull request #845 from SchrodingersGat/tweaks
Tweaks
2020-05-30 22:03:15 +10:00
Oliver Walters
dd9584f487 Follow link when a new stock item is created 2020-05-30 20:58:52 +10:00
Oliver Walters
8459de7be2 Display a message if no stock location is set 2020-05-30 20:58:05 +10:00
Oliver Walters
b73044cd44 Merge remote-tracking branch 'inventree/master' 2020-05-29 13:47:19 +10:00
Oliver
55bfdc000b Merge pull request #844 from SchrodingersGat/part-validation-fixes
template parts are now allowed to be variants
2020-05-29 12:51:08 +10:00
Oliver Walters
5f3816212f template parts are now allowed to be variants
- Do not throw an error here!
2020-05-29 12:40:40 +10:00
Oliver
a6dab76ff6 Merge pull request #843 from SchrodingersGat/api-improvements
Api improvements
2020-05-28 21:31:28 +10:00
Oliver Walters
59d9e430b4 Remove unique-together requirement
- This is handled manually via the validate_unique function
2020-05-28 20:38:24 +10:00
Oliver Walters
774e26eb19 Mark some fields as not-required via the API 2020-05-28 20:33:33 +10:00
Oliver
f8e36c5468 Merge pull request #840 from SchrodingersGat/bom-queryset
Allow template parts to be specified for the BOM item
2020-05-27 10:47:46 +10:00
Oliver Walters
9b7b65374d Use rounding decimal field in BomItem form 2020-05-27 10:33:47 +10:00
Oliver Walters
7bcf9bf5be Allow template parts to be specified for the BOM item 2020-05-27 10:06:18 +10:00
Oliver Walters
d0b3e0bd7c Merge remote-tracking branch 'inventree/master' 2020-05-27 09:31:15 +10:00
Oliver
04858f8835 Merge pull request #839 from SchrodingersGat/serializer-fix
Fix serializer for stock item
2020-05-26 23:20:15 +10:00
Oliver Walters
78990a99e5 Fix serializer for stock item 2020-05-26 23:01:30 +10:00
Oliver Walters
fe69a8e7bb Merge remote-tracking branch 'inventree/master' 2020-05-26 21:53:20 +10:00
Oliver
002b896384 Merge pull request #838 from SchrodingersGat/attachies
Attachies
2020-05-26 20:33:06 +10:00
Oliver Walters
e128410d54 Update 'required' status for new serializers
(cherry picked from commit 2306e29743eb25266c78bec5357d1194e0778c58)
2020-05-26 20:29:09 +10:00
Oliver Walters
81e38eeb14 Add some more custom FileField serializers
(cherry picked from commit 7b9ff27baefacc977fef7852e99d8a9bb46a062a)
2020-05-26 20:29:04 +10:00
Oliver Walters
861e30e8d6 Add a special serializer class for FileField which has a custom to_representation function
- This was solving a very subtle bug which will probably only ever apply to a single installation instance
- Future me will most likely not remember what this was for or how it works
- In any case, there we go
- Ref: http://www.cdrf.co/3.9/rest_framework.fields/Field.html

(cherry picked from commit 7305094854)
2020-05-26 20:29:00 +10:00
Oliver Walters
03cc6892ea Merge remote-tracking branch 'inventree/master' 2020-05-26 12:52:17 +10:00
Oliver
3678c940eb Merge pull request #836 from SchrodingersGat/serial-number-fixes
Serial number fixes
2020-05-26 12:16:02 +10:00
Oliver Walters
c0f1966a2c Decimal filter on StockItem adjustment form 2020-05-26 12:08:00 +10:00
Oliver Walters
c92bb78ae8 Stock table display fixes 2020-05-26 12:06:38 +10:00
Oliver Walters
e63622341f Add description field to table filters 2020-05-26 11:57:35 +10:00
Oliver Walters
669a76c921 Add serial number range filtering options for the stock table 2020-05-26 11:54:23 +10:00
Oliver Walters
4cbf2099fa Add stock item filtering by serial number range 2020-05-26 11:49:48 +10:00
Oliver Walters
046a00026c remove debug print 2020-05-26 11:42:30 +10:00
Oliver Walters
47a4ab2ed8 Template changes 2020-05-26 11:38:17 +10:00
Oliver Walters
27ca84fd2a Part view shows next available serial number 2020-05-26 11:34:11 +10:00
Oliver Walters
ae4bfd07da StockItemCreate form now has better logic for auto-detecting the part 2020-05-26 11:31:08 +10:00
Oliver
8384071ac3 Merge pull request #834 from SchrodingersGat/api-bug-fix
Allow API upload of file attachments against StockItemTestResult objects
2020-05-25 22:24:33 +10:00
Oliver Walters
1bf696a052 Allow API upload of file attachments against StockItemTestResult objects 2020-05-25 22:19:28 +10:00
Oliver
835451c02c Merge pull request #833 from SchrodingersGat/latex-fix
Catch some errors related to missing system packages
2020-05-25 15:13:33 +10:00
Oliver Walters
75cdc7eb59 Catch some errors related to missing system packages 2020-05-25 14:57:15 +10:00
Oliver
9ad54c6579 Merge pull request #832 from SchrodingersGat/convert-variant
Convert variant
2020-05-25 14:27:55 +10:00
Oliver Walters
d2c1e9e2b0 Type fixes 2020-05-25 14:24:29 +10:00
Oliver Walters
0d052334e2 Allow stock items to be created for template parts 2020-05-25 14:20:35 +10:00
Oliver Walters
fdf57891fc Form / view / etc for performing StockItem conversion 2020-05-25 14:16:38 +10:00
Oliver Walters
009adaf528 Code to get and test for variants of a part 2020-05-25 13:13:28 +10:00
Oliver
cfc15582c1 Merge pull request #830 from SchrodingersGat/copy-test-results
Copy test results
2020-05-24 21:14:05 +10:00
Oliver Walters
22220493bd Add unit tests 2020-05-24 21:10:00 +10:00
Oliver Walters
95cc3d2a7a Copy test results when a stock item is split or serialized 2020-05-24 21:09:43 +10:00
Oliver
4292a32ab9 Merge pull request #829 from SchrodingersGat/bom-validation
Integer value required for trackable bom item
2020-05-24 20:26:18 +10:00
Oliver Walters
68b9a690f2 Integer value required for trackable bom item 2020-05-24 20:22:15 +10:00
Oliver
8537dc2a85 Merge pull request #828 from SchrodingersGat/api-stuff
Api stuff
2020-05-24 20:12:28 +10:00
Oliver Walters
c44205273c Simplify javascript 2020-05-24 20:05:34 +10:00
Oliver Walters
e4d10279fa Include 'key' field in StockItemTestResult serializer 2020-05-24 20:04:34 +10:00
Oliver Walters
01481ef5c9 Add function to get the number of required tests for a part 2020-05-23 14:28:25 +10:00
Oliver Walters
e63342418f Improve / simplify logic for file attachments against test result object 2020-05-23 11:30:42 +10:00
Oliver Walters
50987f47b0 Add a buttony thing 2020-05-22 23:37:26 +10:00
Oliver Walters
4bd0872b2c Expose some more stock item data over API 2020-05-22 23:33:27 +10:00
Oliver
203062a67a Merge pull request #824 from SchrodingersGat/reporting-app
Reporting app
2020-05-22 23:16:24 +10:00
Oliver Walters
34b40d205e Expose 'part' to the TestReport interface 2020-05-22 23:08:15 +10:00
Oliver Walters
5245442b11 Fixes 2020-05-22 22:27:52 +10:00
Oliver Walters
e6f56cb056 where one or more test report templates exist for a part,
provide a button for all stock-items of that part,
allowing the user to generate and download a test repotr
2020-05-22 22:25:05 +10:00
Oliver Walters
71681bfda1 Add a button if a stock item test report is available 2020-05-22 21:38:05 +10:00
Oliver Walters
1ad7e699a9 PEP 2020-05-22 21:31:21 +10:00
Oliver Walters
0ec880290b Functionality for retrieving test templates associated with a given part 2020-05-22 21:29:58 +10:00
Oliver Walters
7215a563b1 Add PartFilterMixin 2020-05-22 21:22:43 +10:00
Oliver Walters
616f17d08a Reset the report app migrations 2020-05-22 21:01:08 +10:00
Oliver Walters
d6cad372db Add migration 2020-05-22 13:05:30 +10:00
Oliver Walters
865a6db828 Fix subdirectory lookup 2020-05-22 13:05:12 +10:00
Oliver Walters
174c4cc591 Add subclass models for report types 2020-05-22 13:01:21 +10:00
Oliver Walters
251a23d127 Cleanup 2020-05-22 00:09:51 +10:00
Oliver Walters
cab87a6860 Update admin 2020-05-22 00:01:36 +10:00
Oliver Walters
b93ba6339a Option for rendering HTML template 2020-05-21 23:41:47 +10:00
Oliver Walters
c3dcabcaad Render an uploaded template to LaTeX 2020-05-21 23:03:01 +10:00
Oliver Walters
05be4da25c remove test code 2020-05-21 14:06:29 +10:00
Oliver Walters
70c5b27d22 Add ReportAsset model
- Files which can be embedded into a report
2020-05-21 14:05:25 +10:00
Oliver Walters
b78fe88c26 PEP fixes 2020-05-21 13:53:17 +10:00
Oliver Walters
3d8c059a43 Add "report" app
- Define ReportTemplate model which contains a report file template
2020-05-21 13:51:13 +10:00
Oliver
5018f899f7 Update README.md 2020-05-20 10:45:43 +10:00
Oliver Walters
59dfac2c9b Merge branch 'warning-mesages' 2020-05-17 22:58:21 +10:00
Oliver Walters
1e94a597c9 Merge remote-tracking branch 'inventree/master' 2020-05-17 00:42:03 +10:00
Oliver Walters
dcf00d816d Merge remote-tracking branch 'inventree/master' 2020-05-12 22:14:20 +10:00
Oliver Walters
e4872d9f67 Merge remote-tracking branch 'inventree/master' 2020-05-12 09:16:04 +10:00
Oliver Walters
a86513e15d Merge remote-tracking branch 'inventree/master' 2020-05-12 00:29:33 +10:00
Oliver Walters
c5999f7186 Merge remote-tracking branch 'inventree/master' 2020-05-11 23:10:29 +10:00
Oliver Walters
bbf6f6f93d Merge remote-tracking branch 'inventree/master' 2020-05-04 12:04:02 +10:00
Oliver Walters
15011b7b20 Merge remote-tracking branch 'inventree/master' 2020-05-04 09:46:43 +10:00
Oliver Walters
1c3878829d Merge remote-tracking branch 'inventree/master' 2020-05-04 09:39:19 +10:00
Oliver Walters
fb0ebbb1e4 Merge remote-tracking branch 'inventree/master' 2020-05-02 21:05:00 +10:00
Oliver Walters
937211288e Merge remote-tracking branch 'inventree/master' 2020-05-02 17:30:08 +10:00
Oliver Walters
6912899f41 Merge remote-tracking branch 'inventree/master' 2020-05-02 15:37:24 +10:00
Oliver Walters
094ef38e27 Merge remote-tracking branch 'inventree/master' 2020-05-02 15:29:47 +10:00
Oliver Walters
36ad69091b Merge remote-tracking branch 'inventree/master' 2020-04-28 12:34:47 +10:00
Oliver Walters
351e825ba8 Merge remote-tracking branch 'inventree/master' 2020-04-28 10:51:55 +10:00
Oliver Walters
b338834146 Merge remote-tracking branch 'inventree/master' 2020-04-27 22:18:45 +10:00
Oliver Walters
87d8b4674a Merge remote-tracking branch 'inventree/master' 2020-04-20 09:58:49 +10:00
Oliver Walters
c49cd9ffde Merge remote-tracking branch 'inventree/master' 2020-04-20 01:28:31 +10:00
Oliver Walters
51e2f5c46b Merge remote-tracking branch 'inventree/master' 2020-04-18 15:46:33 +10:00
Oliver Walters
4822d3fd63 Merge remote-tracking branch 'inventree/master' 2020-04-17 21:49:00 +10:00
Oliver Walters
cbfb3b55e6 Merge remote-tracking branch 'upstream/master' 2020-04-17 19:14:15 +10:00
Oliver Walters
762d735618 Merge remote-tracking branch 'inventree/master' 2020-04-16 21:55:59 +10:00
Oliver Walters
2e1c4e9792 Merge remote-tracking branch 'inventree/master' 2020-04-13 20:43:00 +10:00
Oliver Walters
a8ceddc8e4 Merge remote-tracking branch 'inventree/master' 2020-04-12 01:05:42 +10:00
Oliver Walters
ba2b1ce581 Merge remote-tracking branch 'inventree/master' 2020-04-10 01:12:11 +10:00
Oliver Walters
4a02a90954 Merge remote-tracking branch 'inventree/master' 2020-04-07 00:08:44 +10:00
Oliver Walters
93eeeec2f3 Merge remote-tracking branch 'inventree/master' 2020-04-06 21:15:06 +10:00
Oliver Walters
b8f7555a73 Merge remote-tracking branch 'inventree/master' 2020-04-06 16:25:48 +10:00
Oliver Walters
efaa532162 Merge remote-tracking branch 'inventree/master' 2020-04-05 22:07:57 +10:00
Oliver Walters
428b52693a Merge remote-tracking branch 'inventree/master' 2020-04-05 01:00:00 +11:00
Oliver Walters
55e831f4b4 Merge remote-tracking branch 'inventree/master' 2020-04-03 14:24:35 +11:00
Oliver Walters
aada5f91cb Merge remote-tracking branch 'inventree/master' 2020-03-31 22:15:58 +11:00
Oliver Walters
b0edd0eb05 Merge remote-tracking branch 'inventree/master' 2020-03-30 19:06:30 +11:00
Oliver Walters
5b77ff4a4c Merge remote-tracking branch 'inventree/master' 2020-03-26 18:08:34 +11:00
Oliver Walters
ed6abcdf32 Merge remote-tracking branch 'inventree/master' 2020-03-22 20:20:22 +11:00
Oliver Walters
dc0a0f9dc2 Merge branch 'master' of https://github.com/inventree/inventree 2020-03-22 20:14:34 +11:00
Oliver Walters
02ec1d4fa2 Merge remote-tracking branch 'inventree/master' 2020-03-19 10:29:26 +11:00
Oliver Walters
d8f5255572 Merge remote-tracking branch 'inventree/master' 2020-03-18 22:24:52 +11:00
Oliver Walters
7424cc1352 Merge remote-tracking branch 'inventree/master' 2020-03-18 21:33:09 +11:00
Oliver Walters
41259f520f Merge remote-tracking branch 'inventree/master' 2020-03-18 21:12:49 +11:00
Oliver Walters
388b26dad2 Merge remote-tracking branch 'inventree/master' 2020-02-25 12:42:49 +11:00
Oliver Walters
ef83480f65 Merge remote-tracking branch 'inventree/master' 2020-02-19 00:03:32 +11:00
Oliver Walters
0498fd633a Merge remote-tracking branch 'inventree/master' 2020-02-12 12:56:17 +11:00
Oliver Walters
3479528d5b Merge branch 'cascading-bom' 2020-02-11 22:48:33 +11:00
Oliver Walters
bb4c25ba68 Merge remote-tracking branch 'inventree/master' 2020-02-11 20:36:13 +11:00
Oliver Walters
bb0c991965 Merge branch 'inventree-settings' 2020-02-03 21:34:08 +11:00
Oliver Walters
8412885e09 Merge remote-tracking branch 'inventree/master' 2020-02-02 22:26:18 +11:00
Oliver Walters
22e3dc634b Merge remote-tracking branch 'inventree/master' 2020-02-02 21:11:52 +11:00
Oliver Walters
e03d8f55ea Merge remote-tracking branch 'inventree/master' 2020-02-02 18:10:05 +11:00
Oliver Walters
40037d826d Merge remote-tracking branch 'inventree/master' 2020-02-02 12:48:04 +11:00
Oliver Walters
8d924eb300 Merge remote-tracking branch 'inventree/master' 2020-01-19 21:39:22 +11:00
Oliver Walters
07f3cd5644 Merge remote-tracking branch 'inventree/master' 2020-01-07 21:31:28 +11:00
Oliver Walters
f217650cec Merge remote-tracking branch 'inventree/master' 2020-01-06 21:11:00 +11:00
Oliver Walters
07de23f120 Merge remote-tracking branch 'inventree/master' 2020-01-06 10:11:18 +11:00
Oliver Walters
881931c6b1 Merge remote-tracking branch 'inventree/master' 2020-01-02 21:08:56 +11:00
Oliver Walters
6bbe818e9c Merge remote-tracking branch 'inventree/master' 2019-12-09 22:27:06 +11:00
Oliver Walters
f6d5f2e426 Merge remote-tracking branch 'inventree/master' 2019-12-05 23:11:54 +11:00
Oliver Walters
0e57a4caec Merge remote-tracking branch 'inventree/master' 2019-12-05 16:36:23 +11:00
Oliver Walters
b29e1ded64 Merge branch 'decimal-quantity' 2019-11-19 21:47:22 +11:00
Oliver Walters
6e54c49142 Merge remote-tracking branch 'inventree/master' 2019-11-16 20:45:34 +11:00
Oliver Walters
f7a1fb0a9d Merge remote-tracking branch 'upstream/master' 2019-09-30 13:54:49 +10:00
Oliver Walters
cfe33deb8e Merge remote-tracking branch 'upstream/master' 2019-09-29 09:04:47 +10:00
Oliver Walters
e891f117f3 Merge remote-tracking branch 'inventree/master' 2019-09-27 10:25:11 +10:00
Oliver Walters
6d628a77fd Merge remote-tracking branch 'inventree/master' 2019-09-24 08:10:00 +10:00
Oliver Walters
14217ff648 Merge remote-tracking branch 'inventree/master' 2019-09-24 08:06:11 +10:00
Oliver Walters
d6749dfb24 Merge remote-tracking branch 'inventree/master' 2019-09-22 22:34:34 +10:00
Oliver Walters
41d91a8f9b Merge remote-tracking branch 'inventree/master' 2019-09-19 15:43:15 +10:00
Oliver Walters
119cccc318 Merge remote-tracking branch 'inventree/master' 2019-09-17 20:32:30 +10:00
Oliver Walters
0a7ea27e9f Merge remote-tracking branch 'inventree/master' 2019-09-17 14:22:04 +10:00
Oliver Walters
420b16104c Merge remote-tracking branch 'inventree/master' 2019-09-16 00:09:20 +10:00
Oliver Walters
f64758eb03 Merge remote-tracking branch 'inventree/master' 2019-09-15 23:29:36 +10:00
Oliver Walters
d0ad3f0e37 Merge remote-tracking branch 'inventree/master' 2019-09-15 22:28:55 +10:00
Oliver Walters
5fde9777fb Merge remote-tracking branch 'inventree/master' 2019-09-14 00:19:17 +10:00
Oliver Walters
4b33b15dd2 Merge remote-tracking branch 'inventree/master' 2019-09-13 23:38:07 +10:00
Oliver Walters
2be99be4de Merge remote-tracking branch 'inventree/master' 2019-09-13 16:41:34 +10:00
Oliver Walters
625ab33bc8 Merge remote-tracking branch 'inventree/master' 2019-09-13 15:38:41 +10:00
Oliver Walters
9681372a84 Merge remote-tracking branch 'inventree/master' 2019-09-13 11:20:39 +10:00
Oliver Walters
0683911076 Merge remote-tracking branch 'inventree/master' 2019-09-12 22:55:58 +10:00
Oliver Walters
d703e48ecb Merge remote-tracking branch 'inventree/master' 2019-09-10 14:50:47 +10:00
Oliver Walters
015ed66967 Merge remote-tracking branch 'inventree/master' 2019-09-09 20:54:55 +10:00
Oliver Walters
0a4f7a55b8 Merge remote-tracking branch 'inventree/master' 2019-09-09 16:20:01 +10:00
Oliver Walters
a6e850e39f Merge remote-tracking branch 'inventree/master' 2019-09-09 15:03:57 +10:00
Oliver Walters
abecb4856f Merge remote-tracking branch 'inventree/master' 2019-09-09 00:09:58 +10:00
Oliver Walters
dbf88f8485 Merge remote-tracking branch 'upstream/master' 2019-09-08 01:48:20 +10:00
Oliver Walters
83af318ad0 Merge remote-tracking branch 'inventree/master' 2019-09-07 21:23:50 +10:00
Oliver Walters
7be1edd896 Merge remote-tracking branch 'inventree/master' 2019-09-07 20:37:30 +10:00
Oliver Walters
d6ca21273d Merge remote-tracking branch 'inventree/master' 2019-09-07 15:03:54 +10:00
Oliver Walters
dd934f0e34 Merge remote-tracking branch 'inventree/master' 2019-09-06 14:42:40 +10:00
Oliver Walters
612851fd48 Merge remote-tracking branch 'inventree/master' 2019-09-06 11:19:48 +10:00
Oliver Walters
755962c6a2 Merge remote-tracking branch 'inventree/master' 2019-09-05 20:13:17 +10:00
Oliver Walters
153dde4129 Merge remote-tracking branch 'inventree/master' 2019-09-04 11:02:27 +10:00
Oliver Walters
8f3a022b3c Merge remote-tracking branch 'inventree/master' 2019-09-04 08:57:24 +10:00
Oliver Walters
017bf187f9 Merge remote-tracking branch 'inventree/master' 2019-09-03 10:42:14 +10:00
Oliver Walters
7b8d7c9fe0 Merge remote-tracking branch 'upstream/master' 2019-09-01 23:33:39 +10:00
Oliver Walters
d319c79abb Merge remote-tracking branch 'upstream/master' 2019-08-30 02:59:01 +10:00
Oliver Walters
1e62528d2a Merge remote-tracking branch 'upstream/master' 2019-08-29 21:37:03 +10:00
Oliver Walters
7ae7c19a24 Merge remote-tracking branch 'inventree/master' 2019-08-29 08:21:21 +10:00
Oliver Walters
0dce5fab7b Merge remote-tracking branch 'inventree/master' 2019-08-28 19:48:46 +10:00
Oliver Walters
d1dc0fae19 Merge remote-tracking branch 'inventree/master' 2019-08-15 22:02:45 +10:00
Oliver Walters
dd33209b1c Merge remote-tracking branch 'inventree/master' 2019-08-15 19:54:21 +10:00
Oliver Walters
c3fe101571 Merge remote-tracking branch 'inventree/master' 2019-08-15 13:41:50 +10:00
Oliver Walters
2c1b20b5d5 Merge branch 'mysql-install' 2019-08-14 13:19:13 +10:00
Oliver Walters
c1ab004c0c Merge remote-tracking branch 'inventree/master' 2019-08-09 20:37:46 +10:00
Oliver Walters
348f2e1df8 Merge remote-tracking branch 'inventree/master' 2019-08-07 10:29:32 +10:00
Oliver Walters
3098c8c155 Merge branch 'bom-output' 2019-08-07 09:27:31 +10:00
Oliver Walters
55ed483b13 Merge remote-tracking branch 'inventree/master' 2019-08-07 08:55:01 +10:00
Oliver Walters
84ea95181d Merge remote-tracking branch 'inventree/master' 2019-08-02 22:37:26 +10:00
Oliver Walters
163f076565 Merge remote-tracking branch 'inventree/master' 2019-07-23 12:07:13 +10:00
Oliver Walters
7d2d6a79e4 Merge remote-tracking branch 'inventree/master' 2019-07-12 00:20:54 +10:00
Oliver Walters
40695b3288 Merge remote-tracking branch 'inventree/master' 2019-07-10 20:13:35 +10:00
Oliver Walters
bd9d5b92dc Merge remote-tracking branch 'inventree/master' 2019-06-25 21:04:02 +10:00
Oliver Walters
39a62d1cb9 Merge remote-tracking branch 'origin/master' 2019-06-25 16:39:50 +10:00
Oliver Walters
fd5b902e1f Merge remote-tracking branch 'inventree/master' 2019-06-25 16:39:41 +10:00
Oliver Walters
c7877c67ff Add a simple endpoint with server information 2019-06-24 23:51:46 +10:00
Oliver Walters
5d0369958f Merge remote-tracking branch 'inventree/master' 2019-06-24 08:27:58 +10:00
Oliver Walters
6da0106aa2 Merge remote-tracking branch 'inventree/master' 2019-06-20 21:49:30 +10:00
Oliver Walters
e0bfda2b14 Merge remote-tracking branch 'inventree/master' 2019-06-20 21:49:19 +10:00
Oliver Walters
e5c2ee5587 Merge remote-tracking branch 'inventree/master' 2019-06-19 08:12:14 +10:00
Oliver Walters
d4391f99bb Merge remote-tracking branch 'inventree/master' 2019-06-18 23:26:48 +10:00
Oliver Walters
346c713cd2 Merge remote-tracking branch 'inventree/master' 2019-06-18 22:26:47 +10:00
Oliver Walters
ec44a480a8 Merge remote-tracking branch 'inventree/master' 2019-06-18 11:51:02 +10:00
Oliver Walters
f417ddb8e0 Merge remote-tracking branch 'inventree/master' 2019-06-18 01:50:50 +10:00
Oliver Walters
1b43f151df Merge remote-tracking branch 'inventree/master' 2019-06-17 23:28:35 +10:00
Oliver Walters
6b5bed7786 Merge remote-tracking branch 'inventree/master' 2019-06-13 23:07:54 +10:00
Oliver Walters
c906cbe2c2 Merge branch 'stock-endpoint' 2019-06-13 23:06:08 +10:00
Oliver Walters
1dea5f1624 Merge remote-tracking branch 'inventree/master' 2019-06-13 22:54:10 +10:00
Oliver Walters
0fea7f2a22 Merge remote-tracking branch 'inventree/master' 2019-06-11 08:57:14 +10:00
Oliver Walters
45d19e3a4e Merge remote-tracking branch 'inventree/master' 2019-06-11 08:40:11 +10:00
Oliver Walters
8a46dda07f Merge remote-tracking branch 'inventree/master' 2019-06-10 23:22:04 +10:00
Oliver Walters
166b41196b Merge remote-tracking branch 'inventree/master' 2019-06-04 21:22:36 +10:00
Oliver Walters
a13e50445e Merge branch 'tweeeek' 2019-06-03 14:19:21 +10:00
Oliver Walters
c00b19bc5b Merge remote-tracking branch 'inventree/master' 2019-06-02 20:42:37 +10:00
Oliver Walters
9577e4e505 Merge remote-tracking branch 'inventree/master'
# Conflicts:
#	InvenTree/static/script/inventree/stock.js
#	InvenTree/stock/forms.py
#	InvenTree/stock/urls.py
#	InvenTree/stock/views.py
2019-06-02 12:51:56 +10:00
Oliver Walters
72dc75512b Pass list of selected stock items to the view 2019-05-29 22:23:45 +10:00
Oliver Walters
f4a052ee2b Redirect non-ajax forms to / 2019-05-29 22:11:03 +10:00
Oliver Walters
080f9da9c8 Beginning to move the stocktake forms server side 2019-05-29 22:05:13 +10:00
Oliver Walters
1c1cc670f8 Merge remote-tracking branch 'inventree/master' 2019-05-29 01:06:27 +10:00
Oliver Walters
141d9b779d Merge remote-tracking branch 'inventree/master' 2019-05-26 16:09:20 +10:00
Oliver Walters
dbfa812d37 Merge remote-tracking branch 'inventree/master' 2019-05-26 00:48:45 +10:00
Oliver Walters
026ffde807 Merge remote-tracking branch 'inventree/master' 2019-05-25 22:11:21 +10:00
Oliver Walters
e07d7e3874 Merge remote-tracking branch 'inventree/master' 2019-05-23 23:24:11 +10:00
Oliver Walters
413e996e92 Merge remote-tracking branch 'inventree/master' 2019-05-23 23:01:17 +10:00
Oliver Walters
bebf2c9bee Merge remote-tracking branch 'inventree/master' 2019-05-23 00:48:05 +10:00
Oliver Walters
afb927258c Merge remote-tracking branch 'inventree/master' 2019-05-21 16:37:16 +10:00
Oliver Walters
a15f46c972 Merge remote-tracking branch 'inventree/master' 2019-05-21 14:13:30 +10:00
Oliver Walters
92b0ed6599 Merge remote-tracking branch 'inventree/master' 2019-05-21 08:58:08 +10:00
Oliver Walters
29ab493cbe Merge remote-tracking branch 'inventree/master' 2019-05-21 00:58:19 +10:00
Oliver Walters
90915f8dc0 Merge remote-tracking branch 'inventree/master' 2019-05-19 00:14:35 +10:00
Oliver Walters
1f4471ccc3 Merge remote-tracking branch 'inventree/master' 2019-05-18 15:40:50 +10:00
Oliver Walters
5d4ec2154b Merge remote-tracking branch 'inventree/master' 2019-05-16 23:15:02 +10:00
Oliver Walters
9d9f30e41f Merge branch 'secondary-modals' 2019-05-14 23:53:14 +10:00
Oliver Walters
e3a8bb23c1 Merge remote-tracking branch 'inventree/master' 2019-05-14 18:54:23 +10:00
Oliver Walters
787ab0a2e4 Merge remote-tracking branch 'inventree/master' 2019-05-13 23:07:12 +10:00
Oliver Walters
c140ecf14b Merge remote-tracking branch 'inventree/master' 2019-05-13 19:00:51 +10:00
Oliver Walters
980116b33b Merge remote-tracking branch 'inventree/master' 2019-05-12 20:58:06 +10:00
Oliver Walters
142a7659bd Merge remote-tracking branch 'inventree/master' 2019-05-12 16:39:02 +10:00
Oliver Walters
6fbe588aee Merge branch 'case-insensitive-names' 2019-05-11 20:28:54 +10:00
Oliver Walters
17eb8237da Merge remote-tracking branch 'inventree/master' 2019-05-11 09:00:41 +10:00
Oliver Walters
f11cee7197 Merge remote-tracking branch 'inventree/master' 2019-05-10 23:29:16 +10:00
Oliver Walters
1b28326c5e Merge branch 'part-revision' 2019-05-10 20:19:21 +10:00
Oliver Walters
6ffb6db248 Merge remote-tracking branch 'inventree/master' 2019-05-10 08:52:45 +10:00
Oliver Walters
9b0825739a Merge remote-tracking branch 'inventree/master' 2019-05-09 23:07:42 +10:00
Oliver Walters
b42f7fce44 Merge remote-tracking branch 'inventree/master' 2019-05-09 18:44:29 +10:00
Oliver Walters
30f491795d Merge remote-tracking branch 'inventree/master' 2019-05-09 18:33:36 +10:00
Oliver Walters
55f7557b5e Merge remote-tracking branch 'inventree/master' 2019-05-09 18:30:49 +10:00
Oliver Walters
5a0de7088b Merge remote-tracking branch 'inventree/master' 2019-05-09 12:03:36 +10:00
Oliver Walters
9319b9f433 Merge remote-tracking branch 'inventree/master' 2019-05-09 00:53:20 +10:00
Oliver Walters
b8942acfed Merge remote-tracking branch 'inventree/master' 2019-05-09 00:44:19 +10:00
Oliver Walters
a0d8fbede3 Merge remote-tracking branch 'inventree/master' 2019-05-09 00:42:50 +10:00
Oliver Walters
8e8930d51f Merge branch 'help-text' 2019-05-09 00:20:31 +10:00
Oliver Walters
09b7578c35 Merge remote-tracking branch 'inventree/master' 2019-05-08 23:33:55 +10:00
Oliver Walters
fdd4d09714 Merge remote-tracking branch 'inventree/master' 2019-05-08 23:05:49 +10:00
Oliver Walters
0deb6e8bea Merge remote-tracking branch 'inventree/master' 2019-05-08 22:09:40 +10:00
Oliver Walters
586bad4876 Merge remote-tracking branch 'inventree/master' 2019-05-07 21:17:42 +10:00
Oliver Walters
47fd317a11 Merge remote-tracking branch 'inventree/master' 2019-05-07 14:53:31 +10:00
Oliver Walters
0c229ede24 Merge remote-tracking branch 'inventree/master' 2019-05-07 10:30:07 +10:00
Oliver Walters
64a6ee0f3b Merge remote-tracking branch 'inventree/master' 2019-05-07 08:14:12 +10:00
Oliver Walters
364f78d20c Merge remote-tracking branch 'inventree/master' 2019-05-07 00:19:18 +10:00
Oliver Walters
ff0d163a95 Limit SupplierPart choices in EditStockItem view 2019-05-06 18:05:29 +10:00
Oliver Walters
a7a37437a1 Merge remote-tracking branch 'inventree/master' 2019-05-06 18:00:43 +10:00
Oliver Walters
e333f5f726 Merge remote-tracking branch 'inventree/master' 2019-05-06 07:36:37 +10:00
Oliver Walters
c822450792 Merge remote-tracking branch 'inventree/master' 2019-05-05 20:22:41 +10:00
Oliver Walters
e6d77273c4 Merge remote-tracking branch 'inventree/master' 2019-05-05 11:53:50 +10:00
Oliver Walters
c203c3542f Merge remote-tracking branch 'inventree/master' 2019-05-05 11:49:58 +10:00
Oliver Walters
d218f07940 Merge remote-tracking branch 'inventree/master' 2019-05-05 01:07:35 +10:00
Oliver Walters
0da2999c75 Merge remote-tracking branch 'inventree/master' 2019-05-05 00:39:36 +10:00
Oliver Walters
67cfd22084 Merge branch 'part-image-hover' 2019-05-05 00:30:23 +10:00
Oliver Walters
d97484b30b Merge remote-tracking branch 'inventree/master' 2019-05-04 22:03:18 +10:00
Oliver Walters
d5ad888b0a Merge remote-tracking branch 'inventree/master' 2019-05-04 21:59:48 +10:00
Oliver Walters
a7cec1627f Merge remote-tracking branch 'inventree/master' 2019-05-04 11:49:49 +10:00
Oliver Walters
e42a1b7b88 Merge remote-tracking branch 'inventree/master' 2019-05-04 10:47:55 +10:00
Oliver Walters
dc03283e14 Merge branch 'image-upload-fix' 2019-05-04 00:43:47 +10:00
Oliver Walters
4aef7643a0 Fixed part image upload
- Image was being saved twice
- Don't call super().post in AjaxUpdateView
- Instead, handle properly
2019-05-04 00:37:08 +10:00
Oliver Walters
ac17cf0121 Merge remote-tracking branch 'inventree/master' 2019-05-04 00:03:46 +10:00
Oliver Walters
e19061c902 Merge remote-tracking branch 'inventree/master' 2019-05-03 23:53:37 +10:00
Oliver Walters
db71993905 Merge remote-tracking branch 'inventree/master' 2019-05-03 08:08:31 +10:00
Oliver Walters
3f8f7ed32c Merge remote-tracking branch 'inventree/master' 2019-05-02 21:33:51 +10:00
Oliver Walters
b7ac86fab4 Merge remote-tracking branch 'inventree/master' 2019-05-02 21:30:34 +10:00
Oliver Walters
79e0f972e7 Merge remote-tracking branch 'inventree/master' 2019-05-02 17:47:17 +10:00
Oliver Walters
255d754045 Merge remote-tracking branch 'inventree/master' 2019-05-02 01:05:08 +10:00
Oliver Walters
385c13148d Merge branch 'migration-test' 2019-05-02 01:03:08 +10:00
Oliver Walters
4de3445c58 Merge remote-tracking branch 'inventree/master' 2019-05-02 00:56:42 +10:00
Oliver Walters
a2314074d3 Merge remote-tracking branch 'inventree/master' 2019-05-02 00:30:17 +10:00
Oliver Walters
460ff571e4 Merge remote-tracking branch 'inventree/master' 2019-05-02 00:26:34 +10:00
Oliver Walters
3a10d235c1 Merge remote-tracking branch 'inventree/master' 2019-04-29 00:05:18 +10:00
Oliver Walters
207d2bb4d3 Merge remote-tracking branch 'inventree/master' 2019-04-28 21:26:33 +10:00
Oliver Walters
2076faaa6c Added docstring 2019-04-28 11:49:20 +10:00
Oliver Walters
ec166c906f Merge remote-tracking branch 'inventree/master' 2019-04-28 11:29:23 +10:00
Oliver Walters
c0e69d7a99 Merge remote-tracking branch 'inventree/master' 2019-04-28 01:18:32 +10:00
Oliver Walters
a8348aa674 Merge remote-tracking branch 'inventree/master' 2019-04-27 18:01:57 +10:00
Oliver Walters
b17590942d Merge remote-tracking branch 'inventree/master' 2019-04-27 17:56:49 +10:00
Oliver Walters
062b3fd0fe Merge remote-tracking branch 'inventree/master' 2019-04-27 15:32:46 +10:00
Oliver Walters
f2f40e4758 Merge branch 'stockitem-note' 2019-04-27 13:56:41 +10:00
Oliver Walters
922feec7f4 Merge remote-tracking branch 'inventree/master' 2019-04-27 01:08:14 +10:00
Oliver Walters
64636a6d60 Merge remote-tracking branch 'inventree/master' 2019-04-27 01:05:12 +10:00
Oliver Walters
ac46a4a413 Merge remote-tracking branch 'inventree/master' 2019-04-26 21:44:44 +10:00
Oliver Walters
7593d855cb Merge remote-tracking branch 'inventree/master' 2019-04-26 21:40:26 +10:00
Oliver Walters
27c7f6589c Merge remote-tracking branch 'inventree/master' 2019-04-26 21:25:00 +10:00
Oliver Walters
edad4f9cf1 Merge branch 'master' of https://github.com/SchrodingersGat/InvenTree
# Conflicts:
#	Makefile
2019-04-26 21:24:03 +10:00
Oliver Walters
14e9b71ebb Remove comment line in Makefile which doesn't play nice on Windows 2019-04-26 18:51:37 +10:00
729 changed files with 117638 additions and 13637 deletions

View File

@@ -1,8 +1,6 @@
[run]
source = ./InvenTree
omit =
# Do not run coverage on migration files
*/migrations/*
InvenTree/manage.py
InvenTree/setup.py
InvenTree/InvenTree/middleware.py

48
.github/workflows/coverage.yaml vendored Normal file
View File

@@ -0,0 +1,48 @@
# Perform CI checks, and calculate code coverage
name: SQLite
on: ["push", "pull_request"]
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
pip3 install invoke
invoke install
- 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
- name: Check Migration Files
run: python3 ci/check_migration_files.py
- name: Upload Coverage Report
run: coveralls

18
.github/workflows/docker_build.yaml vendored Normal file
View File

@@ -0,0 +1,18 @@
# Test that the docker file builds correctly
name: Docker
on: ["push", "pull_request"]
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Server Image
run: cd docker/inventree && docker build . --tag inventree:$(date +%s)
- name: Build nginx Image
run: cd docker/nginx && docker build . --tag nxinx:$(date +%s)

38
.github/workflows/docker_publish.yaml vendored Normal file
View File

@@ -0,0 +1,38 @@
# Publish docker images to dockerhub
name: Docker Publish
on:
release:
types: [published]
jobs:
server_image:
name: Push InvenTree web server image to dockerhub
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v2
- name: Push to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: inventree/inventree
tag_with_ref: true
context: docker/inventree
nginx_image:
name: Push InvenTree nginx image to dockerhub
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v2
- name: Push to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: inventree/nginx
tag_with_ref: true
context: docker/nginx

51
.github/workflows/mysql.yaml vendored Normal file
View File

@@ -0,0 +1,51 @@
# MySQL Unit Testing
name: MySQL
on: ["push", "pull_request"]
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

47
.github/workflows/postgresql.yaml vendored Normal file
View File

@@ -0,0 +1,47 @@
# PostgreSQL Unit Testing
name: PostgreSQL
on: ["push", "pull_request"]
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

27
.github/workflows/style.yaml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Style Checks
on: ["push", "pull_request"]
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

View File

@@ -1,17 +0,0 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
formats: all
# Optionally set the version of Python and requirements required to build your docs
python:
version: 3.5
install:
- requirements: docs/requirements.txt

View File

@@ -1,27 +0,0 @@
dist: xenial
language: python
python:
- 3.6
- 3.7
addons:
apt-packages:
- sqlite3
before_install:
- sudo apt-get update
- sudo apt-get install gettext
- make install
- make migrate
- cd InvenTree && python3 manage.py createsuperuser --username InvenTreeAdmin --email admin@inventree.com --noinput && cd ..
script:
- cd InvenTree && python3 manage.py makemigrations && cd ..
- python3 ci/check_migration_files.py
- make coverage
- make translate
- make style
after_success:
- coveralls

View File

@@ -6,7 +6,7 @@ No pushing to master! New featues must be submitted in a separate branch (one br
## Include 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 `make migrate` and commit the migration files before submitting the PR.
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
@@ -14,7 +14,7 @@ Any PRs which update translatable strings (i.e. text strings that will appear in
*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.*
To perform this step, simply run `make_translate` from the top level directory before submitting the PR.
To perform this step, simply run `invoke translate` from the top level directory before submitting the PR.
## Testing
@@ -22,9 +22,8 @@ Any new code should be covered by unit tests - a submitted PR may not be accepte
## 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.github.io
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
Sumbitted Python code is automatically checked against PEP style guidelines. Locally you can run `make style` to ensure the style checks will pass, before submitting the PR.
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.

View File

@@ -5,7 +5,9 @@ Main JSON interface views
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
import logging
from django.utils.translation import ugettext_lazy as _
from django.http import JsonResponse
from django_filters.rest_framework import DjangoFilterBackend
@@ -16,15 +18,16 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from .views import AjaxView
from .version import inventreeVersion, inventreeInstanceName
from .version import inventreeVersion, inventreeApiVersion, inventreeInstanceName
from .status import is_worker_running
from plugins import plugins as inventree_plugins
# Load barcode plugins
print("Loading barcode plugins")
barcode_plugins = inventree_plugins.load_barcode_plugins()
print("Loading action plugins")
logger = logging.getLogger("inventree")
logger.info("Loading action plugins...")
action_plugins = inventree_plugins.load_action_plugins()
@@ -33,17 +36,38 @@ class InfoView(AjaxView):
Use to confirm that the server is running, etc.
"""
permission_classes = [permissions.AllowAny]
def get(self, request, *args, **kwargs):
data = {
'server': 'InvenTree',
'version': inventreeVersion(),
'instance': inventreeInstanceName(),
'apiVersion': inventreeApiVersion(),
'worker_running': is_worker_running(),
}
return JsonResponse(data)
class NotFoundView(AjaxView):
"""
Simple JSON view when accessing an invalid API view.
"""
permission_classes = [permissions.AllowAny]
def get(self, request, *args, **kwargs):
data = {
'details': _('API endpoint not found'),
'url': request.build_absolute_uri(),
}
return JsonResponse(data, status=404)
class AttachmentMixin:
"""
Mixin for creating attachment objects,
@@ -100,66 +124,3 @@ class ActionPluginView(APIView):
'error': _("No matching action found"),
"action": action,
})
class BarcodePluginView(APIView):
"""
Endpoint for handling barcode scan requests.
Barcode data are decoded by the client application,
and sent to this endpoint (as a JSON object) for validation.
A barcode could follow the internal InvenTree barcode format,
or it could match to a third-party barcode format (e.g. Digikey).
"""
permission_classes = [
permissions.IsAuthenticated,
]
def post(self, request, *args, **kwargs):
response = {}
barcode_data = request.data.get('barcode', None)
print("Barcode data:")
print(barcode_data)
if barcode_data is None:
response['error'] = _('No barcode data provided')
else:
# Look for a barcode plugin that knows how to handle the data
for plugin_class in barcode_plugins:
# Instantiate the plugin with the provided plugin data
plugin = plugin_class(barcode_data)
if plugin.validate():
# Plugin should return a dict response
response = plugin.decode()
if type(response) is dict:
if 'success' not in response.keys() and 'error' not in response.keys():
response['success'] = _('Barcode successfully decoded')
else:
response = {
'error': _('Barcode plugin returned incorrect response')
}
response['plugin'] = plugin.plugin_name()
response['hash'] = plugin.hash()
break
if 'error' not in response and 'success' not in response:
response = {
'error': _('Unknown barcode format'),
}
# Include the original barcode data
response['barcode_data'] = barcode_data
return Response(response)

View File

@@ -0,0 +1,94 @@
"""
Helper functions for performing API unit tests
"""
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from rest_framework.test import APITestCase
class InvenTreeAPITestCase(APITestCase):
"""
Base class for running InvenTree API tests
"""
# User information
username = 'testuser'
password = 'mypassword'
email = 'test@testing.com'
superuser = False
auto_login = True
# Set list of roles automatically associated with the user
roles = []
def setUp(self):
super().setUp()
# Create a user to log in with
self.user = get_user_model().objects.create_user(
username=self.username,
password=self.password,
email=self.email
)
# Create a group for the user
self.group = Group.objects.create(name='my_test_group')
self.user.groups.add(self.group)
if self.superuser:
self.user.is_superuser = True
self.user.save()
for role in self.roles:
self.assignRole(role)
if self.auto_login:
self.client.login(username=self.username, password=self.password)
def assignRole(self, role):
"""
Set the user roles for the registered user
"""
# role is of the format 'rule.permission' e.g. 'part.add'
rule, perm = role.split('.')
for ruleset in self.group.rule_sets.all():
if ruleset.name == rule:
if perm == 'view':
ruleset.can_view = True
elif perm == 'change':
ruleset.can_change = True
elif perm == 'delete':
ruleset.can_delete = True
elif perm == 'add':
ruleset.can_add = True
ruleset.save()
break
def get(self, url, data={}, code=200):
"""
Issue a GET request
"""
response = self.client.get(url, data, format='json')
self.assertEqual(response.status_code, code)
return response
def post(self, url, data):
"""
Issue a POST request
"""
response = self.client.post(url, data=data, format='json')
return response

View File

@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
import logging
from django.apps import AppConfig
from django.core.exceptions import AppRegistryNotReady
import InvenTree.tasks
logger = logging.getLogger("inventree")
class InvenTreeConfig(AppConfig):
name = 'InvenTree'
def ready(self):
self.start_background_tasks()
def start_background_tasks(self):
try:
from django_q.models import Schedule
except (AppRegistryNotReady):
return
logger.info("Starting background tasks...")
InvenTree.tasks.schedule_task(
'InvenTree.tasks.delete_successful_tasks',
schedule_type=Schedule.DAILY,
)
InvenTree.tasks.schedule_task(
'InvenTree.tasks.check_for_updates',
schedule_type=Schedule.DAILY
)
InvenTree.tasks.schedule_task(
'InvenTree.tasks.heartbeat',
schedule_type=Schedule.MINUTES,
minutes=15
)

View File

@@ -7,8 +7,56 @@ Provides extra global data to all templates.
from InvenTree.status_codes import SalesOrderStatus, PurchaseOrderStatus
from InvenTree.status_codes import BuildStatus, StockStatus
import InvenTree.status
from users.models import RuleSet
def health_status(request):
"""
Provide system health status information to the global context.
- Not required for AJAX requests
- Do not provide if it is already provided to the context
"""
if request.path.endswith('.js'):
# Do not provide to script requests
return {}
if hasattr(request, '_inventree_health_status'):
# Do not duplicate efforts
return {}
request._inventree_health_status = True
status = {
'django_q_running': InvenTree.status.is_worker_running(),
}
all_healthy = True
for k in status.keys():
if status[k] is not True:
all_healthy = False
status['system_healthy'] = all_healthy
status['up_to_date'] = InvenTree.version.isInvenTreeUpToDate()
return status
def status_codes(request):
"""
Provide status code enumerations.
"""
if hasattr(request, '_inventree_status_codes'):
# Do not duplicate efforts
return {}
request._inventree_status_codes = True
return {
# Expose the StatusCode classes to the templates
@@ -17,3 +65,52 @@ def status_codes(request):
'BuildStatus': BuildStatus,
'StockStatus': StockStatus,
}
def user_roles(request):
"""
Return a map of the current roles assigned to the user.
Roles are denoted by their simple names, and then the permission type.
Permissions can be access as follows:
- roles.part.view
- roles.build.delete
Each value will return a boolean True / False
"""
user = request.user
roles = {
}
if user.is_superuser:
for ruleset in RuleSet.RULESET_MODELS.keys():
roles[ruleset] = {
'view': True,
'add': True,
'change': True,
'delete': True,
}
else:
for group in user.groups.all():
for rule in group.rule_sets.all():
# Ensure the role name is in the dict
if rule.name not in roles:
roles[rule.name] = {
'view': user.is_superuser,
'add': user.is_superuser,
'change': user.is_superuser,
'delete': user.is_superuser
}
# Roles are additive across groups
roles[rule.name]['view'] |= rule.can_view
roles[rule.name]['add'] |= rule.can_add
roles[rule.name]['change'] |= rule.can_change
roles[rule.name]['delete'] |= rule.can_delete
return {'roles': roles}

View File

@@ -0,0 +1,21 @@
from djmoney.contrib.exchange.backends.base import BaseExchangeBackend
class InvenTreeManualExchangeBackend(BaseExchangeBackend):
"""
Backend for manually updating currency exchange rates
See the documentation for django-money: https://github.com/django-money/django-money
Specifically: https://github.com/django-money/django-money/tree/master/djmoney/contrib/exchange/backends
"""
name = "inventree"
url = None
def get_rates(self, **kwargs):
"""
Do not get any rates...
"""
return {}

View File

@@ -5,13 +5,16 @@ from __future__ import unicode_literals
from .validators import allowable_url_schemes
from django.utils.translation import ugettext_lazy as _
from django.forms.fields import URLField as FormURLField
from django.db import models as models
from django.core import validators
from django import forms
from decimal import Decimal
from InvenTree.helpers import normalize
import InvenTree.helpers
class InvenTreeURLFormField(FormURLField):
@@ -31,6 +34,34 @@ class InvenTreeURLField(models.URLField):
})
class DatePickerFormField(forms.DateField):
"""
Custom date-picker field
"""
def __init__(self, **kwargs):
help_text = kwargs.get('help_text', _('Enter date'))
label = kwargs.get('label', None)
required = kwargs.get('required', False)
initial = kwargs.get('initial', None)
widget = forms.DateInput(
attrs={
'type': 'date',
}
)
forms.DateField.__init__(
self,
required=required,
initial=initial,
help_text=help_text,
widget=widget,
label=label
)
def round_decimal(value, places):
"""
Round value to the specified number of places.
@@ -55,7 +86,7 @@ class RoundingDecimalFormField(forms.DecimalField):
"""
if type(value) == Decimal:
return normalize(value)
return InvenTree.helpers.normalize(value)
else:
return value

View File

@@ -5,12 +5,14 @@ Helper forms which subclass Django forms to provide additional functionality
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy as _
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field
from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText
from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText, StrictButton, Div
from django.contrib.auth.models import User
from common.models import ColorTheme
from part.models import PartCategory
class HelperForm(forms.ModelForm):
@@ -26,6 +28,7 @@ class HelperForm(forms.ModelForm):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_show_errors = True
"""
Create a default 'layout' for this form.
@@ -37,6 +40,12 @@ class HelperForm(forms.ModelForm):
self.rebuild_layout()
def is_valid(self):
valid = super(HelperForm, self).is_valid()
return valid
def rebuild_layout(self):
layouts = []
@@ -114,6 +123,7 @@ class DeleteForm(forms.Form):
confirm_delete = forms.BooleanField(
required=False,
initial=False,
label=_('Confirm delete'),
help_text=_('Confirm item deletion')
)
@@ -146,6 +156,7 @@ class SetPasswordForm(HelperForm):
required=True,
initial='',
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
label=_('Enter password'),
help_text=_('Enter new password'))
confirm_password = forms.CharField(max_length=100,
@@ -153,6 +164,7 @@ class SetPasswordForm(HelperForm):
required=True,
initial='',
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
label=_('Confirm password'),
help_text=_('Confirm new password'))
class Meta:
@@ -161,3 +173,66 @@ class SetPasswordForm(HelperForm):
'enter_password',
'confirm_password'
]
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 """
category = forms.ModelChoiceField(queryset=PartCategory.objects.all())
class Meta:
model = PartCategory
fields = [
'category'
]
def __init__(self, *args, **kwargs):
super(SettingCategorySelectForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
# Form rendering
self.helper.form_show_labels = False
self.helper.layout = Layout(
Div(
Div(Field('category'),
css_class='col-sm-6',
style='width: 70%;'),
Div(StrictButton(_('Select Category'), css_class='btn btn-primary', type='submit'),
css_class='col-sm-6',
style='width: 30%; padding-left: 0;'),
css_class='row',
),
)

View File

@@ -12,13 +12,25 @@ from decimal import Decimal
from wsgiref.util import FileWrapper
from django.http import StreamingHttpResponse
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.core.exceptions import ValidationError, FieldError
from django.utils.translation import ugettext_lazy as _
from .version import inventreeVersion, inventreeInstanceName
from django.contrib.auth.models import Permission
import InvenTree.version
from common.models import InvenTreeSetting
from .settings import MEDIA_URL, STATIC_URL
def getSetting(key, backup_value=None):
"""
Shortcut for reading a setting value from the database
"""
return InvenTreeSetting.get_setting(key, backup_value=backup_value)
def generateTestKey(test_name):
"""
Generate a test 'key' for a given test name.
@@ -108,6 +120,19 @@ def str2bool(text, test=True):
return str(text).lower() in ['0', 'n', 'no', 'none', 'f', 'false', 'off', ]
def is_bool(text):
"""
Determine if a string value 'looks' like a boolean.
"""
if str2bool(text, True):
return True
elif str2bool(text, False):
return True
else:
return False
def isNull(text):
"""
Test if a string 'looks' like a null value.
@@ -242,7 +267,7 @@ def WrapWithQuotes(text, quote='"'):
return text
def MakeBarcode(object_name, object_data):
def MakeBarcode(object_name, object_pk, object_data={}, **kwargs):
""" Generate a string for a barcode. Adds some global InvenTree parameters.
Args:
@@ -255,12 +280,20 @@ def MakeBarcode(object_name, object_data):
json string of the supplied data plus some other data
"""
data = {
'tool': 'InvenTree',
'version': inventreeVersion(),
'instance': inventreeInstanceName(),
object_name: object_data
}
brief = kwargs.get('brief', True)
data = {}
if brief:
data[object_name] = object_pk
else:
data['tool'] = 'InvenTree'
data['version'] = InvenTree.version.inventreeVersion()
data['instance'] = InvenTree.version.inventreeInstanceName()
# Ensure PK is included
object_data['id'] = object_pk
data[object_name] = object_data
return json.dumps(data, sort_keys=True)
@@ -304,7 +337,7 @@ def DownloadFile(data, filename, content_type='application/text'):
return response
def ExtractSerialNumbers(serials, expected_quantity):
def extract_serial_numbers(serials, expected_quantity):
""" Attempt to extract serial numbers from an input string.
- Serial numbers must be integer values
- Serial numbers must be positive
@@ -349,28 +382,24 @@ def ExtractSerialNumbers(serials, expected_quantity):
if a < b:
for n in range(a, b + 1):
if n in numbers:
errors.append(_('Duplicate serial: {n}'.format(n=n)))
errors.append(_('Duplicate serial: {n}').format(n=n))
else:
numbers.append(n)
else:
errors.append(_("Invalid group: {g}".format(g=group)))
errors.append(_("Invalid group: {g}").format(g=group))
except ValueError:
errors.append(_("Invalid group: {g}".format(g=group)))
errors.append(_("Invalid group: {g}").format(g=group))
continue
else:
errors.append(_("Invalid group: {g}".format(g=group)))
errors.append(_("Invalid group: {g}").format(g=group))
continue
else:
try:
n = int(group)
if n in numbers:
errors.append(_("Duplicate serial: {n}".format(n=n)))
else:
numbers.append(n)
except ValueError:
errors.append(_("Invalid group: {g}".format(g=group)))
if group in numbers:
errors.append(_("Duplicate serial: {g}".format(g=group)))
else:
numbers.append(group)
if len(errors) > 0:
raise ValidationError(errors)
@@ -380,6 +409,155 @@ def ExtractSerialNumbers(serials, expected_quantity):
# The number of extracted serial numbers must match the expected quantity
if not expected_quantity == len(numbers):
raise ValidationError([_("Number of unique serial number ({s}) must match quantity ({q})".format(s=len(numbers), q=expected_quantity))])
raise ValidationError([_("Number of unique serial number ({s}) must match quantity ({q})").format(s=len(numbers), q=expected_quantity)])
return numbers
def validateFilterString(value, model=None):
"""
Validate that a provided filter string looks like a list of comma-separated key=value pairs
These should nominally match to a valid database filter based on the model being filtered.
e.g. "category=6, IPN=12"
e.g. "part__name=widget"
The ReportTemplate class uses the filter string to work out which items a given report applies to.
For example, an acceptance test report template might only apply to stock items with a given IPN,
so the string could be set to:
filters = "IPN = ACME0001"
Returns a map of key:value pairs
"""
# Empty results map
results = {}
value = str(value).strip()
if not value or len(value) == 0:
return results
groups = value.split(',')
for group in groups:
group = group.strip()
pair = group.split('=')
if not len(pair) == 2:
raise ValidationError(
"Invalid group: {g}".format(g=group)
)
k, v = pair
k = k.strip()
v = v.strip()
if not k or not v:
raise ValidationError(
"Invalid group: {g}".format(g=group)
)
results[k] = v
# If a model is provided, verify that the provided filters can be used against it
if model is not None:
try:
model.objects.filter(**results)
except FieldError as e:
raise ValidationError(
str(e),
)
return results
def addUserPermission(user, permission):
"""
Shortcut function for adding a certain permission to a user.
"""
perm = Permission.objects.get(codename=permission)
user.user_permissions.add(perm)
def addUserPermissions(user, permissions):
"""
Shortcut function for adding multiple permissions to a user.
"""
for permission in permissions:
addUserPermission(user, permission)
def getMigrationFileNames(app):
"""
Return a list of all migration filenames for provided app
"""
local_dir = os.path.dirname(os.path.abspath(__file__))
migration_dir = os.path.join(local_dir, '..', app, 'migrations')
files = os.listdir(migration_dir)
# Regex pattern for migration files
pattern = r"^[\d]+_.*\.py$"
migration_files = []
for f in files:
if re.match(pattern, f):
migration_files.append(f)
return migration_files
def getOldestMigrationFile(app, exclude_extension=True, ignore_initial=True):
"""
Return the filename associated with the oldest migration
"""
oldest_num = -1
oldest_file = None
for f in getMigrationFileNames(app):
if ignore_initial and f.startswith('0001_initial'):
continue
num = int(f.split('_')[0])
if oldest_file is None or num < oldest_num:
oldest_num = num
oldest_file = f
if exclude_extension:
oldest_file = oldest_file.replace('.py', '')
return oldest_file
def getNewestMigrationFile(app, exclude_extension=True):
"""
Return the filename associated with the newest migration
"""
newest_file = None
newest_num = -1
for f in getMigrationFileNames(app):
num = int(f.split('_')[0])
if newest_file is None or num > newest_num:
newest_num = num
newest_file = f
if exclude_extension:
newest_file = newest_file.replace('.py', '')
return newest_file

View File

@@ -0,0 +1,42 @@
"""
Custom management command, wait for the database to be ready!
"""
from django.core.management.base import BaseCommand
from django.db import connection
from django.db.utils import OperationalError, ImproperlyConfigured
import time
class Command(BaseCommand):
"""
django command to pause execution until the database is ready
"""
def handle(self, *args, **kwargs):
self.stdout.write("Waiting for database...")
connected = False
while not connected:
time.sleep(5)
try:
connection.ensure_connection()
connected = True
except OperationalError as e:
self.stdout.write(f"Could not connect to database: {e}")
except ImproperlyConfigured as e:
self.stdout.write(f"Improperly configured: {e}")
else:
if not connection.is_usable():
self.stdout.write("Database configuration is not usable")
if connected:
self.stdout.write("Database connection sucessful!")

View File

@@ -8,7 +8,7 @@ import operator
from rest_framework.authtoken.models import Token
logger = logging.getLogger(__name__)
logger = logging.getLogger("inventree")
class AuthRequiredMiddleware(object):
@@ -47,7 +47,12 @@ class AuthRequiredMiddleware(object):
authorized = False
if 'Authorization' in request.headers.keys():
# Allow static files to be accessed without auth
# Important for e.g. login page
if request.path_info.startswith('/static/'):
authorized = True
elif 'Authorization' in request.headers.keys():
auth = request.headers['Authorization'].strip()
if auth.startswith('Token') and len(auth.split()) == 2:
@@ -56,7 +61,7 @@ class AuthRequiredMiddleware(object):
# Does the provided token match a valid user?
if Token.objects.filter(key=token).exists():
allowed = ['/api/', '/media/', '/static/']
allowed = ['/api/', '/media/']
# Only allow token-auth for /media/ or /static/ dirs!
if any([request.path_info.startswith(a) for a in allowed]):
@@ -91,6 +96,8 @@ class QueryCountMiddleware(object):
To enable this middleware, set 'log_queries: True' in the local InvenTree config file.
Reference: https://www.dabapps.com/blog/logging-sql-queries-django-13/
Note: 2020-08-15 - This is no longer used, instead we now rely on the django-debug-toolbar addon
"""
def __init__(self, get_response):

View File

@@ -56,19 +56,20 @@ class InvenTreeAttachment(models.Model):
def __str__(self):
return os.path.basename(self.attachment.name)
attachment = models.FileField(upload_to=rename_attachment,
attachment = models.FileField(upload_to=rename_attachment, verbose_name=_('Attachment'),
help_text=_('Select file to attach'))
comment = models.CharField(blank=True, max_length=100, help_text=_('File comment'))
comment = models.CharField(blank=True, max_length=100, verbose_name=_('Comment'), help_text=_('File comment'))
user = models.ForeignKey(
User,
on_delete=models.SET_NULL,
blank=True, null=True,
verbose_name=_('User'),
help_text=_('User'),
)
upload_date = models.DateField(auto_now_add=True, null=True, blank=True)
upload_date = models.DateField(auto_now_add=True, null=True, blank=True, verbose_name=_('upload date'))
@property
def basename(self):
@@ -102,12 +103,16 @@ class InvenTreeTree(MPTTModel):
name = models.CharField(
blank=False,
max_length=100,
validators=[validate_tree_name]
validators=[validate_tree_name],
verbose_name=_("Name"),
help_text=_("Name"),
)
description = models.CharField(
blank=False,
max_length=250
blank=True,
max_length=250,
verbose_name=_("Description"),
help_text=_("Description (optional)")
)
# When a category is deleted, graft the children onto its parent
@@ -115,6 +120,7 @@ class InvenTreeTree(MPTTModel):
on_delete=models.DO_NOTHING,
blank=True,
null=True,
verbose_name=_("parent"),
related_name='children')
@property

View File

@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from rest_framework import permissions
import users.models
class RolePermission(permissions.BasePermission):
"""
Role mixin for API endpoints, allowing us to specify the user "role"
which is required for certain operations.
Each endpoint can have one or more of the following actions:
- GET
- POST
- PUT
- PATCH
- DELETE
Specify the required "role" using the role_required attribute.
e.g.
role_required = "part"
The RoleMixin class will then determine if the user has the required permission
to perform the specified action.
For example, a DELETE action will be rejected unless the user has the "part.remove" permission
"""
def has_permission(self, request, view):
"""
Determine if the current user has the specified permissions
"""
user = request.user
# Superuser can do it all
if user.is_superuser:
return True
# Map the request method to a permission type
rolemap = {
'GET': 'view',
'OPTIONS': 'view',
'POST': 'add',
'PUT': 'change',
'PATCH': 'change',
'DELETE': 'delete',
}
permission = rolemap[request.method]
try:
# Extract the model name associated with this request
model = view.serializer_class.Meta.model
app_label = model._meta.app_label
model_name = model._meta.model_name
table = f"{app_label}_{model_name}"
except AttributeError:
# We will assume that if the serializer class does *not* have a Meta,
# then we don't need a permission
return True
result = users.models.RuleSet.check_table_permission(user, table, permission)
return result

View File

@@ -0,0 +1,43 @@
# -*- 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

@@ -8,6 +8,9 @@ from __future__ import unicode_literals
from rest_framework import serializers
import os
from django.conf import settings
from django.contrib.auth.models import User
@@ -50,3 +53,32 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
instance.clean()
return data
class InvenTreeAttachmentSerializerField(serializers.FileField):
"""
Override the DRF native FileField serializer,
to remove the leading server path.
For example, the FileField might supply something like:
http://127.0.0.1:8000/media/foo/bar.jpg
Whereas we wish to return:
/media/foo/bar.jpg
Why? You can't handle the why!
Actually, if the server process is serving the data at 127.0.0.1,
but a proxy service (e.g. nginx) is then providing DNS lookup to the outside world,
then an attachment which prefixes the "address" of the internal server
will not be accessible from the outside world.
"""
def to_representation(self, value):
if not value:
return None
return os.path.join(str(settings.MEDIA_URL), str(value))

View File

@@ -11,42 +11,152 @@ database setup in this file.
"""
import sys
import os
import logging
import os
import random
import string
import shutil
import sys
import tempfile
import yaml
from datetime import datetime
import yaml
from django.utils.translation import gettext_lazy as _
def eprint(*args, **kwargs):
""" Print a warning message to stderr """
print(*args, file=sys.stderr, **kwargs)
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
# Determine if we are running in "test" mode e.g. "manage.py test"
TESTING = 'test' in sys.argv
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
cfg_filename = os.path.join(BASE_DIR, 'config.yaml')
# 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):
CONFIG = {}
eprint("Warning: config.yaml not found - using default settings")
else:
with open(cfg_filename, 'r') as cfg:
CONFIG = yaml.safe_load(cfg)
print("InvenTree configuration file 'config.yaml' not found - creating default file")
# Read the autogenerated key-file
key_file = open(os.path.join(BASE_DIR, 'secret_key.txt'), 'r')
cfg_template = os.path.join(BASE_DIR, "config_template.yaml")
shutil.copyfile(cfg_template, cfg_filename)
print(f"Created config file {cfg_filename}")
SECRET_KEY = key_file.read().strip()
with open(cfg_filename, 'r') as cfg:
CONFIG = yaml.safe_load(cfg)
# Default action is to run the system in Debug mode
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = CONFIG.get('debug', True)
DEBUG = _is_true(get_setting(
'INVENTREE_DEBUG',
CONFIG.get('debug', True)
))
# Configure logging settings
log_level = get_setting(
'INVENTREE_LOG_LEVEL',
CONFIG.get('log_level', 'DEBUG')
)
logging.basicConfig(
level=log_level,
format="%(asctime)s %(levelname)s %(message)s",
)
if log_level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']:
log_level = 'WARNING'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'root': {
'handlers': ['console'],
'level': log_level,
},
}
# Get a logger instance for this setup file
logger = logging.getLogger("inventree")
"""
Specify a secret key to be used by django.
Following options are tested, in descending order of preference:
A) Check for environment variable INVENTREE_SECRET_KEY => Use raw key data
B) Check for environment variable INVENTREE_SECRET_KEY_FILE => Load key data from file
C) Look for default key file "secret_key.txt"
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")
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)
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):
logger.info(f"Generating random key file at '{key_file}'")
# Create a random key file
with open(key_file, 'w') as f:
options = string.digits + string.ascii_letters + string.punctuation
key = ''.join([random.choice(options) for i in range(100)])
f.write(key)
logger.info(f"Loading SECRET_KEY from '{key_file}'")
try:
SECRET_KEY = open(key_file, "r").read().strip()
except Exception:
logger.exception(f"Couldn't load keyfile {key_file}")
sys.exit(-1)
# List of allowed hosts (default = allow all)
ALLOWED_HOSTS = CONFIG.get('allowed_hosts', ['*'])
@@ -65,33 +175,40 @@ if cors_opt:
if not CORS_ORIGIN_ALLOW_ALL:
CORS_ORIGIN_WHITELIST = cors_opt.get('whitelist', [])
if DEBUG:
# will output to your console
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)s %(message)s',
# 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/static')
)
)
# Does the user wish to use the sentry.io integration?
sentry_opts = CONFIG.get('sentry', {})
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'InvenTree', 'static'),
]
if sentry_opts.get('enabled', False):
dsn = sentry_opts.get('dsn', None)
# Color Themes Directory
STATIC_COLOR_THEMES_DIR = os.path.join(STATIC_ROOT, 'css', 'color-themes')
if dsn is not None:
# Try to import required modules (exit if not installed)
try:
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
# Web URL endpoint for served media files
MEDIA_URL = '/media/'
sentry_sdk.init(dsn=dsn, integrations=[DjangoIntegration()], send_default_pii=True)
# 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')
)
)
except ModuleNotFoundError:
print("sentry_sdk module not found. Install using 'pip install sentry-sdk'")
sys.exit(-1)
if DEBUG:
logger.info("InvenTree running in DEBUG mode")
else:
print("Warning: Sentry.io DSN not specified")
logger.info(f"MEDIA_ROOT: '{MEDIA_ROOT}'")
logger.info(f"STATIC_ROOT: '{STATIC_ROOT}'")
# Application definition
@@ -106,40 +223,37 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
# InvenTree apps
'common.apps.CommonConfig',
'part.apps.PartConfig',
'stock.apps.StockConfig',
'company.apps.CompanyConfig',
'build.apps.BuildConfig',
'common.apps.CommonConfig',
'company.apps.CompanyConfig',
'label.apps.LabelConfig',
'order.apps.OrderConfig',
'part.apps.PartConfig',
'report.apps.ReportConfig',
'stock.apps.StockConfig',
'users.apps.UsersConfig',
'InvenTree.apps.InvenTreeConfig', # InvenTree app runs last
# Third part add-ons
'django_filters', # Extended filter functionality
'dbbackup', # Database backup / restore
'rest_framework', # DRF (Django Rest Framework)
'rest_framework.authtoken', # Token authentication for API
'corsheaders', # Cross-origin Resource Sharing for DRF
'crispy_forms', # Improved form rendering
'import_export', # Import / export tables to file
'django_cleanup', # Automatically delete orphaned MEDIA files
'qr_code', # Generate QR codes
'mptt', # Modified Preorder Tree Traversal
'markdownx', # Markdown editing
'markdownify', # Markdown template rendering
'django_filters', # Extended filter functionality
'dbbackup', # Database backup / restore
'rest_framework', # DRF (Django Rest Framework)
'rest_framework.authtoken', # Token authentication for API
'corsheaders', # Cross-origin Resource Sharing for DRF
'crispy_forms', # Improved form rendering
'import_export', # Import / export tables to file
'django_cleanup.apps.CleanupConfig', # Automatically delete orphaned MEDIA files
'mptt', # Modified Preorder Tree Traversal
'markdownx', # Markdown editing
'markdownify', # Markdown template rendering
'django_admin_shell', # Python shell for the admin interface
'djmoney', # django-money integration
'djmoney.contrib.exchange', # django-money exchange rates
'error_report', # Error reporting in the admin interface
'django_q',
]
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
}
MIDDLEWARE = [
MIDDLEWARE = CONFIG.get('middleware', [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
@@ -149,18 +263,33 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'InvenTree.middleware.AuthRequiredMiddleware',
]
'InvenTree.middleware.AuthRequiredMiddleware'
])
if CONFIG.get('log_queries', False):
MIDDLEWARE.append('InvenTree.middleware.QueryCountMiddleware')
# Error reporting middleware
MIDDLEWARE.append('error_report.middleware.ExceptionProcessor')
AUTHENTICATION_BACKENDS = CONFIG.get('authentication_backends', [
'django.contrib.auth.backends.ModelBackend'
])
# If the debug toolbar is enabled, add the modules
if DEBUG and CONFIG.get('debug_toolbar', False):
logger.info("Running with DEBUG_TOOLBAR enabled")
INSTALLED_APPS.append('debug_toolbar')
MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')
ROOT_URLCONF = 'InvenTree.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
# Allow templates in the reporting directory to be accessed
os.path.join(MEDIA_ROOT, 'report'),
os.path.join(MEDIA_ROOT, 'label'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
@@ -169,7 +298,9 @@ TEMPLATES = [
'django.template.context_processors.i18n',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'InvenTree.context.health_status',
'InvenTree.context.status_codes',
'InvenTree.context.user_roles',
],
},
},
@@ -183,11 +314,29 @@ REST_FRAMEWORK = {
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema'
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
'rest_framework.permissions.DjangoModelPermissions',
'InvenTree.permissions.RolePermission',
),
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}
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')
@@ -222,42 +371,78 @@ MARKDOWNIFY_BLEACH = False
DATABASES = {}
"""
When running unit tests, enforce usage of sqlite3 database,
so that the tests can be run in RAM without any setup requirements
"""
if 'test' in sys.argv:
eprint('InvenTree: Running tests - Using sqlite3 memory database')
DATABASES['default'] = {
# Ensure sqlite3 backend is being used
'ENGINE': 'django.db.backends.sqlite3',
# Doesn't matter what the database is called, it is executed in RAM
'NAME': 'ram_test_db.sqlite3',
}
Configure the database backend based on the user-specified values.
# Database backend selection
else:
if 'database' in CONFIG:
DATABASES['default'] = CONFIG['database']
else:
eprint("Warning: Database backend not specified - using default (sqlite)")
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'inventree_db.sqlite3'),
}
- Primarily this configuration happens in the config.yaml file
- However there may be reason to configure the DB via environmental variables
- The following code lets the user "mix and match" database configuration
"""
logger.info("Configuring database backend:")
# Extract database configuration from the config.yaml file
db_config = CONFIG.get('database', {})
if not db_config:
db_config = {}
# Environment variables take preference over config file!
db_keys = ['ENGINE', 'NAME', 'USER', 'PASSWORD', 'HOST', 'PORT']
for key in db_keys:
# First, check the environment variables
env_key = f"INVENTREE_DB_{key}"
env_var = os.environ.get(env_key, None)
if env_var:
logger.info(f"{env_key}={env_var}")
# Override configuration value
db_config[key] = env_var
# Check that required database configuration options are specified
reqiured_keys = ['ENGINE', 'NAME']
for key in reqiured_keys:
if key not in db_config:
error_msg = f'Missing required database configuration value {key}'
logger.error(error_msg)
print('Error: ' + error_msg)
sys.exit(-1)
"""
Special considerations for the database 'ENGINE' setting.
It can be specified in config.yaml (or envvar) as either (for example):
- sqlite3
- django.db.backends.sqlite3
- django.db.backends.postgresql
"""
db_engine = db_config['ENGINE']
if db_engine.lower() in ['sqlite3', 'postgresql', 'mysql']:
# Prepend the required python module string
db_engine = f'django.db.backends.{db_engine.lower()}'
db_config['ENGINE'] = db_engine
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}")
DATABASES['default'] = db_config
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
'qr-code': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'qr-code-cache',
'TIMEOUT': 3600
}
}
QR_CODE_CACHE_ALIAS = 'qr-code'
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
@@ -282,72 +467,74 @@ AUTH_PASSWORD_VALIDATORS = [
EXTRA_URL_SCHEMES = CONFIG.get('extra_url_schemes', [])
if not type(EXTRA_URL_SCHEMES) in [list]:
eprint("Warning: extra_url_schemes not correctly formatted")
logger.warning("extra_url_schemes not correctly formatted")
EXTRA_URL_SCHEMES = []
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
# https://docs.djangoproject.com/en/dev/topics/i18n/
LANGUAGE_CODE = CONFIG.get('language', 'en-us')
# If a new language translation is supported, it must be added here
LANGUAGES = [
('en', _('English')),
('de', _('German')),
('fr', _('French')),
('de', _('German')),
('pk', _('Polish')),
('tr', _('Turkish')),
]
# Currencies available for use
CURRENCIES = CONFIG.get(
'currencies',
[
'AUD', 'CAD', 'EUR', 'GBP', 'JPY', 'NZD', 'USD',
],
)
# TODO - Allow live web-based backends in the future
EXCHANGE_BACKEND = 'InvenTree.exchange.InvenTreeManualExchangeBackend'
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale/'),
)
TIME_ZONE = 'UTC'
TIME_ZONE = get_setting(
'INVENTREE_TIMEZONE',
CONFIG.get('timezone', 'UTC')
)
USE_I18N = True
USE_L10N = True
USE_TZ = 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
DATE_INPUT_FORMATS = [
"%Y-%m-%d",
]
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
# Web URL endpoint for served static files
STATIC_URL = '/static/'
# The filesystem location for served static files
STATIC_ROOT = os.path.abspath(CONFIG.get('static_root', os.path.join(BASE_DIR, 'static')))
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'InvenTree', 'static'),
]
# Web URL endpoint for served media files
MEDIA_URL = '/media/'
# The filesystem location for served static files
MEDIA_ROOT = os.path.abspath(CONFIG.get('media_root', os.path.join(BASE_DIR, 'media')))
if DEBUG:
print("InvenTree running in DEBUG mode")
print("MEDIA_ROOT:", MEDIA_ROOT)
print("STATIC_ROOT:", STATIC_ROOT)
# crispy forms use the bootstrap templates
CRISPY_TEMPLATE_PACK = 'bootstrap3'
# Use database transactions when importing / exporting data
IMPORT_EXPORT_USE_TRANSACTIONS = True
BACKUP_DIR = get_setting(
'INVENTREE_BACKUP_DIR',
CONFIG.get('backup_dir', tempfile.gettempdir()),
)
# Settings for dbbsettings app
DBBACKUP_STORAGE = 'django.core.files.storage.FileSystemStorage'
DBBACKUP_STORAGE_OPTIONS = {
'location': CONFIG.get('backup_dir', tempfile.gettempdir()),
'location': BACKUP_DIR,
}
# Internal IP addresses allowed to see the debug toolbar
INTERNAL_IPS = [
'127.0.0.1',
]

View File

@@ -0,0 +1,170 @@
/**
* @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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,116 @@
/**
* @author: general
* @website: note.generals.space
* @email: generals.space@gmail.com
* @github: https://github.com/generals-space/bootstrap-table-addrbar
* @update: zhixin wen <wenzhixin2010@gmail.com>
*/
($ => {
/*
* function: 获取浏览器地址栏中的指定参数.
* key: 参数名
* url: 默认为当前地址栏
*/
function _GET (key, url = window.location.search) {
/*
* 注意这里正则表达式的书写方法
* (^|&)key匹配: 直接以key开始或以&key开始的字符串
* 同理(&|$)表示以&结束或是直接结束的字符串
* ...当然, 我并不知道这种用法.
*/
const reg = new RegExp(`(^|&)${key}=([^&]*)(&|$)`)
const result = url.substr(1).match(reg)
if (result) {
return decodeURIComponent(result[2])
}
return null
}
/*
* function: 根据给定参数生成url地址
* var dic = {name: 'genreal', age: 24}
* var url = 'https://www.baidu.com?age=22';
* _buildUrl(dic, url);
* 将得到"https://www.baidu.com?age=24&name=genreal"
* 哦, 忽略先后顺序吧...
*
* 补充: 可以参考浏览器URLSearchParams对象, 更加方便和强大.
* 考虑到兼容性, 暂时不使用这个工具.
*/
function _buildUrl (dict, url = window.location.search) {
for (const [key, val] of Object.entries(dict)) {
// 搜索name=general这种形式的字符串(&是分隔符)
const pattern = `${key}=([^&]*)`
const targetStr = `${key}=${val}`
/*
* 如果目标url中包含了key键, 我们需要将它替换成我们自己的val
* 不然就直接添加好了.
*/
if (url.match(pattern)) {
const tmp = new RegExp(`(${key}=)([^&]*)`, 'gi')
url = url.replace(tmp, targetStr)
} else {
const seperator = url.match('[?]') ? '&' : '?'
url = url + seperator + targetStr
}
}
if (location.hash) {
url += location.hash
}
return url
}
$.BootstrapTable = class extends $.BootstrapTable {
init () {
// 拥有addrbar选项并且其值为true的才会继续执行
if (this.options.addrbar) {
// 标志位, 初始加载后关闭
this.addrbarInit = true
const _prefix = this.options.addrPrefix || ''
// 优先级排序: 用户指定值最优先, 未指定时从地址栏获取, 未获取到时采用默认值
this.options.pageSize = this.options.pageSize || (
_GET(`${_prefix}limit`) ? parseInt(_GET(`${_prefix}limit`)) : $.BootstrapTable.DEFAULTS.pageSize
)
this.options.pageNumber = this.options.pageNumber || (
_GET(`${_prefix}page`) ? parseInt(_GET(`${_prefix}page`)) : $.BootstrapTable.DEFAULTS.pageNumber
)
this.options.sortOrder = this.options.sortOrder || (
_GET(`${_prefix}order`) ? _GET(`${_prefix}order`) : $.BootstrapTable.DEFAULTS.sortOrder
)
this.options.sortName = this.options.sortName || (
_GET(`${_prefix}sort`) ? _GET(`${_prefix}sort`) : 'id'
)
this.options.searchText = this.options.searchText || (
_GET(`${_prefix}search`) ? _GET(`${_prefix}search`) : $.BootstrapTable.DEFAULTS.searchText
)
const _onLoadSuccess = this.options.onLoadSuccess
this.options.onLoadSuccess = data => {
if (this.addrbarInit) {
this.addrbarInit = false
} else {
const params = {}
params[`${_prefix}page`] = this.options.pageNumber,
params[`${_prefix}limit`] = this.options.pageSize,
params[`${_prefix}order`] = this.options.sortOrder,
params[`${_prefix}sort`] = this.options.sortName,
params[`${_prefix}search`] = this.options.searchText
// h5提供的修改浏览器地址栏的方法
window.history.pushState({}, '', _buildUrl(params))
}
if (_onLoadSuccess) {
_onLoadSuccess.call(this, data)
}
}
}
super.init()
}
}
})(jQuery)

View File

@@ -0,0 +1,78 @@
/**
* @author: Alec Fenichel
* @webSite: https://fenichelar.com
* @update: zhixin wen <wenzhixin2010@gmail.com>
*/
($ => {
const Utils = $.fn.bootstrapTable.utils
$.extend($.fn.bootstrapTable.defaults, {
autoRefresh: false,
autoRefreshInterval: 60,
autoRefreshSilent: true,
autoRefreshStatus: true,
autoRefreshFunction: null
})
$.extend($.fn.bootstrapTable.defaults.icons, {
autoRefresh: Utils.bootstrapVersion === 4 ? 'fa-clock' : 'glyphicon-time icon-time'
})
$.extend($.fn.bootstrapTable.locales, {
formatAutoRefresh () {
return 'Auto Refresh'
}
})
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
$.BootstrapTable = class extends $.BootstrapTable {
init (...args) {
super.init(...args)
if (this.options.autoRefresh && this.options.autoRefreshStatus) {
this.options.autoRefreshFunction = setInterval(() => {
this.refresh({silent: this.options.autoRefreshSilent})
}, this.options.autoRefreshInterval * 1000)
}
}
initToolbar (...args) {
super.initToolbar(...args)
if (this.options.autoRefresh) {
const $btnGroup = this.$toolbar.find('>.btn-group')
let $btnAutoRefresh = $btnGroup.find('.auto-refresh')
if (!$btnAutoRefresh.length) {
$btnAutoRefresh = $(`
<button class="auto-refresh btn${Utils.sprintf(' btn-%s', this.options.buttonsClass)}
${Utils.sprintf(' btn-%s', this.options.iconSize)}
${this.options.autoRefreshStatus ? 'active' : ''}"
type="button" title="${this.options.formatAutoRefresh()}">
<i class="${this.options.iconsPrefix} ${this.options.icons.autoRefresh}"></i>
</button>
`).appendTo($btnGroup)
$btnAutoRefresh.on('click', $.proxy(this.toggleAutoRefresh, this))
}
}
}
toggleAutoRefresh () {
if (this.options.autoRefresh) {
if (this.options.autoRefreshStatus) {
clearInterval(this.options.autoRefreshFunction)
this.$toolbar.find('>.btn-group').find('.auto-refresh').removeClass('active')
} else {
this.options.autoRefreshFunction = setInterval(() => {
this.refresh({silent: this.options.autoRefreshSilent})
}, this.options.autoRefreshInterval * 1000)
this.$toolbar.find('>.btn-group').find('.auto-refresh').addClass('active')
}
this.options.autoRefreshStatus = !this.options.autoRefreshStatus
}
}
}
})(jQuery)

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,401 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @update zhixin wen <wenzhixin2010@gmail.com>
*/
($ => {
const UtilsCookie = {
cookieIds: {
sortOrder: 'bs.table.sortOrder',
sortName: 'bs.table.sortName',
pageNumber: 'bs.table.pageNumber',
pageList: 'bs.table.pageList',
columns: 'bs.table.columns',
searchText: 'bs.table.searchText',
filterControl: 'bs.table.filterControl',
filterBy: 'bs.table.filterBy'
},
getCurrentHeader (that) {
let header = that.$header
if (that.options.height) {
header = that.$tableHeader
}
return header
},
getCurrentSearchControls (that) {
let searchControls = 'select, input'
if (that.options.height) {
searchControls = 'table select, table input'
}
return searchControls
},
cookieEnabled () {
return !!(navigator.cookieEnabled)
},
inArrayCookiesEnabled (cookieName, cookiesEnabled) {
let index = -1
for (let i = 0; i < cookiesEnabled.length; i++) {
if (cookieName.toLowerCase() === cookiesEnabled[i].toLowerCase()) {
index = i
break
}
}
return index
},
setCookie (that, cookieName, cookieValue) {
if ((!that.options.cookie) || (!UtilsCookie.cookieEnabled()) || (that.options.cookieIdTable === '')) {
return
}
if (UtilsCookie.inArrayCookiesEnabled(cookieName, that.options.cookiesEnabled) === -1) {
return
}
cookieName = `${that.options.cookieIdTable}.${cookieName}`
switch (that.options.cookieStorage) {
case 'cookieStorage':
document.cookie = [
cookieName, '=', encodeURIComponent(cookieValue),
`; expires=${UtilsCookie.calculateExpiration(that.options.cookieExpire)}`,
that.options.cookiePath ? `; path=${that.options.cookiePath}` : '',
that.options.cookieDomain ? `; domain=${that.options.cookieDomain}` : '',
that.options.cookieSecure ? '; secure' : ''
].join('')
break
case 'localStorage':
localStorage.setItem(cookieName, cookieValue)
break
case 'sessionStorage':
sessionStorage.setItem(cookieName, cookieValue)
break
default:
return false
}
return true
},
getCookie (that, tableName, cookieName) {
if (!cookieName) {
return null
}
if (UtilsCookie.inArrayCookiesEnabled(cookieName, that.options.cookiesEnabled) === -1) {
return null
}
cookieName = `${tableName}.${cookieName}`
switch (that.options.cookieStorage) {
case 'cookieStorage':
const value = `; ${document.cookie}`
const parts = value.split(`; ${cookieName}=`)
return parts.length === 2 ? decodeURIComponent(parts.pop().split(';').shift()) : null
case 'localStorage':
return localStorage.getItem(cookieName)
case 'sessionStorage':
return sessionStorage.getItem(cookieName)
default:
return null
}
},
deleteCookie (that, tableName, cookieName) {
cookieName = `${tableName}.${cookieName}`
switch (that.options.cookieStorage) {
case 'cookieStorage':
document.cookie = [
encodeURIComponent(cookieName), '=',
'; expires=Thu, 01 Jan 1970 00:00:00 GMT',
that.options.cookiePath ? `; path=${that.options.cookiePath}` : '',
that.options.cookieDomain ? `; domain=${that.options.cookieDomain}` : ''
].join('')
break
case 'localStorage':
localStorage.removeItem(cookieName)
break
case 'sessionStorage':
sessionStorage.removeItem(cookieName)
break
default:
return false
}
return true
},
calculateExpiration (cookieExpire) {
const time = cookieExpire.replace(/[0-9]*/, '') // s,mi,h,d,m,y
cookieExpire = cookieExpire.replace(/[A-Za-z]{1,2}/, '') // number
switch (time.toLowerCase()) {
case 's':
cookieExpire = +cookieExpire
break
case 'mi':
cookieExpire *= 60
break
case 'h':
cookieExpire = cookieExpire * 60 * 60
break
case 'd':
cookieExpire = cookieExpire * 24 * 60 * 60
break
case 'm':
cookieExpire = cookieExpire * 30 * 24 * 60 * 60
break
case 'y':
cookieExpire = cookieExpire * 365 * 24 * 60 * 60
break
default:
cookieExpire = undefined
break
}
if (!cookieExpire) {
return ''
}
const d = new Date()
d.setTime(d.getTime() + cookieExpire * 1000)
return d.toGMTString()
},
initCookieFilters (bootstrapTable) {
setTimeout(() => {
const parsedCookieFilters = JSON.parse(UtilsCookie.getCookie(bootstrapTable, bootstrapTable.options.cookieIdTable, UtilsCookie.cookieIds.filterControl))
if (!bootstrapTable.options.filterControlValuesLoaded && parsedCookieFilters) {
const cachedFilters = {}
const header = UtilsCookie.getCurrentHeader(bootstrapTable)
const searchControls = UtilsCookie.getCurrentSearchControls(bootstrapTable)
const applyCookieFilters = (element, filteredCookies) => {
$(filteredCookies).each((i, cookie) => {
if (cookie.text !== '') {
$(element).val(cookie.text)
cachedFilters[cookie.field] = cookie.text
}
})
}
header.find(searchControls).each(function () {
const field = $(this).closest('[data-field]').data('field')
const filteredCookies = parsedCookieFilters.filter(cookie => cookie.field === field)
applyCookieFilters(this, filteredCookies)
})
bootstrapTable.initColumnSearch(cachedFilters)
bootstrapTable.options.filterControlValuesLoaded = true
bootstrapTable.initServer()
}
}, 250)
}
}
$.extend($.fn.bootstrapTable.defaults, {
cookie: false,
cookieExpire: '2h',
cookiePath: null,
cookieDomain: null,
cookieSecure: null,
cookieIdTable: '',
cookiesEnabled: [
'bs.table.sortOrder', 'bs.table.sortName',
'bs.table.pageNumber', 'bs.table.pageList',
'bs.table.columns', 'bs.table.searchText',
'bs.table.filterControl', 'bs.table.filterBy'
],
cookieStorage: 'cookieStorage', // localStorage, sessionStorage
// internal variable
filterControls: [],
filterControlValuesLoaded: false
})
$.fn.bootstrapTable.methods.push('getCookies')
$.fn.bootstrapTable.methods.push('deleteCookie')
$.extend($.fn.bootstrapTable.utils, {
setCookie: UtilsCookie.setCookie,
getCookie: UtilsCookie.getCookie
})
$.BootstrapTable = class extends $.BootstrapTable {
init () {
// FilterBy logic
const filterByCookie = JSON.parse(UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.filterBy))
this.filterColumns = filterByCookie ? filterByCookie : {}
// FilterControl logic
this.options.filterControls = []
this.options.filterControlValuesLoaded = false
this.options.cookiesEnabled = typeof this.options.cookiesEnabled === 'string' ?
this.options.cookiesEnabled.replace('[', '').replace(']', '')
.replace(/ /g, '').toLowerCase().split(',') :
this.options.cookiesEnabled
if (this.options.filterControl) {
const that = this
this.$el.on('column-search.bs.table', (e, field, text) => {
let isNewField = true
for (let i = 0; i < that.options.filterControls.length; i++) {
if (that.options.filterControls[i].field === field) {
that.options.filterControls[i].text = text
isNewField = false
break
}
}
if (isNewField) {
that.options.filterControls.push({
field,
text
})
}
UtilsCookie.setCookie(that, UtilsCookie.cookieIds.filterControl, JSON.stringify(that.options.filterControls))
}).on('created-controls.bs.table', UtilsCookie.initCookieFilters(that))
}
super.init()
}
initServer (...args) {
if (
this.options.cookie &&
this.options.filterControl &&
!this.options.filterControlValuesLoaded
) {
const cookie = JSON.parse(UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.filterControl))
if (cookie) {
return
}
}
super.initServer(...args)
}
initTable (...args) {
super.initTable(...args)
this.initCookie()
}
onSort (...args) {
super.onSort(...args)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortOrder, this.options.sortOrder)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortName, this.options.sortName)
}
onPageNumber (...args) {
super.onPageNumber(...args)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
}
onPageListChange (...args) {
super.onPageListChange(...args)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageList, this.options.pageSize)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
}
onPagePre (...args) {
super.onPagePre(...args)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
}
onPageNext (...args) {
super.onPageNext(...args)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
}
toggleColumn (...args) {
super.toggleColumn(...args)
const visibleColumns = []
$.each(this.columns, (i, column) => {
if (column.visible) {
visibleColumns.push(column.field)
}
})
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.columns, JSON.stringify(visibleColumns))
}
selectPage (page) {
super.selectPage(page)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, page)
}
onSearch (event) {
super.onSearch(event)
if ($(event.currentTarget).parent().hasClass('search')) {
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.searchText, this.searchText)
}
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber)
}
filterBy (...args) {
super.filterBy(...args)
UtilsCookie.setCookie(this, UtilsCookie.cookieIds.filterBy, JSON.stringify(this.filterColumns))
}
initCookie () {
if (!this.options.cookie) {
return
}
if ((this.options.cookieIdTable === '') || (this.options.cookieExpire === '') || (!UtilsCookie.cookieEnabled())) {
console.error('Configuration error. Please review the cookieIdTable and the cookieExpire property. If the properties are correct, then this browser does not support cookies.')
this.options.cookie = false // Make sure that the cookie extension is disabled
return
}
const sortOrderCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.sortOrder)
const sortOrderNameCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.sortName)
const pageNumberCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.pageNumber)
const pageListCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.pageList)
const columnsCookie = JSON.parse(UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.columns))
const searchTextCookie = UtilsCookie.getCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds.searchText)
// sortOrder
this.options.sortOrder = sortOrderCookie ? sortOrderCookie : this.options.sortOrder
// sortName
this.options.sortName = sortOrderNameCookie ? sortOrderNameCookie : this.options.sortName
// pageNumber
this.options.pageNumber = pageNumberCookie ? +pageNumberCookie : this.options.pageNumber
// pageSize
this.options.pageSize = pageListCookie ? pageListCookie === this.options.formatAllRows() ? pageListCookie : +pageListCookie : this.options.pageSize
// searchText
this.options.searchText = searchTextCookie ? searchTextCookie : ''
if (columnsCookie) {
$.each(this.columns, (i, column) => {
column.visible = $.inArray(column.field, columnsCookie) !== -1
})
}
}
getCookies () {
const bootstrapTable = this
const cookies = {}
$.each(UtilsCookie.cookieIds, (key, value) => {
cookies[key] = UtilsCookie.getCookie(bootstrapTable, bootstrapTable.options.cookieIdTable, value)
if (key === 'columns') {
cookies[key] = JSON.parse(cookies[key])
}
})
return cookies
}
deleteCookie (cookieName) {
if ((cookieName === '') || (!UtilsCookie.cookieEnabled())) {
return
}
UtilsCookie.deleteCookie(this, this.options.cookieIdTable, UtilsCookie.cookieIds[cookieName])
}
}
})(jQuery)

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,102 @@
/**
* @author Homer Glascock <HopGlascock@gmail.com>
* @version: v1.0.0
*/
!function ($) {
"use strict";
var calculateObjectValue = $.fn.bootstrapTable.utils.calculateObjectValue,
sprintf = $.fn.bootstrapTable.utils.sprintf;
var copytext = function (text) {
var textField = document.createElement('textarea');
$(textField).html(text);
document.body.appendChild(textField);
textField.select();
try {
document.execCommand('copy');
}
catch (e) {
console.log("Oops, unable to copy");
}
$(textField).remove();
};
$.extend($.fn.bootstrapTable.defaults, {
copyBtn: false,
copyWHiddenBtn: false,
copyDelemeter: ", "
});
$.fn.bootstrapTable.methods.push('copyColumnsToClipboard', 'copyColumnsToClipboardWithHidden');
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 (this.options.clickToSelect || this.options.singleSelect) {
if (this.options.copyBtn) {
var copybtn = "<button class='btn btn-default' id='copyBtn'><span class='glyphicon glyphicon-copy icon-pencil'></span></button>";
$btnGroup.append(copybtn);
$btnGroup.find('#copyBtn').click(function () { that.copyColumnsToClipboard(); });
}
if (this.options.copyWHiddenBtn) {
var copyhiddenbtn = "<button class='btn btn-default' id='copyWHiddenBtn'><span class='badge'><span class='glyphicon glyphicon-copy icon-pencil'></span></span></button>";
$btnGroup.append(copyhiddenbtn);
$btnGroup.find('#copyWHiddenBtn').click(function () { that.copyColumnsToClipboardWithHidden(); });
}
}
};
BootstrapTable.prototype.copyColumnsToClipboard = function () {
var that = this,
ret = "",
delimet = this.options.copyDelemeter;
$.each(that.getSelections(), function (index, row) {
$.each(that.options.columns[0], function (indy, column) {
if (column.field !== "state" && column.field !== "RowNumber" && column.visible) {
if (row[column.field] !== null) {
ret += calculateObjectValue(column, that.header.formatters[indy], [row[column.field], row, index], row[column.field]);
}
ret += delimet;
}
});
ret += "\r\n";
});
copytext(ret);
};
BootstrapTable.prototype.copyColumnsToClipboardWithHidden = function () {
var that = this,
ret = "",
delimet = this.options.copyDelemeter;
$.each(that.getSelections(), function (index, row) {
$.each(that.options.columns[0], function (indy, column) {
if (column.field != "state" && column.field !== "RowNumber") {
if (row[column.field] !== null) {
ret += calculateObjectValue(column, that.header.formatters[indy], [row[column.field], row, index], row[column.field]);
}
ret += delimet;
}
});
ret += "\r\n";
});
copytext(ret);
};
}(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,32 @@
/**
* When using server-side processing, the default mode of operation for
* bootstrap-table is to simply throw away any data that currently exists in the
* table and make a request to the server to get the first page of data to
* display. This is fine for an empty table, but if you already have the first
* page of data displayed in the plain HTML, it is a waste of resources. As
* such, you can use data-defer-url instead of data-url to allow you to instruct
* bootstrap-table to not make that initial request, rather it will use the data
* already on the page.
*
* @author: Ruben Suarez
* @webSite: http://rubensa.eu.org
* @version: v1.0.0
*/
(function($) {
'use strict';
$.extend($.fn.bootstrapTable.defaults, {
deferUrl : undefined
});
var BootstrapTable = $.fn.bootstrapTable.Constructor, _init = BootstrapTable.prototype.init;
BootstrapTable.prototype.init = function() {
_init.apply(this, Array.prototype.slice.apply(arguments));
if (this.options.deferUrl) {
this.options.url = this.options.deferUrl;
}
}
})(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,149 @@
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
* extensions: https://github.com/vitalets/x-editable
*/
($ => {
const Utils = $.fn.bootstrapTable.utils
$.extend($.fn.bootstrapTable.defaults, {
editable: true,
onEditableInit () {
return false
},
onEditableSave (field, row, oldValue, $el) {
return false
},
onEditableShown (field, row, $el, editable) {
return false
},
onEditableHidden (field, row, $el, reason) {
return false
}
})
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'editable-init.bs.table': 'onEditableInit',
'editable-save.bs.table': 'onEditableSave',
'editable-shown.bs.table': 'onEditableShown',
'editable-hidden.bs.table': 'onEditableHidden'
})
$.BootstrapTable = class extends $.BootstrapTable {
initTable () {
super.initTable()
if (!this.options.editable) {
return
}
$.each(this.columns, (i, column) => {
if (!column.editable) {
return
}
const editableOptions = {}
const editableDataMarkup = []
const editableDataPrefix = 'editable-'
const processDataOptions = (key, value) => {
// Replace camel case with dashes.
const dashKey = key.replace(/([A-Z])/g, $1 => `-${$1.toLowerCase()}`)
if (dashKey.indexOf(editableDataPrefix) === 0) {
editableOptions[dashKey.replace(editableDataPrefix, 'data-')] = value
}
}
$.each(this.options, processDataOptions)
column.formatter = column.formatter || (value => value)
column._formatter = column._formatter ? column._formatter : column.formatter
column.formatter = (value, row, index) => {
const result = Utils.calculateObjectValue(column,
column._formatter, [value, row, index], value)
$.each(column, processDataOptions)
$.each(editableOptions, (key, value) => {
editableDataMarkup.push(` ${key}="${value}"`)
})
let _dont_edit_formatter = false
if (column.editable.hasOwnProperty('noeditFormatter')) {
_dont_edit_formatter = column.editable.noeditFormatter(value, row, index)
}
if (_dont_edit_formatter === false) {
return `<a href="javascript:void(0)"
data-name="${column.field}"
data-pk="${row[this.options.idField]}"
data-value="${result}"
${editableDataMarkup.join('')}></a>`
}
return _dont_edit_formatter
}
})
}
initBody (fixedScroll) {
super.initBody(fixedScroll)
if (!this.options.editable) {
return
}
$.each(this.columns, (i, column) => {
if (!column.editable) {
return
}
const data = this.getData()
const $field = this.$body.find(`a[data-name="${column.field}"]`)
$field.each((i, element) => {
const $element = $(element)
const $tr = $element.closest('tr')
const index = $tr.data('index')
const row = data[index]
const editableOpts = Utils.calculateObjectValue(column,
column.editable, [index, row, $element], {})
$element.editable(editableOpts)
})
$field.off('save').on('save', ({currentTarget}, {submitValue}) => {
const $this = $(currentTarget)
const data = this.getData()
const index = $this.parents('tr[data-index]').data('index')
const row = data[index]
const oldValue = row[column.field]
$this.data('value', submitValue)
row[column.field] = submitValue
this.trigger('editable-save', column.field, row, oldValue, $this)
this.resetFooter()
})
$field.off('shown').on('shown', ({currentTarget}, editable) => {
const $this = $(currentTarget)
const data = this.getData()
const index = $this.parents('tr[data-index]').data('index')
const row = data[index]
this.trigger('editable-shown', column.field, row, $this, editable)
})
$field.off('hidden').on('hidden', ({currentTarget}, reason) => {
const $this = $(currentTarget)
const data = this.getData()
const index = $this.parents('tr[data-index]').data('index')
const row = data[index]
this.trigger('editable-hidden', column.field, row, $this, reason)
})
})
this.trigger('editable-init')
}
}
})(jQuery)

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,225 @@
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
* extensions: https://github.com/hhurz/tableExport.jquery.plugin
*/
($ => {
const Utils = $.fn.bootstrapTable.utils
const bootstrap = {
3: {
icons: {
export: 'glyphicon-export icon-share'
},
html: {
dropmenu: '<ul class="dropdown-menu" role="menu"></ul>',
dropitem: '<li role="menuitem" data-type="%s"><a href="javascript:">%s</a></li>'
}
},
4: {
icons: {
export: 'fa-download'
},
html: {
dropmenu: '<div class="dropdown-menu dropdown-menu-right"></div>',
dropitem: '<a class="dropdown-item" data-type="%s" href="javascript:">%s</a>'
}
}
}[Utils.bootstrapVersion]
const TYPE_NAME = {
json: 'JSON',
xml: 'XML',
png: 'PNG',
csv: 'CSV',
txt: 'TXT',
sql: 'SQL',
doc: 'MS-Word',
excel: 'MS-Excel',
xlsx: 'MS-Excel (OpenXML)',
powerpoint: 'MS-Powerpoint',
pdf: 'PDF'
}
$.extend($.fn.bootstrapTable.defaults, {
showExport: false,
exportDataType: 'basic', // basic, all, selected
exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel'],
exportOptions: {},
exportFooter: false
})
$.extend($.fn.bootstrapTable.defaults.icons, {
export: bootstrap.icons.export
})
$.extend($.fn.bootstrapTable.locales, {
formatExport () {
return 'Export data'
}
})
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
$.fn.bootstrapTable.methods.push('exportTable')
$.BootstrapTable = class extends $.BootstrapTable {
initToolbar () {
const o = this.options
this.showToolbar = this.showToolbar || o.showExport
super.initToolbar()
if (!this.options.showExport) {
return
}
const $btnGroup = this.$toolbar.find('>.btn-group')
this.$export = $btnGroup.find('div.export')
if (this.$export.length) {
this.updateExportButton()
return
}
this.$export = $(`
<div class="export btn-group">
<button class="btn btn-${o.buttonsClass} btn-${o.iconSize} dropdown-toggle"
aria-label="export type"
title="${o.formatExport()}"
data-toggle="dropdown"
type="button">
<i class="${o.iconsPrefix} ${o.icons.export}"></i>
<span class="caret"></span>
</button>
${bootstrap.html.dropmenu}
</div>
`).appendTo($btnGroup)
this.updateExportButton()
const $menu = this.$export.find('.dropdown-menu')
let exportTypes = o.exportTypes
if (typeof exportTypes === 'string') {
const types = exportTypes.slice(1, -1).replace(/ /g, '').split(',')
exportTypes = types.map(t => t.slice(1, -1))
}
for (const type of exportTypes) {
if (TYPE_NAME.hasOwnProperty(type)) {
$menu.append(Utils.sprintf(bootstrap.html.dropitem, type, TYPE_NAME[type]))
}
}
$menu.find('>li, >a').click(({currentTarget}) => {
const type = $(currentTarget).data('type')
const exportOptions = {
type,
escape: false
}
this.exportTable(exportOptions)
})
}
exportTable (options) {
const o = this.options
const stateField = this.header.stateField
const isCardView = o.cardView
const doExport = callback => {
if (stateField) {
this.hideColumn(stateField)
}
if (isCardView) {
this.toggleView()
}
const data = this.getData()
if (o.exportFooter) {
const $footerRow = this.$tableFooter.find('tr').first()
const footerData = {}
const footerHtml = []
$.each($footerRow.children(), (index, footerCell) => {
const footerCellHtml = $(footerCell).children('.th-inner').first().html()
footerData[this.columns[index].field] = footerCellHtml === '&nbsp;' ? null : footerCellHtml
// grab footer cell text into cell index-based array
footerHtml.push(footerCellHtml)
})
this.append(footerData)
const $lastTableRow = this.$body.children().last()
$.each($lastTableRow.children(), (index, lastTableRowCell) => {
$(lastTableRowCell).html(footerHtml[index])
})
}
this.$el.tableExport($.extend({
onAfterSaveToFile: () => {
if (o.exportFooter) {
this.load(data)
}
if (stateField) {
this.showColumn(stateField)
}
if (isCardView) {
this.toggleView()
}
callback()
}
}, o.exportOptions, options))
}
if (o.exportDataType === 'all' && o.pagination) {
const eventName = o.sidePagination === 'server'
? 'post-body.bs.table' : 'page-change.bs.table'
this.$el.one(eventName, () => {
doExport(() => {
this.togglePagination()
})
})
this.togglePagination()
} else if (o.exportDataType === 'selected') {
let data = this.getData()
let selectedData = this.getSelections()
if (!selectedData.length) {
return
}
if (o.sidePagination === 'server') {
data = {
total: o.totalRows,
[this.options.dataField]: data
}
selectedData = {
total: selectedData.length,
[this.options.dataField]: selectedData
}
}
this.load(selectedData)
doExport(() => {
this.load(data)
})
} else {
doExport()
}
}
updateSelected () {
super.updateSelected()
this.updateExportButton()
}
updateExportButton () {
if (this.options.exportDataType === 'selected') {
this.$export.find('> button')
.prop('disabled', !this.getSelections().length)
}
}
}
})(jQuery)

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,13 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v2.1.1
*/
.no-filter-control {
height: 34px;
}
.filter-control {
margin: 0 2px 2px 2px;
}

View File

@@ -0,0 +1,917 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v2.2.0
*/
($ => {
const Utils = $.fn.bootstrapTable.utils
const UtilsFilterControl = {
getOptionsFromSelectControl (selectControl) {
return selectControl.get(selectControl.length - 1).options
},
hideUnusedSelectOptions (selectControl, uniqueValues) {
const options = UtilsFilterControl.getOptionsFromSelectControl(
selectControl
)
for (let i = 0; i < options.length; i++) {
if (options[i].value !== '') {
if (!uniqueValues.hasOwnProperty(options[i].value)) {
selectControl
.find(Utils.sprintf('option[value=\'%s\']', options[i].value))
.hide()
} else {
selectControl
.find(Utils.sprintf('option[value=\'%s\']', options[i].value))
.show()
}
}
}
},
addOptionToSelectControl (selectControl, _value, text) {
const value = $.trim(_value)
const $selectControl = $(selectControl.get(selectControl.length - 1))
if (
!UtilsFilterControl.existOptionInSelectControl(selectControl, value)
) {
$selectControl.append(
$('<option></option>')
.attr('value', value)
.text(
$('<div />')
.html(text)
.text()
)
)
}
},
sortSelectControl (selectControl) {
const $selectControl = $(selectControl.get(selectControl.length - 1))
const $opts = $selectControl.find('option:gt(0)')
$opts.sort((a, b) => {
let aa = $(a).text().toLowerCase()
let bb = $(b).text().toLowerCase()
if ($.isNumeric(a) && $.isNumeric(b)) {
// Convert numerical values from string to float.
aa = parseFloat(aa)
bb = parseFloat(bb)
}
return aa > bb ? 1 : aa < bb ? -1 : 0
})
$selectControl.find('option:gt(0)').remove()
$selectControl.append($opts)
},
existOptionInSelectControl (selectControl, value) {
const options = UtilsFilterControl.getOptionsFromSelectControl(
selectControl
)
for (let i = 0; i < options.length; i++) {
if (options[i].value === value.toString()) {
// The value is not valid to add
return true
}
}
// If we get here, the value is valid to add
return false
},
fixHeaderCSS ({ $tableHeader }) {
$tableHeader.css('height', '77px')
},
getCurrentHeader ({ $header, options, $tableHeader }) {
let header = $header
if (options.height) {
header = $tableHeader
}
return header
},
getCurrentSearchControls ({ options }) {
let searchControls = 'select, input'
if (options.height) {
searchControls = 'table select, table input'
}
return searchControls
},
getCursorPosition (el) {
if (Utils.isIEBrowser()) {
if ($(el).is('input[type=text]')) {
let pos = 0
if ('selectionStart' in el) {
pos = el.selectionStart
} else if ('selection' in document) {
el.focus()
const Sel = document.selection.createRange()
const SelLength = document.selection.createRange().text.length
Sel.moveStart('character', -el.value.length)
pos = Sel.text.length - SelLength
}
return pos
}
return -1
}
return -1
},
setCursorPosition (el) {
$(el).val(el.value)
},
copyValues (that) {
const header = UtilsFilterControl.getCurrentHeader(that)
const searchControls = UtilsFilterControl.getCurrentSearchControls(that)
that.options.valuesFilterControl = []
header.find(searchControls).each(function () {
that.options.valuesFilterControl.push({
field: $(this)
.closest('[data-field]')
.data('field'),
value: $(this).val(),
position: UtilsFilterControl.getCursorPosition($(this).get(0)),
hasFocus: $(this).is(':focus')
})
})
},
setValues (that) {
let field = null
let result = []
const header = UtilsFilterControl.getCurrentHeader(that)
const searchControls = UtilsFilterControl.getCurrentSearchControls(that)
if (that.options.valuesFilterControl.length > 0) {
// Callback to apply after settings fields values
let fieldToFocusCallback = null
header.find(searchControls).each(function (index, ele) {
field = $(this)
.closest('[data-field]')
.data('field')
result = that.options.valuesFilterControl.filter(valueObj => valueObj.field === field)
if (result.length > 0) {
$(this).val(result[0].value)
if (result[0].hasFocus) {
// set callback if the field had the focus.
fieldToFocusCallback = ((fieldToFocus, carretPosition) => {
// Closure here to capture the field and cursor position
const closedCallback = () => {
fieldToFocus.focus()
UtilsFilterControl.setCursorPosition(fieldToFocus, carretPosition)
}
return closedCallback
})($(this).get(0), result[0].position)
}
}
})
// Callback call.
if (fieldToFocusCallback !== null) {
fieldToFocusCallback()
}
}
},
collectBootstrapCookies () {
const cookies = []
const foundCookies = document.cookie.match(/(?:bs.table.)(\w*)/g)
if (foundCookies) {
$.each(foundCookies, (i, _cookie) => {
let cookie = _cookie
if (/./.test(cookie)) {
cookie = cookie.split('.').pop()
}
if ($.inArray(cookie, cookies) === -1) {
cookies.push(cookie)
}
})
return cookies
}
},
escapeID (id) {
return String(id).replace(/(:|\.|\[|\]|,)/g, '\\$1')
},
isColumnSearchableViaSelect ({ filterControl, searchable }) {
return filterControl &&
filterControl.toLowerCase() === 'select' &&
searchable
},
isFilterDataNotGiven ({ filterData }) {
return filterData === undefined ||
filterData.toLowerCase() === 'column'
},
hasSelectControlElement (selectControl) {
return selectControl && selectControl.length > 0
},
initFilterSelectControls (that) {
const data = that.data
const itemsPerPage = that.pageTo < that.options.data.length ? that.options.data.length : that.pageTo
const z = that.options.pagination
? that.options.sidePagination === 'server'
? that.pageTo
: that.options.totalRows
: that.pageTo
$.each(that.header.fields, (j, field) => {
const column = that.columns[that.fieldsColumnsIndex[field]]
const selectControl = $(`.bootstrap-table-filter-control-${UtilsFilterControl.escapeID(column.field)}`)
if (
UtilsFilterControl.isColumnSearchableViaSelect(column) &&
UtilsFilterControl.isFilterDataNotGiven(column) &&
UtilsFilterControl.hasSelectControlElement(selectControl)
) {
if (selectControl.get(selectControl.length - 1).options.length === 0) {
// Added the default option
UtilsFilterControl.addOptionToSelectControl(selectControl, '', column.filterControlPlaceholder)
}
const uniqueValues = {}
for (let i = 0; i < z; i++) {
// Added a new value
const fieldValue = data[i][field]
const formattedValue = Utils.calculateObjectValue(that.header, that.header.formatters[j], [fieldValue, data[i], i], fieldValue)
uniqueValues[formattedValue] = fieldValue
}
// eslint-disable-next-line guard-for-in
for (const key in uniqueValues) {
UtilsFilterControl.addOptionToSelectControl(selectControl, uniqueValues[key], key)
}
UtilsFilterControl.sortSelectControl(selectControl)
if (that.options.hideUnusedSelectOptions) {
UtilsFilterControl.hideUnusedSelectOptions(selectControl, uniqueValues)
}
}
})
that.trigger('created-controls')
},
getFilterDataMethod (objFilterDataMethod, searchTerm) {
const keys = Object.keys(objFilterDataMethod)
for (let i = 0; i < keys.length; i++) {
if (keys[i] === searchTerm) {
return objFilterDataMethod[searchTerm]
}
}
return null
},
createControls (that, header) {
let addedFilterControl = false
let isVisible
let html
$.each(that.columns, (i, column) => {
isVisible = 'hidden'
html = []
if (!column.visible) {
return
}
if (!column.filterControl) {
html.push('<div class="no-filter-control"></div>')
} else {
html.push('<div class="filter-control">')
const nameControl = column.filterControl.toLowerCase()
if (column.searchable && that.options.filterTemplate[nameControl]) {
addedFilterControl = true
isVisible = 'visible'
html.push(
that.options.filterTemplate[nameControl](
that,
column.field,
isVisible,
column.filterControlPlaceholder
? column.filterControlPlaceholder
: '',
`filter-control-${i}`
)
)
}
}
$.each(header.children().children(), (i, tr) => {
const $tr = $(tr)
if ($tr.data('field') === column.field) {
$tr.find('.fht-cell').append(html.join(''))
return false
}
})
if (
column.filterData !== undefined &&
column.filterData.toLowerCase() !== 'column'
) {
const filterDataType = UtilsFilterControl.getFilterDataMethod(
/* eslint-disable no-use-before-define */
filterDataMethods,
column.filterData.substring(0, column.filterData.indexOf(':'))
)
let filterDataSource
let selectControl
if (filterDataType !== null) {
filterDataSource = column.filterData.substring(
column.filterData.indexOf(':') + 1,
column.filterData.length
)
selectControl = $(
`.bootstrap-table-filter-control-${UtilsFilterControl.escapeID(column.field)}`
)
UtilsFilterControl.addOptionToSelectControl(selectControl, '', column.filterControlPlaceholder)
filterDataType(filterDataSource, selectControl)
} else {
throw new SyntaxError(
'Error. You should use any of these allowed filter data methods: var, json, url.' +
' Use like this: var: {key: "value"}'
)
}
let variableValues
let key
// eslint-disable-next-line default-case
switch (filterDataType) {
case 'url':
$.ajax({
url: filterDataSource,
dataType: 'json',
success (data) {
// eslint-disable-next-line guard-for-in
for (const key in data) {
UtilsFilterControl.addOptionToSelectControl(selectControl, key, data[key])
}
UtilsFilterControl.sortSelectControl(selectControl)
}
})
break
case 'var':
variableValues = window[filterDataSource]
// eslint-disable-next-line guard-for-in
for (key in variableValues) {
UtilsFilterControl.addOptionToSelectControl(selectControl, key, variableValues[key])
}
UtilsFilterControl.sortSelectControl(selectControl)
break
case 'jso':
variableValues = JSON.parse(filterDataSource)
// eslint-disable-next-line guard-for-in
for (key in variableValues) {
UtilsFilterControl.addOptionToSelectControl(selectControl, key, variableValues[key])
}
UtilsFilterControl.sortSelectControl(selectControl)
break
}
}
})
if (addedFilterControl) {
header.off('keyup', 'input').on('keyup', 'input', (event, obj) => {
// Simulate enter key action from clear button
event.keyCode = obj ? obj.keyCode : event.keyCode
if (that.options.searchOnEnterKey && event.keyCode !== 13) {
return
}
if ($.inArray(event.keyCode, [37, 38, 39, 40]) > -1) {
return
}
const $currentTarget = $(event.currentTarget)
if ($currentTarget.is(':checkbox') || $currentTarget.is(':radio')) {
return
}
clearTimeout(event.currentTarget.timeoutId || 0)
event.currentTarget.timeoutId = setTimeout(() => {
that.onColumnSearch(event)
}, that.options.searchTimeOut)
})
header.off('change', 'select').on('change', 'select', event => {
if (that.options.searchOnEnterKey && event.keyCode !== 13) {
return
}
if ($.inArray(event.keyCode, [37, 38, 39, 40]) > -1) {
return
}
clearTimeout(event.currentTarget.timeoutId || 0)
event.currentTarget.timeoutId = setTimeout(() => {
that.onColumnSearch(event)
}, that.options.searchTimeOut)
})
header.off('mouseup', 'input').on('mouseup', 'input', function (event) {
const $input = $(this)
const oldValue = $input.val()
if (oldValue === '') {
return
}
setTimeout(() => {
const newValue = $input.val()
if (newValue === '') {
clearTimeout(event.currentTarget.timeoutId || 0)
event.currentTarget.timeoutId = setTimeout(() => {
that.onColumnSearch(event)
}, that.options.searchTimeOut)
}
}, 1)
})
if (header.find('.date-filter-control').length > 0) {
$.each(that.columns, (i, { filterControl, field, filterDatepickerOptions }) => {
if (
filterControl !== undefined &&
filterControl.toLowerCase() === 'datepicker'
) {
header
.find(
`.date-filter-control.bootstrap-table-filter-control-${field}`
)
.datepicker(filterDatepickerOptions)
.on('changeDate', ({ currentTarget }) => {
$(currentTarget).val(
currentTarget.value
)
// Fired the keyup event
$(currentTarget).keyup()
})
}
})
}
} else {
header.find('.filterControl').hide()
}
},
getDirectionOfSelectOptions (_alignment) {
const alignment = _alignment === undefined ? 'left' : _alignment.toLowerCase()
switch (alignment) {
case 'left':
return 'ltr'
case 'right':
return 'rtl'
case 'auto':
return 'auto'
default:
return 'ltr'
}
}
}
const filterDataMethods = {
var (filterDataSource, selectControl) {
const variableValues = window[filterDataSource]
// eslint-disable-next-line guard-for-in
for (const key in variableValues) {
UtilsFilterControl.addOptionToSelectControl(selectControl, key, variableValues[key])
}
UtilsFilterControl.sortSelectControl(selectControl)
},
url (filterDataSource, selectControl) {
$.ajax({
url: filterDataSource,
dataType: 'json',
success (data) {
// eslint-disable-next-line guard-for-in
for (const key in data) {
UtilsFilterControl.addOptionToSelectControl(selectControl, key, data[key])
}
UtilsFilterControl.sortSelectControl(selectControl)
}
})
},
json (filterDataSource, selectControl) {
const variableValues = JSON.parse(filterDataSource)
// eslint-disable-next-line guard-for-in
for (const key in variableValues) {
UtilsFilterControl.addOptionToSelectControl(selectControl, key, variableValues[key])
}
UtilsFilterControl.sortSelectControl(selectControl)
}
}
const bootstrap = {
3: {
icons: {
clear: 'glyphicon-trash icon-clear'
}
},
4: {
icons: {
clear: 'fa-trash icon-clear'
}
}
}[Utils.bootstrapVersion]
$.extend($.fn.bootstrapTable.defaults, {
filterControl: false,
onColumnSearch (field, text) {
return false
},
onCreatedControls () {
return true
},
filterShowClear: false,
alignmentSelectControlOptions: undefined,
filterTemplate: {
input (that, field, isVisible, placeholder) {
return Utils.sprintf(
'<input type="text" class="form-control bootstrap-table-filter-control-%s" style="width: 100%; visibility: %s" placeholder="%s">',
field,
isVisible,
placeholder
)
},
select ({ options }, field, isVisible) {
return Utils.sprintf(
'<select class="form-control bootstrap-table-filter-control-%s" style="width: 100%; visibility: %s" dir="%s"></select>',
field,
isVisible,
UtilsFilterControl.getDirectionOfSelectOptions(
options.alignmentSelectControlOptions
)
)
},
datepicker (that, field, isVisible) {
return Utils.sprintf(
'<input type="text" class="form-control date-filter-control bootstrap-table-filter-control-%s" style="width: 100%; visibility: %s">',
field,
isVisible
)
}
},
disableControlWhenSearch: false,
searchOnEnterKey: false,
// internal variables
valuesFilterControl: []
})
$.extend($.fn.bootstrapTable.columnDefaults, {
filterControl: undefined,
filterData: undefined,
filterDatepickerOptions: undefined,
filterStrictSearch: false,
filterStartsWithSearch: false,
filterControlPlaceholder: ''
})
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'column-search.bs.table': 'onColumnSearch',
'created-controls.bs.table': 'onCreatedControls'
})
$.extend($.fn.bootstrapTable.defaults.icons, {
clear: bootstrap.icons.clear
})
$.extend($.fn.bootstrapTable.locales, {
formatClearFilters () {
return 'Clear Filters'
}
})
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
$.fn.bootstrapTable.methods.push('triggerSearch')
$.fn.bootstrapTable.methods.push('clearFilterControl')
$.BootstrapTable = class extends $.BootstrapTable {
init () {
// Make sure that the filterControl option is set
if (this.options.filterControl) {
const that = this
// Make sure that the internal variables are set correctly
this.options.valuesFilterControl = []
this.$el
.on('reset-view.bs.table', () => {
// 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
}
UtilsFilterControl.createControls(that, that.$tableHeader)
})
.on('post-header.bs.table', () => {
UtilsFilterControl.setValues(that)
})
.on('post-body.bs.table', () => {
if (that.options.height) {
UtilsFilterControl.fixHeaderCSS(that)
}
})
.on('column-switch.bs.table', () => {
UtilsFilterControl.setValues(that)
})
.on('load-success.bs.table', () => {
that.EnableControls(true)
})
.on('load-error.bs.table', () => {
that.EnableControls(true)
})
}
super.init()
}
initToolbar () {
this.showToolbar =
this.showToolbar ||
(this.options.filterControl && this.options.filterShowClear)
super.initToolbar()
if (this.options.filterControl && this.options.filterShowClear) {
const $btnGroup = this.$toolbar.find('>.btn-group')
let $btnClear = $btnGroup.find('.filter-show-clear')
if (!$btnClear.length) {
$btnClear = $(
[
Utils.sprintf(
'<button class="btn btn-%s filter-show-clear" ',
this.options.buttonsClass
),
Utils.sprintf(
'type="button" title="%s">',
this.options.formatClearFilters()
),
Utils.sprintf(
'<i class="%s %s"></i> ',
this.options.iconsPrefix,
this.options.icons.clear
),
'</button>'
].join('')
).appendTo($btnGroup)
$btnClear
.off('click')
.on('click', $.proxy(this.clearFilterControl, this))
}
}
}
initHeader () {
super.initHeader()
if (!this.options.filterControl) {
return
}
UtilsFilterControl.createControls(this, this.$header)
}
initBody () {
super.initBody()
UtilsFilterControl.initFilterSelectControls(this)
}
initSearch () {
const that = this
const fp = $.isEmptyObject(that.filterColumnsPartial)
? null
: that.filterColumnsPartial
if (fp === null || Object.keys(fp).length <= 1) {
super.initSearch()
}
if (this.options.sidePagination === 'server') {
return
}
if (fp === null) {
return
}
// Check partial column filter
that.data = fp
? that.options.data.filter((item, i) => {
const itemIsExpected = []
Object.keys(item).forEach((key, index) => {
const thisColumn = that.columns[that.fieldsColumnsIndex[key]]
const fval = (fp[key] || '').toLowerCase()
let value = item[key]
if (fval === '') {
itemIsExpected.push(true)
} else {
// Fix #142: search use formated data
if (thisColumn && thisColumn.searchFormatter) {
value = $.fn.bootstrapTable.utils.calculateObjectValue(
that.header,
that.header.formatters[$.inArray(key, that.header.fields)],
[value, item, i],
value
)
}
if ($.inArray(key, that.header.fields) !== -1) {
if (typeof value === 'string' || typeof value === 'number') {
if (thisColumn.filterStrictSearch) {
if (value.toString().toLowerCase() === fval.toString().toLowerCase()) {
itemIsExpected.push(true)
} else {
itemIsExpected.push(false)
}
} else if (thisColumn.filterStartsWithSearch) {
if ((`${value}`).toLowerCase().indexOf(fval) === 0) {
itemIsExpected.push(true)
} else {
itemIsExpected.push(false)
}
} else {
if ((`${value}`).toLowerCase().includes(fval)) {
itemIsExpected.push(true)
} else {
itemIsExpected.push(false)
}
}
}
}
}
})
return !itemIsExpected.includes(false)
})
: that.data
}
initColumnSearch (filterColumnsDefaults) {
UtilsFilterControl.copyValues(this)
if (filterColumnsDefaults) {
this.filterColumnsPartial = filterColumnsDefaults
this.updatePagination()
// eslint-disable-next-line guard-for-in
for (const filter in filterColumnsDefaults) {
this.trigger('column-search', filter, filterColumnsDefaults[filter])
}
}
}
onColumnSearch (event) {
if ($.inArray(event.keyCode, [37, 38, 39, 40]) > -1) {
return
}
UtilsFilterControl.copyValues(this)
const text = $.trim($(event.currentTarget).val())
const $field = $(event.currentTarget)
.closest('[data-field]')
.data('field')
if ($.isEmptyObject(this.filterColumnsPartial)) {
this.filterColumnsPartial = {}
}
if (text) {
this.filterColumnsPartial[$field] = text
} else {
delete this.filterColumnsPartial[$field]
}
// if the searchText is the same as the previously selected column value,
// bootstrapTable will not try searching again (even though the selected column
// may be different from the previous search). As a work around
// we're manually appending some text to bootrap's searchText field
// to guarantee that it will perform a search again when we call this.onSearch(event)
this.searchText += 'randomText'
this.options.pageNumber = 1
this.EnableControls(false)
this.onSearch(event)
this.trigger('column-search', $field, text)
}
clearFilterControl () {
if (this.options.filterControl && this.options.filterShowClear) {
const that = this
const cookies = UtilsFilterControl.collectBootstrapCookies()
const header = UtilsFilterControl.getCurrentHeader(that)
const table = header.closest('table')
const controls = header.find(UtilsFilterControl.getCurrentSearchControls(that))
const search = that.$toolbar.find('.search input')
let hasValues = false
let timeoutId = 0
$.each(that.options.valuesFilterControl, (i, item) => {
hasValues = hasValues ? true : item.value !== ''
item.value = ''
})
UtilsFilterControl.setValues(that)
// clear cookies once the filters are clean
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
if (cookies && cookies.length > 0) {
$.each(cookies, (i, item) => {
if (that.deleteCookie !== undefined) {
that.deleteCookie(item)
}
})
}
}, that.options.searchTimeOut)
// If there is not any value in the controls exit this method
if (!hasValues) {
return
}
// Clear each type of filter if it exists.
// Requires the body to reload each time a type of filter is found because we never know
// which ones are going to be present.
if (controls.length > 0) {
this.filterColumnsPartial = {}
$(controls[0]).trigger(
controls[0].tagName === 'INPUT' ? 'keyup' : 'change', { keyCode: 13 }
)
} else {
return
}
if (search.length > 0) {
that.resetSearch()
}
// use the default sort order if it exists. do nothing if it does not
if (
that.options.sortName !== table.data('sortName') ||
that.options.sortOrder !== table.data('sortOrder')
) {
const sorter = header.find(
Utils.sprintf(
'[data-field="%s"]',
$(controls[0])
.closest('table')
.data('sortName')
)
)
if (sorter.length > 0) {
that.onSort({ type: 'keypress', currentTarget: sorter })
$(sorter)
.find('.sortable')
.trigger('click')
}
}
}
}
triggerSearch () {
const header = UtilsFilterControl.getCurrentHeader(this)
const searchControls = UtilsFilterControl.getCurrentSearchControls(this)
header.find(searchControls).each(function () {
const el = $(this)
if (el.is('select')) {
el.change()
} else {
el.keyup()
}
})
}
EnableControls (enable) {
if (
this.options.disableControlWhenSearch &&
this.options.sidePagination === 'server'
) {
const header = UtilsFilterControl.getCurrentHeader(this)
const searchControls = UtilsFilterControl.getCurrentSearchControls(this)
if (!enable) {
header.find(searchControls).prop('disabled', 'disabled')
} else {
header.find(searchControls).removeProp('disabled')
}
}
}
}
})(jQuery)

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,27 @@
.fixed-table-header-columns,
.fixed-table-body-columns {
position: absolute;
background-color: #fff;
box-sizing: border-box;
overflow: hidden;
z-index: 1;
}
.fixed-table-header-columns {
z-index: 2;
}
.fixed-table-header-columns .table,
.fixed-table-body-columns .table {
border-right: 1px solid #ddd;
}
.fixed-table-header-columns .table.table-no-bordered,
.fixed-table-body-columns .table.table-no-bordered {
border-right: 1px solid transparent;
}
.fixed-table-body-columns table {
position: absolute;
animation: none;
}

View File

@@ -0,0 +1,115 @@
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
*/
($ => {
$.extend($.fn.bootstrapTable.defaults, {
fixedColumns: false,
fixedNumber: 1
})
$.BootstrapTable = class extends $.BootstrapTable {
fitHeader (...args) {
super.fitHeader(...args)
if (!this.options.fixedColumns) {
return
}
if (this.$el.is(':hidden')) {
return
}
this.$container.find('.fixed-table-header-columns').remove()
this.$fixedHeader = $('<div class="fixed-table-header-columns"></div>')
this.$fixedHeader.append(this.$tableHeader.find('>table').clone(true))
this.$tableHeader.after(this.$fixedHeader)
const width = this.getFixedColumnsWidth()
this.$fixedHeader.css({
top: 0,
width,
height: this.$tableHeader.outerHeight(true)
})
this.initFixedColumnsBody()
this.$fixedBody.css({
top: this.$tableHeader.outerHeight(true),
width,
height: this.$tableBody.outerHeight(true) - 1
})
this.initFixedColumnsEvents()
}
initBody (...args) {
super.initBody(...args)
if (!this.options.fixedColumns) {
return
}
if (this.options.showHeader && this.options.height) {
return
}
this.initFixedColumnsBody()
this.$fixedBody.css({
top: 0,
width: this.getFixedColumnsWidth(),
height: this.$tableHeader.outerHeight(true) + this.$tableBody.outerHeight(true)
})
this.initFixedColumnsEvents()
}
initFixedColumnsBody () {
this.$container.find('.fixed-table-body-columns').remove()
this.$fixedBody = $('<div class="fixed-table-body-columns"></div>')
this.$fixedBody.append(this.$tableBody.find('>table').clone(true))
this.$tableBody.after(this.$fixedBody)
}
getFixedColumnsWidth () {
const visibleFields = this.getVisibleFields()
let width = 0
for (let i = 0; i < this.options.fixedNumber; i++) {
width += this.$header.find(`th[data-field="${visibleFields[i]}"]`).outerWidth(true)
}
return width + 1
}
initFixedColumnsEvents () {
// events
this.$tableBody.off('scroll.fixed-columns').on('scroll.fixed-columns', e => {
this.$fixedBody.find('table').css('top', -$(e.currentTarget).scrollTop())
})
this.$body.find('> tr[data-index]').off('hover').hover(e => {
const index = $(e.currentTarget).data('index')
this.$fixedBody.find(`tr[data-index="${index}"]`)
.css('background-color', $(e.currentTarget).css('background-color'))
}, e => {
const index = $(e.currentTarget).data('index')
const $tr = this.$fixedBody.find(`tr[data-index="${index}"]`)
$tr.attr('style', $tr.attr('style').replace(/background-color:.*;/, ''))
})
this.$fixedBody.find('tr[data-index]').off('hover').hover(e => {
const index = $(e.currentTarget).data('index')
this.$body.find(`tr[data-index="${index}"]`)
.css('background-color', $(e.currentTarget).css('background-color'))
}, e => {
const index = $(e.currentTarget).data('index')
const $tr = this.$body.find(`> tr[data-index="${index}"]`)
$tr.attr('style', $tr.attr('style').replace(/background-color:.*;/, ''))
})
}
}
})(jQuery)

View File

@@ -0,0 +1,11 @@
.bootstrap-table .table > tbody > tr.groupBy {
cursor: pointer;
}
.bootstrap-table .table > tbody > tr.groupBy.expanded {
}
.bootstrap-table .table > tbody > tr.hidden + tr.detail-view {
display: none;
}

View File

@@ -0,0 +1,230 @@
/**
* @author: Yura Knoxville
* @version: v1.1.0
*/
(function ($) {
'use strict';
var initBodyCaller,
tableGroups;
// it only does '%s', and return '' when arguments are undefined
var sprintf = function (str) {
var args = arguments,
flag = true,
i = 1;
str = str.replace(/%s/g, function () {
var arg = args[i++];
if (typeof arg === 'undefined') {
flag = false;
return '';
}
return arg;
});
return flag ? str : '';
};
var groupBy = function (array , f) {
var groups = {};
array.forEach(function(o) {
var group = f(o);
groups[group] = groups[group] || [];
groups[group].push(o);
});
return groups;
};
$.extend($.fn.bootstrapTable.defaults, {
groupBy: false,
groupByField: '',
groupByFormatter: undefined
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initSort = BootstrapTable.prototype.initSort,
_initBody = BootstrapTable.prototype.initBody,
_updateSelected = BootstrapTable.prototype.updateSelected;
BootstrapTable.prototype.initSort = function () {
_initSort.apply(this, Array.prototype.slice.apply(arguments));
var that = this;
tableGroups = [];
if ((this.options.groupBy) && (this.options.groupByField !== '')) {
if ((this.options.sortName != this.options.groupByField)) {
this.data.sort(function(a, b) {
return a[that.options.groupByField].localeCompare(b[that.options.groupByField]);
});
}
var that = this;
var groups = groupBy(that.data, function (item) {
return [item[that.options.groupByField]];
});
var index = 0;
$.each(groups, function(key, value) {
tableGroups.push({
id: index,
name: key,
data: value
});
value.forEach(function(item) {
if (!item._data) {
item._data = {};
}
item._data['parent-index'] = index;
});
index++;
});
}
}
BootstrapTable.prototype.initBody = function () {
initBodyCaller = true;
_initBody.apply(this, Array.prototype.slice.apply(arguments));
if ((this.options.groupBy) && (this.options.groupByField !== '')) {
var that = this,
checkBox = false,
visibleColumns = 0;
this.columns.forEach(function(column) {
if (column.checkbox) {
checkBox = true;
} else {
if (column.visible) {
visibleColumns += 1;
}
}
});
if (this.options.detailView && !this.options.cardView) {
visibleColumns += 1;
}
tableGroups.forEach(function(item){
var html = [];
html.push(sprintf('<tr class="info groupBy expanded" data-group-index="%s">', item.id));
if (that.options.detailView && !that.options.cardView) {
html.push('<td class="detail"></td>');
}
if (checkBox) {
html.push('<td class="bs-checkbox">',
'<input name="btSelectGroup" type="checkbox" />',
'</td>'
);
}
var formattedValue = item.name;
if (typeof(that.options.groupByFormatter) == "function") {
formattedValue = that.options.groupByFormatter(item.name, item.id, item.data);
}
html.push('<td',
sprintf(' colspan="%s"', visibleColumns),
'>', formattedValue, '</td>'
);
html.push('</tr>');
that.$body.find('tr[data-parent-index='+item.id+']:first').before($(html.join('')));
});
this.$selectGroup = [];
this.$body.find('[name="btSelectGroup"]').each(function() {
var self = $(this);
that.$selectGroup.push({
group: self,
item: that.$selectItem.filter(function () {
return ($(this).closest('tr').data('parent-index') ===
self.closest('tr').data('group-index'));
})
});
});
this.$container.off('click', '.groupBy')
.on('click', '.groupBy', function() {
$(this).toggleClass('expanded');
that.$body.find('tr[data-parent-index='+$(this).closest('tr').data('group-index')+']').toggleClass('hidden');
});
this.$container.off('click', '[name="btSelectGroup"]')
.on('click', '[name="btSelectGroup"]', function (event) {
event.stopImmediatePropagation();
var self = $(this);
var checked = self.prop('checked');
that[checked ? 'checkGroup' : 'uncheckGroup']($(this).closest('tr').data('group-index'));
});
}
initBodyCaller = false;
this.updateSelected();
};
BootstrapTable.prototype.updateSelected = function () {
if (!initBodyCaller) {
_updateSelected.apply(this, Array.prototype.slice.apply(arguments));
if ((this.options.groupBy) && (this.options.groupByField !== '')) {
this.$selectGroup.forEach(function (item) {
var checkGroup = item.item.filter(':enabled').length ===
item.item.filter(':enabled').filter(':checked').length;
item.group.prop('checked', checkGroup);
});
}
}
};
BootstrapTable.prototype.getGroupSelections = function (index) {
var that = this;
return $.grep(this.data, function (row) {
return (row[that.header.stateField] && (row._data['parent-index'] === index));
});
};
BootstrapTable.prototype.checkGroup = function (index) {
this.checkGroup_(index, true);
};
BootstrapTable.prototype.uncheckGroup = function (index) {
this.checkGroup_(index, false);
};
BootstrapTable.prototype.checkGroup_ = function (index, checked) {
var rows;
var filter = function() {
return ($(this).closest('tr').data('parent-index') === index);
};
if (!checked) {
rows = this.getGroupSelections(index);
}
this.$selectItem.filter(filter).prop('checked', checked);
this.updateRows();
this.updateSelected();
if (checked) {
rows = this.getGroupSelections(index);
}
this.trigger(checked ? 'check-all' : 'uncheck-all', rows);
};
})(jQuery);

View File

@@ -0,0 +1,12 @@
{
"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

@@ -0,0 +1,53 @@
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,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAHlJREFUeNrcU1sNgDAQ6wgmcAM2MICGGlg1gJnNzWQcvwQGy1j4oUl/7tH0mpwzM7SgQyO+EZAUWh2MkkzSWhJwuRAlHYsJwEwyvs1gABDuzqoJcTw5qxaIJN0bgQRgIjnlmn1heSO5PE6Y2YXe+5Cr5+h++gs12AcAS6FS+7YOsj4AAAAASUVORK5CYII=);
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

@@ -0,0 +1,243 @@
/**
* @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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,35 @@
/**
* @author: Jewway
* @version: v1.0.0
*/
!function ($) {
'use strict';
var BootstrapTable = $.fn.bootstrapTable.Constructor;
BootstrapTable.prototype.changeTitle = function (locale) {
$.each(this.options.columns, function (idx, columnList) {
$.each(columnList, function (idx, column) {
if (column.field) {
column.title = locale[column.field];
}
});
});
this.initHeader();
this.initBody();
this.initToolbar();
};
BootstrapTable.prototype.changeLocale = function (localeId) {
this.options.locale = localeId;
this.initLocale();
this.initPagination();
this.initBody();
this.initToolbar();
};
$.fn.bootstrapTable.methods.push('changeTitle');
$.fn.bootstrapTable.methods.push('changeLocale');
}(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,80 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.0.0
*
* @update zhixin wen <wenzhixin2010@gmail.com>
*/
!function ($) {
'use strict';
$.extend($.fn.bootstrapTable.defaults, {
keyEvents: false
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init;
BootstrapTable.prototype.init = function () {
_init.apply(this, Array.prototype.slice.apply(arguments));
this.initKeyEvents();
};
BootstrapTable.prototype.initKeyEvents = function () {
if (this.options.keyEvents) {
var that = this;
$(document).off('keydown').on('keydown', function (e) {
var $search = that.$toolbar.find('.search input'),
$refresh = that.$toolbar.find('button[name="refresh"]'),
$toggle = that.$toolbar.find('button[name="toggle"]'),
$paginationSwitch = that.$toolbar.find('button[name="paginationSwitch"]');
if (document.activeElement === $search.get(0) || !$.contains(document.activeElement ,that.$toolbar.get(0))) {
return true;
}
switch (e.keyCode) {
case 83: //s
if (!that.options.search) {
return;
}
$search.focus();
return false;
case 82: //r
if (!that.options.showRefresh) {
return;
}
$refresh.click();
return false;
case 84: //t
if (!that.options.showToggle) {
return;
}
$toggle.click();
return false;
case 80: //p
if (!that.options.showPaginationSwitch) {
return;
}
$paginationSwitch.click();
return false;
case 37: // left
if (!that.options.pagination) {
return;
}
that.prevPage();
return false;
case 39: // right
if (!that.options.pagination) {
return;
}
that.nextPage();
return;
}
});
}
};
}(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,136 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.1.0
*/
!function ($) {
'use strict';
var showHideColumns = function (that, checked) {
if (that.options.columnsHidden.length > 0 ) {
$.each(that.columns, function (i, column) {
if (that.options.columnsHidden.indexOf(column.field) !== -1) {
if (column.visible !== checked) {
that.toggleColumn(that.fieldsColumnsIndex[column.field], checked, true);
}
}
});
}
};
var resetView = function (that) {
if (that.options.height || that.options.showFooter) {
setTimeout(function(){
that.resetView.call(that);
}, 1);
}
};
var changeView = function (that, width, height) {
if (that.options.minHeight) {
if ((width <= that.options.minWidth) && (height <= that.options.minHeight)) {
conditionCardView(that);
} else if ((width > that.options.minWidth) && (height > that.options.minHeight)) {
conditionFullView(that);
}
} else {
if (width <= that.options.minWidth) {
conditionCardView(that);
} else if (width > that.options.minWidth) {
conditionFullView(that);
}
}
resetView(that);
};
var conditionCardView = function (that) {
changeTableView(that, false);
showHideColumns(that, false);
};
var conditionFullView = function (that) {
changeTableView(that, true);
showHideColumns(that, true);
};
var changeTableView = function (that, cardViewState) {
that.options.cardView = cardViewState;
that.toggleView();
};
var debounce = function(func,wait) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
func.apply(context,args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
$.extend($.fn.bootstrapTable.defaults, {
mobileResponsive: false,
minWidth: 562,
minHeight: undefined,
heightThreshold: 100, // just slightly larger than mobile chrome's auto-hiding toolbar
checkOnInit: true,
columnsHidden: []
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init;
BootstrapTable.prototype.init = function () {
_init.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.mobileResponsive) {
return;
}
if (!this.options.minWidth) {
return;
}
if (this.options.minWidth < 100 && this.options.resizable) {
console.log("The minWidth when the resizable extension is active should be greater or equal than 100");
this.options.minWidth = 100;
}
var that = this,
old = {
width: $(window).width(),
height: $(window).height()
};
$(window).on('resize orientationchange',debounce(function (evt) {
// reset view if height has only changed by at least the threshold.
var height = $(this).height(),
width = $(this).width();
if (Math.abs(old.height - height) > that.options.heightThreshold || old.width != width) {
changeView(that, width, height);
old = {
width: width,
height: height
};
}
},200));
if (this.options.checkOnInit) {
var height = $(window).height(),
width = $(window).width();
changeView(this, width, height);
old = {
width: width,
height: height
};
}
};
}(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,88 @@
/**
* @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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,71 @@
/**
* @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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,17 @@
.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

@@ -0,0 +1,127 @@
/**
* @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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,412 @@
/**
* @author Nadim Basalamah <dimbslmh@gmail.com>
* @version: v1.1.0
* https://github.com/dimbslmh/bootstrap-table/tree/master/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js
* Modification: ErwannNevou <https://github.com/ErwannNevou>
*/
(function($) {
'use strict';
var isSingleSort = false;
var showSortModal = function(that) {
var _selector = that.sortModalSelector,
_id = '#' + _selector;
if (!$(_id).hasClass("modal")) {
var sModal = ' <div class="modal fade" id="' + _selector + '" tabindex="-1" role="dialog" aria-labelledby="' + _selector + 'Label" aria-hidden="true">';
sModal += ' <div class="modal-dialog">';
sModal += ' <div class="modal-content">';
sModal += ' <div class="modal-header">';
sModal += ' <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
sModal += ' <h4 class="modal-title" id="' + _selector + 'Label">' + that.options.formatMultipleSort() + '</h4>';
sModal += ' </div>';
sModal += ' <div class="modal-body">';
sModal += ' <div class="bootstrap-table">';
sModal += ' <div class="fixed-table-toolbar">';
sModal += ' <div class="bars">';
sModal += ' <div id="toolbar">';
sModal += ' <button id="add" type="button" class="btn btn-default"><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.plus + '"></i> ' + that.options.formatAddLevel() + '</button>';
sModal += ' <button id="delete" type="button" class="btn btn-default" disabled><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.minus + '"></i> ' + that.options.formatDeleteLevel() + '</button>';
sModal += ' </div>';
sModal += ' </div>';
sModal += ' </div>';
sModal += ' <div class="fixed-table-container">';
sModal += ' <table id="multi-sort" class="table">';
sModal += ' <thead>';
sModal += ' <tr>';
sModal += ' <th></th>';
sModal += ' <th><div class="th-inner">' + that.options.formatColumn() + '</div></th>';
sModal += ' <th><div class="th-inner">' + that.options.formatOrder() + '</div></th>';
sModal += ' </tr>';
sModal += ' </thead>';
sModal += ' <tbody></tbody>';
sModal += ' </table>';
sModal += ' </div>';
sModal += ' </div>';
sModal += ' </div>';
sModal += ' <div class="modal-footer">';
sModal += ' <button type="button" class="btn btn-default" data-dismiss="modal">' + that.options.formatCancel() + '</button>';
sModal += ' <button type="button" class="btn btn-primary">' + that.options.formatSort() + '</button>';
sModal += ' </div>';
sModal += ' </div>';
sModal += ' </div>';
sModal += ' </div>';
$('body').append($(sModal));
that.$sortModal = $(_id);
var $rows = that.$sortModal.find('tbody > tr');
that.$sortModal.off('click', '#add').on('click', '#add', function() {
var total = that.$sortModal.find('.multi-sort-name:first option').length,
current = that.$sortModal.find('tbody tr').length;
if (current < total) {
current++;
that.addLevel();
that.setButtonStates();
}
});
that.$sortModal.off('click', '#delete').on('click', '#delete', function() {
var total = that.$sortModal.find('.multi-sort-name:first option').length,
current = that.$sortModal.find('tbody tr').length;
if (current > 1 && current <= total) {
current--;
that.$sortModal.find('tbody tr:last').remove();
that.setButtonStates();
}
});
that.$sortModal.off('click', '.btn-primary').on('click', '.btn-primary', function() {
var $rows = that.$sortModal.find('tbody > tr'),
$alert = that.$sortModal.find('div.alert'),
fields = [],
results = [];
that.options.sortPriority = $.map($rows, function(row) {
var $row = $(row),
name = $row.find('.multi-sort-name').val(),
order = $row.find('.multi-sort-order').val();
fields.push(name);
return {
sortName: name,
sortOrder: order
};
});
var sorted_fields = fields.sort();
for (var i = 0; i < fields.length - 1; i++) {
if (sorted_fields[i + 1] == sorted_fields[i]) {
results.push(sorted_fields[i]);
}
}
if (results.length > 0) {
if ($alert.length === 0) {
$alert = '<div class="alert alert-danger" role="alert"><strong>' + that.options.formatDuplicateAlertTitle() + '</strong> ' + that.options.formatDuplicateAlertDescription() + '</div>';
$($alert).insertBefore(that.$sortModal.find('.bars'));
}
} else {
if ($alert.length === 1) {
$($alert).remove();
}
that.$sortModal.modal('hide');
that.options.sortName = '';
if (that.options.sidePagination === 'server') {
var t = that.options.queryParams;
that.options.queryParams = function(params) {
params.multiSort = that.options.sortPriority;
return t(params);
};
isSingleSort=false;
that.initServer(that.options.silentSort);
return;
}
that.onMultipleSort();
}
});
if (that.options.sortPriority === null || that.options.sortPriority.length === 0) {
if (that.options.sortName) {
that.options.sortPriority = [{
sortName: that.options.sortName,
sortOrder: that.options.sortOrder
}];
}
}
if (that.options.sortPriority !== null && that.options.sortPriority.length > 0) {
if ($rows.length < that.options.sortPriority.length && typeof that.options.sortPriority === 'object') {
for (var i = 0; i < that.options.sortPriority.length; i++) {
that.addLevel(i, that.options.sortPriority[i]);
}
}
} else {
that.addLevel(0);
}
that.setButtonStates();
}
};
$.fn.bootstrapTable.methods.push('multipleSort');
$.extend($.fn.bootstrapTable.defaults, {
showMultiSort: false,
showMultiSortButton: true,
sortPriority: null,
onMultipleSort: function() {
return false;
}
});
$.extend($.fn.bootstrapTable.defaults.icons, {
sort: 'glyphicon-sort',
plus: 'glyphicon-plus',
minus: 'glyphicon-minus'
});
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'multiple-sort.bs.table': 'onMultipleSort'
});
$.extend($.fn.bootstrapTable.locales, {
formatMultipleSort: function() {
return 'Multiple Sort';
},
formatAddLevel: function() {
return 'Add Level';
},
formatDeleteLevel: function() {
return 'Delete Level';
},
formatColumn: function() {
return 'Column';
},
formatOrder: function() {
return 'Order';
},
formatSortBy: function() {
return 'Sort by';
},
formatThenBy: function() {
return 'Then by';
},
formatSort: function() {
return 'Sort';
},
formatCancel: function() {
return 'Cancel';
},
formatDuplicateAlertTitle: function() {
return 'Duplicate(s) detected!';
},
formatDuplicateAlertDescription: function() {
return 'Please remove or change any duplicate column.';
},
formatSortOrders: function() {
return {
asc: 'Ascending',
desc: 'Descending'
};
}
});
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales);
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initToolbar = BootstrapTable.prototype.initToolbar;
BootstrapTable.prototype.initToolbar = function() {
this.showToolbar = this.showToolbar || this.options.showMultiSort;
var that = this,
sortModalSelector = 'sortModal_' + this.$el.attr('id'),
sortModalId = '#' + sortModalSelector;
this.$sortModal = $(sortModalId);
this.sortModalSelector = sortModalSelector;
_initToolbar.apply(this, Array.prototype.slice.apply(arguments));
if (that.options.sidePagination === 'server' && !isSingleSort && that.options.sortPriority !== null){
var t = that.options.queryParams;
that.options.queryParams = function(params) {
params.multiSort = that.options.sortPriority;
return t(params);
};
}
if (this.options.showMultiSort) {
var $btnGroup = this.$toolbar.find('>.btn-group').first(),
$multiSortBtn = this.$toolbar.find('div.multi-sort');
if (!$multiSortBtn.length && this.options.showMultiSortButton) {
$multiSortBtn = ' <button class="multi-sort btn btn-default' + (this.options.iconSize === undefined ? '' : ' btn-' + this.options.iconSize) + '" type="button" data-toggle="modal" data-target="' + sortModalId + '" title="' + this.options.formatMultipleSort() + '">';
$multiSortBtn += ' <i class="' + this.options.iconsPrefix + ' ' + this.options.icons.sort + '"></i>';
$multiSortBtn += '</button>';
$btnGroup.append($multiSortBtn);
showSortModal(that);
}
this.$el.on('sort.bs.table', function() {
isSingleSort = true;
});
this.$el.on('multiple-sort.bs.table', function() {
isSingleSort = false;
});
this.$el.on('load-success.bs.table', function() {
if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object' && that.options.sidePagination !== 'server') {
that.onMultipleSort();
}
});
this.$el.on('column-switch.bs.table', function(field, checked) {
for (var i = 0; i < that.options.sortPriority.length; i++) {
if (that.options.sortPriority[i].sortName === checked) {
that.options.sortPriority.splice(i, 1);
}
}
that.assignSortableArrows();
that.$sortModal.remove();
showSortModal(that);
});
this.$el.on('reset-view.bs.table', function() {
if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object') {
that.assignSortableArrows();
}
});
}
};
BootstrapTable.prototype.multipleSort = function() {
var that = this;
if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object' && that.options.sidePagination !== 'server') {
that.onMultipleSort();
}
};
BootstrapTable.prototype.onMultipleSort = function() {
var that = this;
var cmp = function(x, y) {
return x > y ? 1 : x < y ? -1 : 0;
};
var arrayCmp = function(a, b) {
var arr1 = [],
arr2 = [];
for (var i = 0; i < that.options.sortPriority.length; i++) {
var order = that.options.sortPriority[i].sortOrder === 'desc' ? -1 : 1,
aa = a[that.options.sortPriority[i].sortName],
bb = b[that.options.sortPriority[i].sortName];
if (aa === undefined || aa === null) {
aa = '';
}
if (bb === undefined || bb === null) {
bb = '';
}
if ($.isNumeric(aa) && $.isNumeric(bb)) {
aa = parseFloat(aa);
bb = parseFloat(bb);
}
if (typeof aa !== 'string') {
aa = aa.toString();
}
arr1.push(
order * cmp(aa, bb));
arr2.push(
order * cmp(bb, aa));
}
return cmp(arr1, arr2);
};
this.data.sort(function(a, b) {
return arrayCmp(a, b);
});
this.initBody();
this.assignSortableArrows();
this.trigger('multiple-sort');
};
BootstrapTable.prototype.addLevel = function(index, sortPriority) {
var text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy();
this.$sortModal.find('tbody')
.append($('<tr>')
.append($('<td>').text(text))
.append($('<td>').append($('<select class="form-control multi-sort-name">')))
.append($('<td>').append($('<select class="form-control multi-sort-order">')))
);
var $multiSortName = this.$sortModal.find('.multi-sort-name').last(),
$multiSortOrder = this.$sortModal.find('.multi-sort-order').last();
$.each(this.columns, function(i, column) {
if (column.sortable === false || column.visible === false) {
return true;
}
$multiSortName.append('<option value="' + column.field + '">' + column.title + '</option>');
});
$.each(this.options.formatSortOrders(), function(value, order) {
$multiSortOrder.append('<option value="' + value + '">' + order + '</option>');
});
if (sortPriority !== undefined) {
$multiSortName.find('option[value="' + sortPriority.sortName + '"]').attr("selected", true);
$multiSortOrder.find('option[value="' + sortPriority.sortOrder + '"]').attr("selected", true);
}
};
BootstrapTable.prototype.assignSortableArrows = function() {
var that = this,
headers = that.$header.find('th');
for (var i = 0; i < headers.length; i++) {
for (var c = 0; c < that.options.sortPriority.length; c++) {
if ($(headers[i]).data('field') === that.options.sortPriority[c].sortName) {
$(headers[i]).find('.sortable').removeClass('desc asc').addClass(that.options.sortPriority[c].sortOrder);
}
}
}
};
BootstrapTable.prototype.setButtonStates = function() {
var total = this.$sortModal.find('.multi-sort-name:first option').length,
current = this.$sortModal.find('tbody tr').length;
if (current == total) {
this.$sortModal.find('#add').attr('disabled', 'disabled');
}
if (current > 1) {
this.$sortModal.find('#delete').removeAttr('disabled');
}
if (current < total) {
this.$sortModal.find('#add').removeAttr('disabled');
}
if (current == 1) {
this.$sortModal.find('#delete').attr('disabled', 'disabled');
}
};
})(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,67 @@
/**
* @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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,8 @@
.jumpto input {
height: 31px;
width: 50px;
margin-left: 5px;
margin-right: 5px;
text-align: center;
display: inline-block;
}

View File

@@ -0,0 +1,50 @@
/**
* @author Jay <jwang@dizsoft.com>
*/
(function ($) {
'use strict';
var sprintf = $.fn.bootstrapTable.utils.sprintf;
$.extend($.fn.bootstrapTable.defaults, {
showJumpto: false,
exportOptions: {}
});
$.extend($.fn.bootstrapTable.locales, {
formatJumpto: function () {
return 'GO';
}
});
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales);
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initPagination = BootstrapTable.prototype.initPagination;
BootstrapTable.prototype.initPagination = function () {
_initPagination.apply(this, Array.prototype.slice.apply(arguments));
if (this.options.showJumpto) {
var that = this,
$pageGroup = this.$pagination.find('ul.pagination'),
$jumpto = $pageGroup.find('li.jumpto');
if (!$jumpto.length) {
$jumpto = $([
'<li class="jumpto">',
'<input type="text" class="form-control">',
'<button class="btn' +
sprintf(' btn-%s', this.options.buttonsClass) +
sprintf(' btn-%s', this.options.iconSize) +
'" title="' + this.options.formatJumpto() + '" ' +
' type="button">'+this.options.formatJumpto(),
'</button>',
'</li>'].join('')).appendTo($pageGroup);
$jumpto.find('button').click(function () {
that.selectPage(parseInt($jumpto.find('input').val()));
});
}
}
};
})(jQuery);

View File

@@ -0,0 +1,21 @@
(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

@@ -0,0 +1,92 @@
# 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

@@ -0,0 +1,330 @@
/**
* @author doug-the-guy
* @version v1.0.0
*
* Boostrap 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 a
* new server side request is issued
*
**/
(function ($) {
'use strict';
var Utils = $.fn.bootstrapTable.utils;
$.extend($.fn.bootstrapTable.defaults, {
usePipeline: false,
pipelineSize: 1000,
onCachedDataHit: function(data) {
return false;
},
onCachedDataReset: function(data){
return false;
}
});
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'cached-data-hit.bs.table': 'onCachedDataHit',
'cached-data-reset.bs.table': 'onCachedDataReset'
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init,
_initServer = BootstrapTable.prototype.initServer,
_onSearch = BootstrapTable.prototype.onSearch,
_onSort = BootstrapTable.prototype.onSort,
_onPageListChange = BootstrapTable.prototype.onPageListChange;
BootstrapTable.prototype.init = function () {
// needs to be called before initServer()
this.initPipeline();
_init.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.initPipeline = function() {
this.cacheRequestJSON = {};
this.cacheWindows = [];
this.currWindow = 0;
this.resetCache = true;
};
BootstrapTable.prototype.onSearch = function(event) {
/* force a cache reset on search */
if (this.options.usePipeline) {
this.resetCache = true;
}
_onSearch.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.onSort = function(event) {
/* force a cache reset on sort */
if (this.options.usePipeline) {
this.resetCache = true;
}
_onSort.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.onPageListChange = function (event) {
/* rebuild cache window on page size change */
var target = $(event.currentTarget);
var newPageSize = parseInt(target.text());
this.options.pipelineSize = this.calculatePipelineSize(this.options.pipelineSize, newPageSize);
this.resetCache = true;
_onPageListChange.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.calculatePipelineSize = function(pipelineSize, pageSize) {
/* calculate pipeline size by rounding up to the nearest value evenly divisible
* by the pageSize */
if(pageSize == 0) return 0;
return Math.ceil(pipelineSize/pageSize) * pageSize;
};
BootstrapTable.prototype.setCacheWindows = function() {
/* set cache windows based on the total number of rows returned by server side
* request and the pipelineSize */
this.cacheWindows = [];
var numWindows = this.options.totalRows / this.options.pipelineSize;
for(var i = 0; i <= numWindows; i++){
var b = i * this.options.pipelineSize;
this.cacheWindows[i] = {'lower': b, 'upper': b + this.options.pipelineSize - 1};
}
};
BootstrapTable.prototype.setCurrWindow = function(offset) {
/* set the current cache window index, based on where the current offset falls */
this.currWindow = 0;
for(var i = 0; i < this.cacheWindows.length; i++){
if(this.cacheWindows[i].lower <= offset && offset <= this.cacheWindows[i].upper){
this.currWindow = i;
break;
}
}
};
BootstrapTable.prototype.drawFromCache = function(offset, limit) {
/* draw rows from the cache using offset and limit */
var res = $.extend(true, {}, this.cacheRequestJSON);
var drawStart = offset - this.cacheWindows[this.currWindow].lower;
var drawEnd = drawStart + limit;
res.rows = res.rows.slice(drawStart, drawEnd);
return res;
};
BootstrapTable.prototype.initServer = function(silent, query, url){
/* determine if requested data is in cache (on paging) or if
* a new ajax request needs to be issued (sorting, searching, paging
* moving outside of cached data, page size change)
* initial version of this extension will entirely override base initServer
**/
var data = {};
var index = this.header.fields.indexOf(this.options.sortName);
var params = {
searchText: this.searchText,
sortName: this.options.sortName,
sortOrder: this.options.sortOrder
};
var request = null;
if (this.header.sortNames[index]) {
params.sortName = this.header.sortNames[index];
}
if (this.options.pagination && this.options.sidePagination === 'server') {
params.pageSize = this.options.pageSize === this.options.formatAllRows()
? this.options.totalRows : this.options.pageSize
params.pageNumber = this.options.pageNumber
}
if (!(url || this.options.url) && !this.options.ajax) {
return;
}
var useAjax = true;
if (this.options.queryParamsType === 'limit') {
params = {
searchText: params.searchText,
sortName: params.sortName,
sortOrder: params.sortOrder
}
if (this.options.pagination && this.options.sidePagination === 'server') {
params.limit = this.options.pageSize === this.options.formatAllRows() ? this.options.totalRows : this.options.pageSize;
params.offset = (this.options.pageSize === this.options.formatAllRows() ? this.options.totalRows : this.options.pageSize) * (this.options.pageNumber - 1);
if (this.options.usePipeline) {
// if cacheWindows is empty, this is the initial request
if(!this.cacheWindows.length){
useAjax = true;
params.drawOffset = params.offset;
// cache exists: determine if the page request is entirely within the current cached window
} else {
var w = this.cacheWindows[this.currWindow];
// case 1: reset cache but stay within current window (e.g. column sort)
// case 2: move outside of the current window (e.g. search or paging)
// since each cache window is aligned with the current page size
// checking if params.offset is outside the current window is sufficient.
// need to requery for preceding or succeeding cache window
// also handle case
if(this.resetCache || (params.offset < w.lower || params.offset > w.upper)){
useAjax = true;
this.setCurrWindow(params.offset);
// store the relative offset for drawing the page data afterwards
params.drawOffset = params.offset;
// now set params.offset to the lower bound of the new cache window
// the server will return that whole cache window
params.offset = this.cacheWindows[this.currWindow].lower;
// within current cache window
} else {
useAjax = false;
}
}
} else {
if (params.limit === 0) {
delete params.limit;
}
}
}
}
// force an ajax call - this is on search, sort or page size change
if (this.resetCache) {
useAjax = true;
this.resetCache = false;
}
if(this.options.usePipeline && useAjax) {
/* in this scenario limit is used on the server to get the cache window
* and drawLimit is used to get the page data afterwards */
params.drawLimit = params.limit;
params.limit = this.options.pipelineSize;
}
// cached results can be used
if(!useAjax) {
var res = this.drawFromCache(params.offset, params.limit);
this.load(res);
this.trigger('load-success', res);
this.trigger('cached-data-hit', res);
return;
}
// cached results can't be used
// continue base initServer code
if (!($.isEmptyObject(this.filterColumnsPartial))) {
params.filter = JSON.stringify(this.filterColumnsPartial, null);
}
data = Utils.calculateObjectValue(this.options, this.options.queryParams, [params], data);
$.extend(data, query || {});
// false to stop request
if (data === false) {
return;
}
if (!silent) {
this.$tableLoading.show();
}
var self = this;
request = $.extend({}, Utils.calculateObjectValue(null, this.options.ajaxOptions), {
type: this.options.method,
url: url || this.options.url,
data: this.options.contentType === 'application/json' && this.options.method === 'post'
? JSON.stringify(data) : data,
cache: this.options.cache,
contentType: this.options.contentType,
dataType: this.options.dataType,
success: function(res){
res = Utils.calculateObjectValue(self.options, self.options.responseHandler, [res], res);
// cache results if using pipelining
if(self.options.usePipeline){
// store entire request in cache
self.cacheRequestJSON = $.extend(true, {}, res);
// this gets set in load() also but needs to be set before
// setting cacheWindows
self.options.totalRows = res[self.options.totalField];
// if this is a search, potentially less results will be returned
// so cache windows need to be rebuilt. Otherwise it
// will come out the same
self.setCacheWindows();
self.setCurrWindow(params.drawOffset);
// just load data for the page
res = self.drawFromCache(params.drawOffset, params.drawLimit);
self.trigger('cached-data-reset', res);
}
self.load(res);
self.trigger('load-success', res);
if (!silent) self.$tableLoading.hide();
},
error: function(res){
var data = [];
if (self.options.sidePagination === 'server') {
data = {};
data[self.options.totalField] = 0;
data[self.options.dataField] = [];
}
self.load(data);
self.trigger('load-error', res.status, res);
if (!silent) self.$tableLoading.hide();
}
});
if (this.options.ajax) {
Utils.calculateObjectValue(this, this.options.ajax, [request], null);
} else {
if (this._xhr && this._xhr.readyState !== 4) {
this._xhr.abort();
}
this._xhr = $.ajax(request);
}
}
$.fn.bootstrapTable.methods.push();
})(jQuery);

View File

@@ -0,0 +1,18 @@
{
"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

@@ -0,0 +1,149 @@
(function ($) {
'use strict';
var sprintf = $.fn.bootstrapTable.utils.sprintf;
function printPageBuilderDefault(table) {
return '<html><head>' +
'<style type="text/css" media="print">' +
' @page { size: auto; margin: 25px 0 25px 0; }' +
'</style>' +
'<style type="text/css" media="all">' +
'table{border-collapse: collapse; font-size: 12px; }\n' +
'table, th, td {border: 1px solid grey}\n' +
'th, td {text-align: center; vertical-align: middle;}\n' +
'p {font-weight: bold; margin-left:20px }\n' +
'table { width:94%; margin-left:3%; margin-right:3%}\n' +
'div.bs-table-print { text-align:center;}\n' +
'</style></head><title>Print Table</title><body>' +
'<p>Printed on: ' + new Date + ' </p>' +
'<div class="bs-table-print">' + table + "</div></body></html>";
}
$.extend($.fn.bootstrapTable.defaults, {
showPrint: false,
printAsFilteredAndSortedOnUI: true, //boolean, when true - print table as sorted and filtered on UI.
//Please note that if true is set, along with explicit predefined print options for filtering and sorting (printFilter, printSortOrder, printSortColumn)- then they will be applied on data already filtered and sorted by UI controls.
//For printing data as filtered and sorted on UI - do not set these 3 options:printFilter, printSortOrder, printSortColumn
printSortColumn: undefined , //String, set column field name to be sorted by
printSortOrder: 'asc', //String: 'asc' , 'desc' - relevant only if printSortColumn is set
printPageBuilder: function(table){return printPageBuilderDefault(table)} // function, receive html <table> element as string, returns html string for printing. by default delegates to function printPageBuilderDefault(table). used for styling and adding header or footer
});
$.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
printFilter: undefined, //set value to filter by in print page
printIgnore: false, //boolean, set true to ignore this column in the print page
printFormatter:undefined //function(value, row, index), formats the cell value for this column in the printed table. Function behaviour is similar to the 'formatter' column option
});
$.extend($.fn.bootstrapTable.defaults.icons, {
print: 'glyphicon-print icon-share'
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initToolbar = BootstrapTable.prototype.initToolbar;
BootstrapTable.prototype.initToolbar = function () {
this.showToolbar = this.showToolbar || this.options.showPrint;
_initToolbar.apply(this, Array.prototype.slice.apply(arguments));
if (this.options.showPrint) {
var that = this,
$btnGroup = this.$toolbar.find('>.btn-group'),
$print = $btnGroup.find('button.bs-print');
if (!$print.length) {
$print = $([
'<button class="bs-print btn btn-default' + sprintf(' btn-%s"', this.options.iconSize) + ' name="print" title="print" type="button">',
sprintf('<i class="%s %s"></i> ', this.options.iconsPrefix, this.options.icons.print),
'</button>'].join('')).appendTo($btnGroup);
$print.click(function () {
function formatValue(row, i, column ) {
var value = row[column.field];
if (typeof column.printFormatter === 'function') {
return column.printFormatter.apply(column, [value, row, i]);
}
else {
return typeof value === 'undefined' ? "-" : value;
}
}
function buildTable(data, columnsArray) {
var html = ['<table><thead>'];
for (var k = 0; k < columnsArray.length; k++) {
var columns = columnsArray[k];
html.push('<tr>');
for (var h = 0; h < columns.length; h++) {
if (!columns[h].printIgnore) {
html.push(
'<th',
sprintf(' rowspan="%s"', columns[h].rowspan),
sprintf(' colspan="%s"', columns[h].colspan),
sprintf('>%s</th>', columns[h].title)
);
}
}
html.push('</tr>');
}
html.push('</thead><tbody>');
for (var i = 0; i < data.length; i++) {
html.push('<tr>');
for(var l = 0; l < columnsArray.length; l++) {
var columns = columnsArray[l];
for(var j = 0; j < columns.length; j++) {
if (!columns[j].printIgnore && columns[j].field) {
html.push('<td>', formatValue(data[i], i, columns[j]), '</td>');
}
}
}
html.push('</tr>');
}
html.push('</tbody></table>');
return html.join('');
}
function sortRows(data,colName,sortOrder) {
if(!colName){
return data;
}
var reverse = sortOrder != 'asc';
reverse = -((+reverse) || -1);
return data.sort(function (a, b) {
return reverse * (a[colName].localeCompare(b[colName]));
});
}
function filterRow(row,filters) {
for (var index = 0; index < filters.length; ++index) {
if(row[filters[index].colName]!=filters[index].value) {
return false;
}
}
return true;
}
function filterRows(data,filters) {
return data.filter(function (row) {
return filterRow(row,filters)
});
}
function getColumnFilters(columns) {
return !columns || !columns[0] ? [] : columns[0].filter(function (col) {
return col.printFilter;
}).map(function (col) {
return {colName:col.field, value:col.printFilter};
});
}
var doPrint = function (data) {
data=filterRows(data,getColumnFilters(that.options.columns));
data=sortRows(data,that.options.printSortColumn,that.options.printSortOrder);
var table=buildTable(data,that.options.columns);
var newWin = window.open("");
newWin.document.write(that.options.printPageBuilder.call(this, table));
newWin.print();
newWin.close();
};
doPrint(that.options.printAsFilteredAndSortedOnUI? that.getData() : that.options.data.slice(0));
});
}
}
};
})(jQuery);

View File

@@ -0,0 +1,181 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.1.0
*/
!function ($) {
'use strict';
//From MDN site, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
var filterFn = function () {
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun/*, thisArg*/) {
'use strict';
if (this === void 0 || this === null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== 'function') {
throw new TypeError();
}
var res = [];
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i];
// NOTE: Technically this should Object.defineProperty at
// the next index, as push can be affected by
// properties on Object.prototype and Array.prototype.
// But that method's new, and collisions should be
// rare, so use the more-compatible alternative.
if (fun.call(thisArg, val, i, t)) {
res.push(val);
}
}
}
return res;
};
}
};
$.extend($.fn.bootstrapTable.defaults, {
reorderableColumns: false,
maxMovingRows: 10,
onReorderColumn: function (headerFields) {
return false;
},
dragaccept: null
});
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'reorder-column.bs.table': 'onReorderColumn'
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initHeader = BootstrapTable.prototype.initHeader,
_toggleColumn = BootstrapTable.prototype.toggleColumn,
_toggleView = BootstrapTable.prototype.toggleView,
_resetView = BootstrapTable.prototype.resetView;
BootstrapTable.prototype.initHeader = function () {
_initHeader.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.reorderableColumns) {
return;
}
this.makeRowsReorderable();
};
BootstrapTable.prototype.toggleColumn = function () {
_toggleColumn.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.reorderableColumns) {
return;
}
this.makeRowsReorderable();
};
BootstrapTable.prototype.toggleView = function () {
_toggleView.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.reorderableColumns) {
return;
}
if (this.options.cardView) {
return;
}
this.makeRowsReorderable();
};
BootstrapTable.prototype.resetView = function () {
_resetView.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.reorderableColumns) {
return;
}
this.makeRowsReorderable();
};
BootstrapTable.prototype.makeRowsReorderable = function () {
var that = this;
try {
$(this.$el).dragtable('destroy');
} catch (e) {}
$(this.$el).dragtable({
maxMovingRows: that.options.maxMovingRows,
dragaccept: that.options.dragaccept,
clickDelay:200,
beforeStop: function() {
var ths = [],
formatters = [],
columns = [],
columnsHidden = [],
columnIndex = -1,
optionsColumns = [];
that.$header.find('th').each(function (i) {
ths.push($(this).data('field'));
formatters.push($(this).data('formatter'));
});
//Exist columns not shown
if (ths.length < that.columns.length) {
columnsHidden = $.grep(that.columns, function (column) {
return !column.visible;
});
for (var i = 0; i < columnsHidden.length; i++) {
ths.push(columnsHidden[i].field);
formatters.push(columnsHidden[i].formatter);
}
}
for (var i = 0; i < this.length; i++ ) {
columnIndex = that.fieldsColumnsIndex[ths[i]];
if (columnIndex !== -1) {
that.columns[columnIndex].fieldIndex = i;
columns.push(that.columns[columnIndex]);
that.columns.splice(columnIndex, 1);
}
}
that.columns = that.columns.concat(columns);
filterFn(); //Support <IE9
$.each(that.columns, function(i, column) {
var found = false,
field = column.field;
that.options.columns[0].filter(function(item) {
if(!found && item["field"] == field) {
optionsColumns.push(item);
found = true;
return false;
} else
return true;
})
});
that.options.columns[0] = optionsColumns;
that.header.fields = ths;
that.header.formatters = formatters;
that.initHeader();
that.initToolbar();
that.initBody();
that.resetView();
that.trigger('reorder-column', ths);
}
});
};
}(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,14 @@
.reorder_rows_onDragClass td {
background-color: #eee;
-webkit-box-shadow: 11px 5px 12px 2px #333, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset;
-webkit-box-shadow: 6px 3px 5px #555, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset;
-moz-box-shadow: 6px 4px 5px 1px #555, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset;
-box-shadow: 6px 4px 5px 1px #555, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset;
}
.reorder_rows_onDragClass td:last-child {
-webkit-box-shadow: 8px 7px 12px 0 #333, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset;
-webkit-box-shadow: 1px 8px 6px -4px #555, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset;
-moz-box-shadow: 0 9px 4px -4px #555, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset, -1px 0 0 #ccc inset;
-box-shadow: 0 9px 4px -4px #555, 0 1px 0 #ccc inset, 0 -1px 0 #ccc inset, -1px 0 0 #ccc inset;
}

View File

@@ -0,0 +1,118 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.0.1
*/
(function ($) {
'use strict';
var isSearch = false;
var rowAttr = function (row, index) {
return {
id: 'customId_' + index
};
};
$.extend($.fn.bootstrapTable.defaults, {
reorderableRows: false,
onDragStyle: null,
onDropStyle: null,
onDragClass: "reorder_rows_onDragClass",
dragHandle: null,
useRowAttrFunc: false,
onReorderRowsDrag: function (table, row) {
return false;
},
onReorderRowsDrop: function (table, row) {
return false;
},
onReorderRow: function (newData) {
return false;
}
});
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'reorder-row.bs.table': 'onReorderRow'
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init,
_initSearch = BootstrapTable.prototype.initSearch;
BootstrapTable.prototype.init = function () {
if (!this.options.reorderableRows) {
_init.apply(this, Array.prototype.slice.apply(arguments));
return;
}
var that = this;
if (this.options.useRowAttrFunc) {
this.options.rowAttributes = rowAttr;
}
var onPostBody = this.options.onPostBody;
this.options.onPostBody = function () {
setTimeout(function () {
that.makeRowsReorderable();
onPostBody.apply();
}, 1);
};
_init.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.initSearch = function () {
_initSearch.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.reorderableRows) {
return;
}
//Known issue after search if you reorder the rows the data is not display properly
//isSearch = true;
};
BootstrapTable.prototype.makeRowsReorderable = function () {
if (this.options.cardView) {
return;
}
var that = this;
this.$el.tableDnD({
onDragStyle: that.options.onDragStyle,
onDropStyle: that.options.onDropStyle,
onDragClass: that.options.onDragClass,
onDrop: that.onDrop,
onDragStart: that.options.onReorderRowsDrag,
dragHandle: that.options.dragHandle
});
};
BootstrapTable.prototype.onDrop = function (table, droppedRow) {
var tableBs = $(table),
tableBsData = tableBs.data('bootstrap.table'),
tableBsOptions = tableBs.data('bootstrap.table').options,
row = null,
newData = [];
for (var i = 0; i < table.tBodies[0].rows.length; i++) {
row = $(table.tBodies[0].rows[i]);
newData.push(tableBsOptions.data[row.data('index')]);
row.data('index', i).attr('data-index', i);
}
tableBsOptions.data = tableBsOptions.data.slice(0, tableBsData.pageFrom - 1)
.concat(newData)
.concat(tableBsOptions.data.slice(tableBsData.pageTo));
//Call the user defined function
tableBsOptions.onReorderRowsDrop.apply(table, [table, droppedRow]);
//Call the event reorder-row
tableBsData.trigger('reorder-row', newData);
};
})(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,72 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v2.0.0
*/
(function($) {
"use strict";
var initResizable = function(that) {
if (that.options.resizable && !that.options.cardView && !isInit(that)) {
that.$el.resizableColumns();
}
};
var reInitResizable = function(that) {
destroy(that);
initResizable(that);
};
var destroy = function(that) {
if (isInit(that)) {
that.$el.data("resizableColumns").destroy();
}
};
var isInit = function(that) {
return that.$el.data("resizableColumns") !== undefined;
};
$.extend($.fn.bootstrapTable.defaults, {
resizable: false
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initBody = BootstrapTable.prototype.initBody,
_toggleView = BootstrapTable.prototype.toggleView,
_resetView = BootstrapTable.prototype.resetView;
BootstrapTable.prototype.initBody = function() {
var that = this;
_initBody.apply(this, Array.prototype.slice.apply(arguments));
that.$el
.off("column-switch.bs.table, page-change.bs.table")
.on("column-switch.bs.table, page-change.bs.table", function() {
reInitResizable(that);
});
};
BootstrapTable.prototype.toggleView = function() {
_toggleView.apply(this, Array.prototype.slice.apply(arguments));
if (this.options.resizable && this.options.cardView) {
//Destroy the plugin
destroy(this);
}
};
BootstrapTable.prototype.resetView = function() {
var that = this;
_resetView.apply(this, Array.prototype.slice.apply(arguments));
if (this.options.resizable) {
// because in fitHeader function, we use setTimeout(func, 100);
setTimeout(function() {
initResizable(that);
}, 100);
}
};
})(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,332 @@
/**
* @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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,22 @@
/**
* @author vincent loh <vincent.ml@gmail.com>
* @update zhixin wen <wenzhixin2010@gmail.com>
*/
.fix-sticky {
position: fixed !important;
overflow: hidden;
z-index: 100;
}
.fix-sticky table thead {
background: #fff;
}
.fix-sticky table thead.thead-light {
background: #e9ecef;
}
.fix-sticky table thead.thead-light {
background: #212529;
}

View File

@@ -0,0 +1,76 @@
/**
* @author vincent loh <vincent.ml@gmail.com>
* @update J Manuel Corona <jmcg92@gmail.com>
* @update zhixin wen <wenzhixin2010@gmail.com>
*/
($ => {
const Utils = $.fn.bootstrapTable.utils
$.extend($.fn.bootstrapTable.defaults, {
stickyHeader: false,
stickyHeaderOffsetY: 0
})
const hiddenClass = Utils.bootstrapVersion === 4 ? 'd-none' : 'hidden'
$.BootstrapTable = class extends $.BootstrapTable {
initHeader (...args) {
super.initHeader(...args)
if (!this.options.stickyHeader) {
return
}
this.$el.before('<div class="sticky-header-container"></div>')
this.$el.before('<div class="sticky_anchor_begin"></div>')
this.$el.after('<div class="sticky_anchor_end"></div>')
this.$header.addClass('sticky-header')
// clone header just once, to be used as sticky header
// deep clone header, using source header affects tbody>td width
this.$stickyContainer = this.$tableBody.find('.sticky-header-container')
this.$stickyBegin = this.$tableBody.find('.sticky_anchor_begin')
this.$stickyEnd = this.$tableBody.find('.sticky_anchor_end')
this.$stickyHeader = this.$header.clone(true, true)
// render sticky on window scroll or resize
$(window).on('resize.sticky-header-table', () => this.renderStickyHeader())
$(window).on('scroll.sticky-header-table', () => this.renderStickyHeader())
this.$tableBody.off('scroll').on('scroll', () => this.matchPositionX())
}
renderStickyHeader () {
const top = $(window).scrollTop()
// top anchor scroll position, minus header height
const start = this.$stickyBegin.offset().top - this.options.stickyHeaderOffsetY
// bottom anchor scroll position, minus header height, minus sticky height
const end = this.$stickyEnd.offset().top - this.options.stickyHeaderOffsetY - this.$header.height()
// show sticky when top anchor touches header, and when bottom anchor not exceeded
if (top > start && top <= end) {
// ensure clone and source column widths are the same
this.$stickyHeader.find('tr:eq(0)').find('th').each((index, el) => {
$(el).css('min-width', this.$header.find('tr:eq(0)').find('th').eq(index).css('width'))
})
// match bootstrap table style
this.$stickyContainer.removeClass(hiddenClass).addClass('fix-sticky fixed-table-container')
// stick it in position
this.$stickyContainer.css('top', `${this.options.stickyHeaderOffsetY}px`)
// create scrollable container for header
this.$stickyTable = $('<table/>')
this.$stickyTable.addClass(this.options.classes)
// append cloned header to dom
this.$stickyContainer.html(this.$stickyTable.append(this.$stickyHeader))
// match clone and source header positions when left-right scroll
this.matchPositionX()
} else {
this.$stickyContainer.removeClass('fix-sticky').addClass(hiddenClass)
}
}
matchPositionX () {
this.$stickyContainer.scrollLeft(this.$tableBody.scrollLeft())
}
}
})(jQuery)

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,228 @@
/**
* @author: aperez <aperez@datadec.es>
* @version: v2.0.0
*
* @update Dennis Hernández <http://djhvscf.github.io/Blog>
* @update zhixin wen <wenzhixin2010@gmail.com>
*/
($ => {
const Utils = $.fn.bootstrapTable.utils
const bootstrap = {
3: {
icons: {
advancedSearchIcon: 'glyphicon-chevron-down'
},
html: {
modalHeader: `
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">%s</h4>
</div>
`
}
},
4: {
icons: {
advancedSearchIcon: 'fa-chevron-down'
},
html: {
modalHeader: `
<div class="modal-header">
<h4 class="modal-title">%s</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
`
}
}
}[Utils.bootstrapVersion]
$.extend($.fn.bootstrapTable.defaults, {
advancedSearch: false,
idForm: 'advancedSearch',
actionForm: '',
idTable: undefined,
onColumnAdvancedSearch (field, text) {
return false
}
})
$.extend($.fn.bootstrapTable.defaults.icons, {
advancedSearchIcon: bootstrap.icons.advancedSearchIcon
})
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'column-advanced-search.bs.table': 'onColumnAdvancedSearch'
})
$.extend($.fn.bootstrapTable.locales, {
formatAdvancedSearch () {
return 'Advanced search'
},
formatAdvancedCloseButton () {
return 'Close'
}
})
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales)
$.BootstrapTable = class extends $.BootstrapTable {
initToolbar () {
const o = this.options
this.showToolbar = this.showToolbar ||
(o.search &&
o.advancedSearch &&
o.idTable)
super.initToolbar()
if (!o.search || !o.advancedSearch || !o.idTable) {
return
}
this.$toolbar.find('>.btn-group').append(`
<button class="btn btn-default${Utils.sprintf(' btn-%s', o.buttonsClass)}${Utils.sprintf(' btn-%s', o.iconSize)}"
type="button"
name="advancedSearch"
aria-label="advanced search"
title="${o.formatAdvancedSearch()}">
<i class="${o.iconsPrefix} ${o.icons.advancedSearchIcon}"></i>
</button>
`)
this.$toolbar.find('button[name="advancedSearch"]').off('click').on('click', () => this.showAvdSearch())
}
showAvdSearch () {
const o = this.options
if (!$(`#avdSearchModal_${o.idTable}`).hasClass('modal')) {
$('body').append(`
<div id="avdSearchModal_${o.idTable}" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xs">
<div class="modal-content">
${Utils.sprintf(bootstrap.html.modalHeader, o.formatAdvancedSearch())}
<div class="modal-body modal-body-custom">
<div class="container-fluid" id="avdSearchModalContent_${o.idTable}"
style="padding-right: 0px; padding-left: 0px;" >
</div>
</div>
<div class="modal-footer">
<button type="button" id="btnCloseAvd_${o.idTable}" class="btn btn-${o.buttonsClass}">
${o.formatAdvancedCloseButton()}
</button>
</div>
</div>
</div>
</div>
`)
let timeoutId = 0
$(`#avdSearchModalContent_${o.idTable}`).append(this.createFormAvd().join(''))
$(`#${o.idForm}`).off('keyup blur', 'input').on('keyup blur', 'input', e => {
if (o.sidePagination === 'server') {
this.onColumnAdvancedSearch(e)
} else {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
this.onColumnAdvancedSearch(e)
}, o.searchTimeOut)
}
})
$(`#btnCloseAvd_${o.idTable}`).click(() => {
$(`#avdSearchModal_${o.idTable}`).modal('hide')
if (o.sidePagination === 'server') {
this.options.pageNumber = 1
this.updatePagination()
this.trigger('column-advanced-search', this.filterColumnsPartial)
}
})
$(`#avdSearchModal_${o.idTable}`).modal()
} else {
$(`#avdSearchModal_${o.idTable}`).modal()
}
}
createFormAvd () {
const o = this.options
const html = [`<form class="form-horizontal" id="${o.idForm}" action="${o.actionForm}">`]
for (const column of this.columns) {
if (!column.checkbox && column.visible && column.searchable) {
html.push(`
<div class="form-group row">
<label class="col-sm-4 control-label">${column.title}</label>
<div class="col-sm-6">
<input type="text" class="form-control input-md" name="${column.field}" placeholder="${column.title}" id="${column.field}">
</div>
</div>
`)
}
}
html.push('</form>')
return html
}
initSearch () {
super.initSearch()
if (!this.options.advancedSearch || this.options.sidePagination === 'server') {
return
}
const fp = $.isEmptyObject(this.filterColumnsPartial) ? null : this.filterColumnsPartial
this.data = fp ? $.grep(this.data, (item, i) => {
for (const [key, v] of Object.entries(fp)) {
const fval = v.toLowerCase()
let value = item[key]
const index = this.header.fields.indexOf(key)
value = Utils.calculateObjectValue(this.header,
this.header.formatters[index], [value, item, i], value)
if (
!(index !== -1 &&
(typeof value === 'string' || typeof value === 'number') &&
(`${value}`).toLowerCase().includes(fval))
) {
return false
}
}
return true
}) : this.data
}
onColumnAdvancedSearch (e) {
const text = $.trim($(e.currentTarget).val())
const $field = $(e.currentTarget)[0].id
if ($.isEmptyObject(this.filterColumnsPartial)) {
this.filterColumnsPartial = {}
}
if (text) {
this.filterColumnsPartial[$field] = text
} else {
delete this.filterColumnsPartial[$field]
}
if (this.options.sidePagination !== 'server') {
this.options.pageNumber = 1
this.onSearch(e)
this.updatePagination()
this.trigger('column-advanced-search', $field, text)
}
}
}
})(jQuery)

View File

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1 @@
.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

@@ -0,0 +1,130 @@
/**
* @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

@@ -0,0 +1,43 @@
.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

@@ -0,0 +1,17 @@
{
"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.

After

Width:  |  Height:  |  Size: 346 B

View File

@@ -0,0 +1,111 @@
/**
* @author: YL
* @version: v1.0.0
*/
!function ($) {
'use strict';
$.extend($.fn.bootstrapTable.defaults, {
treeShowField: null,
idField: 'id',
parentIdField: 'pid',
rootParentId: null,
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;
},
onCheckRoot: function (row, data) {
var that = this;
return that.options.rootParentId === row[that.options.parentIdField] ||
!row[that.options.parentIdField];
}
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init,
_initRow = BootstrapTable.prototype.initRow,
_initHeader = BootstrapTable.prototype.initHeader,
_rowStyle = null;
BootstrapTable.prototype.init = function () {
_rowStyle = this.options.rowStyle;
_init.apply(this, Array.prototype.slice.apply(arguments));
};
// td
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;
return false;
}
});
}
};
var initTr = 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]));
// init sub node
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;
// jquery.treegrid.js
that.options.rowStyle = function (item, idx) {
var res = _rowStyle.apply(that, Array.prototype.slice.apply(arguments));
var id = item[that.options.idField] ? item[that.options.idField] : 0;
var pid = item[that.options.parentIdField] ? item[that.options.parentIdField] : 0;
res.classes = [
res.classes || '',
'treegrid-' + id,
'treegrid-parent-' + pid
].join(' ');
return res;
};
initTr.apply(that, [node, $.inArray(node, data), data, parentDom]);
}
};
// tr
BootstrapTable.prototype.initRow = function (item, idx, data, parentDom) {
var that = this;
if (that.treeEnable) {
// init root node
if (that.options.onCheckRoot.apply(that, [item, data])) {
if (item._level === undefined) {
item._level = 0;
}
// jquery.treegrid.js
that.options.rowStyle = function (item, idx) {
var res = _rowStyle.apply(that, Array.prototype.slice.apply(arguments));
var x = item[that.options.idField] ? item[that.options.idField] : 0;
res.classes = [
res.classes || '',
'treegrid-' + x
].join(' ');
return res;
};
initTr.apply(that, [item, idx, data, parentDom]);
return true;
}
return false;
}
return _initRow.apply(that, Array.prototype.slice.apply(arguments));
};
}(jQuery);

View File

@@ -0,0 +1,17 @@
{
"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,13 @@
@charset "UTF-8";
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v2.1.1
*/
.no-filter-control {
height: 34px;
}
.filter-control {
margin: 0 2px 2px 2px;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
/* Color Theme: "Darker" by Radek Hladik */
.navbar-nav > li {
border-color: rgb(179, 179, 179);
}
.navbar-nav > li > a {
color:#0b2a62 !important;
}
.navbar-nav > li > a:hover {
color:#202020 !important;
}
.navbar-nav > .open > a {
color:#202020 !important;
}
.navbar {
background-color: rgb(189, 189, 189);
}
.table-condensed > tbody > tr > td {
border-top: 1px solid #062152 !important ;
}
.table-striped > tbody > tr > td {
border-top: 1px solid #92b3f1 ;
}
.table-bordered, .table-bordered > tbody > tr > td {
border: 1px solid rgb(182,182,182);
}
.table-bordered > thead > tr > th {
border: 1px solid rgb(182, 182, 182);
background-color: rgb(235, 235, 235);
}
h3 {
color:#06255d;
}

View File

@@ -0,0 +1 @@
/* Color Theme: "Default" */

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