├── .coveragerc
├── .gitignore
├── .pre-commit-config.yaml
├── .travis.yml
├── Dockerfile
├── Makefile
├── Pipfile
├── Pipfile.lock
├── README.md
├── carrot_box
├── __init__.py
├── asgi.py
├── hr
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── backends.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20211217_0556.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── userparser.py
│ └── views.py
├── param
│ ├── __init__.py
│ ├── admin.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_alter_param_id.py
│ │ └── __init__.py
│ └── models.py
├── settings
│ ├── __init__.py
│ ├── base.py
│ └── dev.py
├── templates
│ ├── base.html
│ ├── base_ext.html
│ ├── base_form.html
│ └── base_formset.html
├── tests.py
├── urls.py
├── wfapp
│ ├── __init__.py
│ ├── leave
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ ├── 0002_alter_leave_id.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── templates
│ │ │ └── leave
│ │ │ │ ├── detail.html
│ │ │ │ ├── form.html
│ │ │ │ ├── inc_detail_info.html
│ │ │ │ ├── list.html
│ │ │ │ └── print.html
│ │ ├── tests.py
│ │ ├── views.py
│ │ ├── wf_views.py
│ │ └── wfdata.py
│ └── purchase
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── wfdata.py
├── wfdata.py
└── wsgi.py
├── manage.py
├── package.json
├── screenshots
├── detail.png
├── flowchart.png
└── main.png
├── setup.cfg
├── tox.ini
├── wfgen.py
└── yarn.lock
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | branch = True
3 | source = carrot_box
4 | omit =
5 | */tests*
6 | */migrations/*
7 |
8 | [report]
9 | show_missing = True
10 | skip_covered = True
11 | omit =
12 | */tests*
13 | */migrations/*
14 |
15 | [html]
16 | directory = coverage_html
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite3
2 | node_modules/
3 | vendor/
4 | collectedstatic/
5 | bower_components/
6 | coverage_html/
7 | *.swp
8 |
9 | # Byte-compiled / optimized / DLL files
10 | __pycache__/
11 | *.py[cod]
12 | *$py.class
13 |
14 | # C extensions
15 | *.so
16 |
17 | # Distribution / packaging
18 | .Python
19 | env/
20 | build/
21 | develop-eggs/
22 | dist/
23 | downloads/
24 | eggs/
25 | .eggs/
26 | lib/
27 | lib64/
28 | parts/
29 | sdist/
30 | var/
31 | wheels/
32 | *.egg-info/
33 | .installed.cfg
34 | *.egg
35 |
36 | # PyInstaller
37 | # Usually these files are written by a python script from a template
38 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
39 | *.manifest
40 | *.spec
41 |
42 | # Installer logs
43 | pip-log.txt
44 | pip-delete-this-directory.txt
45 |
46 | # Unit test / coverage reports
47 | htmlcov/
48 | .tox/
49 | .coverage
50 | .coverage.*
51 | .cache
52 | nosetests.xml
53 | coverage.xml
54 | *,cover
55 | .hypothesis/
56 |
57 | # Translations
58 | *.mo
59 | *.pot
60 |
61 | # Django stuff:
62 | *.log
63 | local_settings.py
64 |
65 | # Flask stuff:
66 | instance/
67 | .webassets-cache
68 |
69 | # Scrapy stuff:
70 | .scrapy
71 |
72 | # Sphinx documentation
73 | docs/_build/
74 |
75 | # PyBuilder
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # pyenv
82 | .python-version
83 |
84 | # celery beat schedule file
85 | celerybeat-schedule
86 |
87 | # SageMath parsed files
88 | *.sage.py
89 |
90 | # dotenv
91 | .env
92 |
93 | # virtualenv
94 | .venv
95 | venv/
96 | ENV/
97 |
98 | # Spyder project settings
99 | .spyderproject
100 |
101 | # Rope project settings
102 | .ropeproject
103 |
104 | # idea
105 | .idea/
106 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: git://github.com/pre-commit/pre-commit-hooks
3 | rev: v1.4.0
4 | hooks:
5 | - id: check-case-conflict
6 | - id: check-merge-conflict
7 | - id: check-symlinks
8 | - id: check-xml
9 | - id: check-yaml
10 | - id: detect-private-key
11 | - id: trailing-whitespace
12 | - id: debug-statements
13 | - id: flake8
14 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | dist: bionic
3 |
4 | cache: pip
5 |
6 | install:
7 | - pip install --upgrade pip setuptools tox virtualenv coveralls
8 |
9 | script:
10 | - tox
11 |
12 | notifications:
13 | email: false
14 |
15 | matrix:
16 | include:
17 | # Linting
18 | - python: 3.7
19 | env: TOXENV=flake8
20 | - python: 3.7
21 | env: TOXENV=isort
22 |
23 | # Tests
24 | - python: 3.6
25 | env: TOXENV=py36-django2x
26 | - python: 3.7
27 | env: TOXENV=py37-django2x
28 |
29 | - python: 3.6
30 | env: TOXENV=py36-django30
31 | - python: 3.7
32 | env: TOXENV=py37-django30
33 | - python: 3.8
34 | env: TOXENV=py38-django30
35 |
36 | # Future (Should be in `allow_failures`)
37 | - python: 3.8
38 | env: TOXENV=py38-django_trunk
39 | allow_failures:
40 | - env: TOXENV=py38-django_trunk
41 |
42 | after_success: coveralls
43 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8
2 | MAINTAINER vicalloy "https://github.com/vicalloy"
3 |
4 | RUN apt-get update && apt-get install -y \
5 | npm \
6 | pkg-config \
7 | --no-install-recommends && \
8 | rm -rf /var/lib/apt/lists/* && \
9 | npm install -g yarn
10 |
11 | RUN pip install --upgrade pip setuptools pipenv
12 |
13 | RUN mkdir /app
14 | WORKDIR /app
15 |
16 | COPY ./ ./
17 | RUN pipenv install -d --skip-lock --system
18 | RUN make init
19 |
20 | EXPOSE 9000
21 | CMD ["make", "run"]
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | run:
2 | python manage.py runserver 0.0.0.0:9000
3 |
4 | test:
5 | coverage run manage.py test carrot_box
6 | coverage html
7 |
8 | init-pyenv:
9 | pip install pipenv --upgrade
10 | pipenv --python 3
11 | pipenv install -d --skip-lock
12 | pipenv shell
13 |
14 | init:
15 | yarn install
16 | python manage.py migrate
17 | python manage.py collectstatic --no-input
18 | python manage.py callfunc lbworkflow.wfdata.load_data
19 | python manage.py callfunc carrot_box.wfdata.load_data
20 | python manage.py callfunc carrot_box.wfapp.leave.wfdata.load_data
21 | python wfgen.py
22 |
23 | load_data:
24 | python manage.py callfunc lbworkflow.wfdata.load_data
25 |
26 | load_sample_data:
27 | python manage.py callfunc lbworkflow.wfdata.load_data
28 | python manage.py callfunc carrot_box.wfdata.load_data
29 | python manage.py callfunc carrot_box.wfapp.leave.wfdata.load_data
30 |
31 | isort:
32 | isort --recursive carrot_box
33 |
34 | wfgen:
35 | python wfgen.py
36 |
37 | wfgen_clean:
38 | python wfgen.py clean
39 |
40 |
41 | build_docker_image:
42 | docker build -t carrot-box:latest .
43 |
44 | create_docker_container:
45 | docker run -d -p 9000:9000 --name carrot-box carrot-box:latest
46 |
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | name = "pypi"
3 | url = "https://pypi.org/simple"
4 | # url = "https://mirrors.aliyun.com/pypi/simple/"
5 | verify_ssl = true
6 |
7 | [packages]
8 | django-lb-workflow = {version=">=1.0.3", extras=["options"]}
9 |
10 | [dev-packages]
11 | coverage = "*"
12 | flake8 = "==3.7.9"
13 | isort = "*"
14 | pre-commit = "*"
15 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "d921a3703fb6419aaf63ad25dec7d475179f15bede11db30c1fbd16b80cba081"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {},
8 | "sources": [
9 | {
10 | "name": "pypi",
11 | "url": "https://pypi.org/simple",
12 | "verify_ssl": true
13 | }
14 | ]
15 | },
16 | "default": {
17 | "asgiref": {
18 | "hashes": [
19 | "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0",
20 | "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"
21 | ],
22 | "markers": "python_version >= '3.7'",
23 | "version": "==3.5.0"
24 | },
25 | "django": {
26 | "hashes": [
27 | "sha256:9772e6935703e59e993960832d66a614cf0233a1c5123bc6224ecc6ad69e41e2",
28 | "sha256:9b06c289f9ba3a8abea16c9c9505f25107809fb933676f6c891ded270039d965"
29 | ],
30 | "index": "pypi",
31 | "version": "==3.2.12"
32 | },
33 | "django-appconf": {
34 | "hashes": [
35 | "sha256:ae9f864ee1958c815a965ed63b3fba4874eec13de10236ba063a788f9a17389d",
36 | "sha256:be3db0be6c81fa84742000b89a81c016d70ae66a7ccb620cdef592b1f1a6aaa4"
37 | ],
38 | "markers": "python_version >= '3.6'",
39 | "version": "==1.0.5"
40 | },
41 | "django-bootstrap-pagination": {
42 | "hashes": [
43 | "sha256:47e742679cf109e12f10ae09d5263433f94440818cf7b023e90a3f5252849639",
44 | "sha256:69d826d92217325611cb86e49944d8261e3c92eaa4deafea5a605d79fd363883"
45 | ],
46 | "version": "==1.7.1"
47 | },
48 | "django-compressor": {
49 | "hashes": [
50 | "sha256:89f7ba86777b30672c2f9c7557bf2aff87c5890903c73b1fa3ae38acd143e855",
51 | "sha256:c4a87bf65f9a534cfaf1c321a000a229c24e50c6d62ba6ab089482db42e819d9"
52 | ],
53 | "version": "==3.1"
54 | },
55 | "django-crispy-forms": {
56 | "hashes": [
57 | "sha256:35887b8851a931374dd697207a8f56c57a9c5cb9dbf0b9fa54314da5666cea5b",
58 | "sha256:bc4d2037f6de602d39c0bc452ac3029d1f5d65e88458872cc4dbc01c3a400604"
59 | ],
60 | "version": "==1.14.0"
61 | },
62 | "django-impersonate": {
63 | "hashes": [
64 | "sha256:282003957577c7143fe31e5861f8fffdf6fe0c25557aedb28fcf8b11474eaa23"
65 | ],
66 | "version": "==1.7.3"
67 | },
68 | "django-lb-adminlte": {
69 | "hashes": [
70 | "sha256:7de9061b275cb9c6c891980c9039bb2fecfabaa8b160acfe3292f277fe0b6f3f"
71 | ],
72 | "version": "==1.2.1"
73 | },
74 | "django-lb-workflow": {
75 | "extras": [
76 | "options"
77 | ],
78 | "hashes": [
79 | "sha256:653446a6efe4241cb6e23e9c49369eed492f74d941381c67fa86bd367ffd7a6a"
80 | ],
81 | "index": "pypi",
82 | "version": "==1.0.4"
83 | },
84 | "django-lbattachment": {
85 | "hashes": [
86 | "sha256:ffd0f3ea5e21e4a0ee284d8c1a8fd8f24ac1ea8e43227aa65567732b7001805c"
87 | ],
88 | "version": "==1.1.0"
89 | },
90 | "django-lbutils": {
91 | "hashes": [
92 | "sha256:990d8d45751443bfc9228b03b4cdd27d59719c902ca4022729a21d44d55579f0"
93 | ],
94 | "version": "==1.1.0"
95 | },
96 | "django-select2": {
97 | "hashes": [
98 | "sha256:f3387ba43db4a137b5f17d30b3465dd328d01fb4b5d08a017ba0b76a7c7bbbbf",
99 | "sha256:fd78095b0eef02f990a56f887ada3d6bc3d0ffa858a73ec29498ec86988dc90d"
100 | ],
101 | "version": "==7.10.0"
102 | },
103 | "django-stronghold": {
104 | "hashes": [
105 | "sha256:4127d5f9c11f6582a1c03e7758256b1fe5c872f64f212980e5ad5c67f5eeaa3d"
106 | ],
107 | "version": "==0.4.0"
108 | },
109 | "jinja2": {
110 | "hashes": [
111 | "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8",
112 | "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"
113 | ],
114 | "markers": "python_version >= '3.6'",
115 | "version": "==3.0.3"
116 | },
117 | "jsonfield": {
118 | "hashes": [
119 | "sha256:7e4e84597de21eeaeeaaa7cc5da08c61c48a9b64d0c446b2d71255d01812887a",
120 | "sha256:df857811587f252b97bafba42e02805e70a398a7a47870bc6358a0308dd689ed"
121 | ],
122 | "markers": "python_version >= '3.6'",
123 | "version": "==3.1.0"
124 | },
125 | "markupsafe": {
126 | "hashes": [
127 | "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
128 | "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64",
129 | "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b",
130 | "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194",
131 | "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567",
132 | "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff",
133 | "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724",
134 | "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74",
135 | "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646",
136 | "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35",
137 | "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6",
138 | "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a",
139 | "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6",
140 | "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad",
141 | "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26",
142 | "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38",
143 | "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac",
144 | "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7",
145 | "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6",
146 | "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047",
147 | "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75",
148 | "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f",
149 | "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b",
150 | "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135",
151 | "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8",
152 | "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a",
153 | "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a",
154 | "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1",
155 | "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9",
156 | "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864",
157 | "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914",
158 | "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee",
159 | "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f",
160 | "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18",
161 | "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8",
162 | "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2",
163 | "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d",
164 | "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b",
165 | "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b",
166 | "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86",
167 | "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6",
168 | "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f",
169 | "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb",
170 | "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833",
171 | "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28",
172 | "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e",
173 | "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415",
174 | "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902",
175 | "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f",
176 | "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d",
177 | "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9",
178 | "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d",
179 | "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145",
180 | "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066",
181 | "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c",
182 | "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1",
183 | "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a",
184 | "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207",
185 | "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f",
186 | "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53",
187 | "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd",
188 | "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134",
189 | "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85",
190 | "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9",
191 | "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5",
192 | "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94",
193 | "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509",
194 | "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
195 | "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
196 | ],
197 | "markers": "python_version >= '3.6'",
198 | "version": "==2.0.1"
199 | },
200 | "pytz": {
201 | "hashes": [
202 | "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c",
203 | "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"
204 | ],
205 | "version": "==2021.3"
206 | },
207 | "rcssmin": {
208 | "hashes": [
209 | "sha256:0a6aae7e119509445bf7aa6da6ca0f285cc198273c20f470ad999ff83bbadcf9",
210 | "sha256:1512223b6a687bb747e4e531187bd49a56ed71287e7ead9529cbaa1ca4718a0a",
211 | "sha256:1d7c2719d014e4e4df4e33b75ae8067c7e246cf470eaec8585e06e2efac7586c",
212 | "sha256:2211a5c91ea14a5937b57904c9121f8bfef20987825e55368143da7d25446e3b",
213 | "sha256:27fc400627fd3d328b7fe95af2a01f5d0af6b5af39731af5d071826a1f08e362",
214 | "sha256:30f5522285065cae0164d20068377d84b5d10b414156115f8729b034d0ea5e8b",
215 | "sha256:32ccaebbbd4d56eab08cf26aed36f5d33389b9d1d3ca1fecf53eb6ab77760ddf",
216 | "sha256:352dd3a78eb914bb1cb269ac2b66b3154f2490a52ab605558c681de3fb5194d2",
217 | "sha256:37f1242e34ca273ed2c26cf778854e18dd11b31c6bfca60e23fce146c84667c1",
218 | "sha256:49807735f26f59404194f1e6f93254b6d5b6f7748c2a954f4470a86a40ff4c13",
219 | "sha256:506e33ab4c47051f7deae35b6d8dbb4a5c025f016e90a830929a1ecc7daa1682",
220 | "sha256:6158d0d86cd611c5304d738dc3d6cfeb23864dd78ad0d83a633f443696ac5d77",
221 | "sha256:7085d1b51dd2556f3aae03947380f6e9e1da29fb1eeadfa6766b7f105c54c9ff",
222 | "sha256:7c44002b79f3656348196005b9522ec5e04f182b466f66d72b16be0bd03c13d8",
223 | "sha256:7da63fee37edf204bbd86785edb4d7491642adbfd1d36fd230b7ccbbd8db1a6f",
224 | "sha256:8b659a88850e772c84cfac4520ec223de6807875e173d8ef3248ab7f90876066",
225 | "sha256:c28b9eb20982b45ebe6adef8bd2547e5ed314dafddfff4eba806b0f8c166cfd1",
226 | "sha256:ddff3a41611664c7f1d9e3d8a9c1669e0e155ac0458e586ffa834dc5953e7d9f",
227 | "sha256:f1a37bbd36b050813673e62ae6464467548628690bf4d48a938170e121e8616e",
228 | "sha256:f31c82d06ba2dbf33c20db9550157e80bb0c4cbd24575c098f0831d1d2e3c5df"
229 | ],
230 | "version": "==1.1.0"
231 | },
232 | "rjsmin": {
233 | "hashes": [
234 | "sha256:05efa485dfddb6418e3b86d8862463aa15641a61f6ae05e7e6de8f116ee77c69",
235 | "sha256:1622fbb6c6a8daaf77da13cc83356539bfe79c1440f9664b02c7f7b150b9a18e",
236 | "sha256:1c93b29fd725e61718299ffe57de93ff32d71b313eaabbfcc7bd32ddb82831d5",
237 | "sha256:2ed83aca637186bafdc894b4b7fc3657e2d74014ccca7d3d69122c1e82675216",
238 | "sha256:38a4474ed52e1575fb9da983ec8657faecd8ab3738508d36e04f87769411fd3d",
239 | "sha256:3b14f4c2933ec194eb816b71a0854ce461b6419a3d852bf360344731ab28c0a6",
240 | "sha256:40e7211a25d9a11ac9ff50446e41268c978555676828af86fa1866615823bfff",
241 | "sha256:41c7c3910f7b8816e37366b293e576ddecf696c5f2197d53cf2c1526ac336646",
242 | "sha256:4387a00777faddf853eebdece9f2e56ebaf243c3f24676a9de6a20c5d4f3d731",
243 | "sha256:54fc30519365841b27556ccc1cb94c5b4413c384ff6d467442fddba66e2e325a",
244 | "sha256:6c395ffc130332cca744f081ed5efd5699038dcb7a5d30c3ff4bc6adb5b30a62",
245 | "sha256:6c529feb6c400984452494c52dd9fdf59185afeacca2afc5174a28ab37751a1b",
246 | "sha256:86c4da7285ddafe6888cb262da563570f28e4a31146b5164a7a6947b1222196b",
247 | "sha256:8944a8a55ac825b8e5ec29f341ecb7574697691ef416506885898d2f780fb4ca",
248 | "sha256:993935654c1311280e69665367d7e6ff694ac9e1609168cf51cae8c0307df0db",
249 | "sha256:99e5597a812b60058baa1457387dc79cca7d273b2a700dc98bfd20d43d60711d",
250 | "sha256:b6a7c8c8d19e154334f640954e43e57283e87bb4a2f6e23295db14eea8e9fc1d",
251 | "sha256:c81229ffe5b0a0d5b3b5d5e6d0431f182572de9e9a077e85dbae5757db0ab75c",
252 | "sha256:d63e193a2f932a786ae82068aa76d1d126fcdff8582094caff9e5e66c4dcc124",
253 | "sha256:e18fe1a610fb105273bb369f61c2b0bd9e66a3f0792e27e4cac44e42ace1968b"
254 | ],
255 | "version": "==1.2.0"
256 | },
257 | "sqlparse": {
258 | "hashes": [
259 | "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
260 | "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"
261 | ],
262 | "markers": "python_version >= '3.5'",
263 | "version": "==0.4.2"
264 | },
265 | "xlsxwriter": {
266 | "hashes": [
267 | "sha256:1aa65166697c42284e82f5bf9a33c2e913341eeef2b262019c3f5b5334768765",
268 | "sha256:53005f03e8eb58f061ebf41d5767c7495ee0772c2396fe26b7e0ca22fa9c2570"
269 | ],
270 | "markers": "python_version >= '3.4'",
271 | "version": "==3.0.2"
272 | }
273 | },
274 | "develop": {
275 | "cfgv": {
276 | "hashes": [
277 | "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426",
278 | "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"
279 | ],
280 | "markers": "python_full_version >= '3.6.1'",
281 | "version": "==3.3.1"
282 | },
283 | "coverage": {
284 | "hashes": [
285 | "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0",
286 | "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd",
287 | "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884",
288 | "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48",
289 | "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76",
290 | "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0",
291 | "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64",
292 | "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685",
293 | "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47",
294 | "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d",
295 | "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840",
296 | "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f",
297 | "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971",
298 | "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c",
299 | "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a",
300 | "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de",
301 | "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17",
302 | "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4",
303 | "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521",
304 | "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57",
305 | "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b",
306 | "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282",
307 | "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644",
308 | "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475",
309 | "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d",
310 | "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da",
311 | "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953",
312 | "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2",
313 | "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e",
314 | "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c",
315 | "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc",
316 | "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64",
317 | "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74",
318 | "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617",
319 | "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3",
320 | "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d",
321 | "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa",
322 | "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739",
323 | "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8",
324 | "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8",
325 | "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781",
326 | "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58",
327 | "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9",
328 | "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c",
329 | "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd",
330 | "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e",
331 | "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"
332 | ],
333 | "index": "pypi",
334 | "version": "==6.2"
335 | },
336 | "distlib": {
337 | "hashes": [
338 | "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b",
339 | "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"
340 | ],
341 | "version": "==0.3.4"
342 | },
343 | "entrypoints": {
344 | "hashes": [
345 | "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
346 | "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
347 | ],
348 | "markers": "python_version >= '2.7'",
349 | "version": "==0.3"
350 | },
351 | "filelock": {
352 | "hashes": [
353 | "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80",
354 | "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"
355 | ],
356 | "markers": "python_version >= '3.7'",
357 | "version": "==3.4.2"
358 | },
359 | "flake8": {
360 | "hashes": [
361 | "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb",
362 | "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"
363 | ],
364 | "index": "pypi",
365 | "version": "==3.7.9"
366 | },
367 | "identify": {
368 | "hashes": [
369 | "sha256:bff7c4959d68510bc28b99d664b6a623e36c6eadc933f89a4e0a9ddff9b4fee4",
370 | "sha256:e926ae3b3dc142b6a7a9c65433eb14ccac751b724ee255f7c2ed3b5970d764fb"
371 | ],
372 | "markers": "python_version >= '3.7'",
373 | "version": "==2.4.9"
374 | },
375 | "isort": {
376 | "hashes": [
377 | "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7",
378 | "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"
379 | ],
380 | "index": "pypi",
381 | "version": "==5.10.1"
382 | },
383 | "mccabe": {
384 | "hashes": [
385 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
386 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
387 | ],
388 | "version": "==0.6.1"
389 | },
390 | "nodeenv": {
391 | "hashes": [
392 | "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b",
393 | "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"
394 | ],
395 | "version": "==1.6.0"
396 | },
397 | "platformdirs": {
398 | "hashes": [
399 | "sha256:30671902352e97b1eafd74ade8e4a694782bd3471685e78c32d0fdfd3aa7e7bb",
400 | "sha256:8ec11dfba28ecc0715eb5fb0147a87b1bf325f349f3da9aab2cd6b50b96b692b"
401 | ],
402 | "markers": "python_version >= '3.7'",
403 | "version": "==2.5.0"
404 | },
405 | "pre-commit": {
406 | "hashes": [
407 | "sha256:758d1dc9b62c2ed8881585c254976d66eae0889919ab9b859064fc2fe3c7743e",
408 | "sha256:fe9897cac830aa7164dbd02a4e7b90cae49630451ce88464bca73db486ba9f65"
409 | ],
410 | "index": "pypi",
411 | "version": "==2.16.0"
412 | },
413 | "pycodestyle": {
414 | "hashes": [
415 | "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
416 | "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
417 | ],
418 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
419 | "version": "==2.5.0"
420 | },
421 | "pyflakes": {
422 | "hashes": [
423 | "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
424 | "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
425 | ],
426 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
427 | "version": "==2.1.1"
428 | },
429 | "pyyaml": {
430 | "hashes": [
431 | "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
432 | "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
433 | "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
434 | "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
435 | "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
436 | "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
437 | "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
438 | "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
439 | "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
440 | "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
441 | "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
442 | "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
443 | "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
444 | "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
445 | "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
446 | "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
447 | "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
448 | "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
449 | "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
450 | "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
451 | "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
452 | "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
453 | "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
454 | "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
455 | "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
456 | "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
457 | "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
458 | "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
459 | "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
460 | "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
461 | "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
462 | "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
463 | "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
464 | ],
465 | "markers": "python_version >= '3.6'",
466 | "version": "==6.0"
467 | },
468 | "six": {
469 | "hashes": [
470 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
471 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
472 | ],
473 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
474 | "version": "==1.16.0"
475 | },
476 | "toml": {
477 | "hashes": [
478 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
479 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
480 | ],
481 | "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
482 | "version": "==0.10.2"
483 | },
484 | "virtualenv": {
485 | "hashes": [
486 | "sha256:45e1d053cad4cd453181ae877c4ffc053546ae99e7dd049b9ff1d9be7491abf7",
487 | "sha256:e0621bcbf4160e4e1030f05065c8834b4e93f4fcc223255db2a823440aca9c14"
488 | ],
489 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
490 | "version": "==20.13.1"
491 | }
492 | }
493 | }
494 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Carrot Box
2 |
3 | [](http://travis-ci.org/vicalloy/carrot-box)
4 | [](https://coveralls.io/github/vicalloy/carrot-box?branch=master)
5 |
6 | Carrot box is a workflow platform, it also an example of using [django-lb-workflow](https://github.com/vicalloy/django-lb-workflow/).
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Demo site
15 | ---------
16 |
17 | Demo site: http://wf.haoluobo.com/
18 |
19 | username: ``admin`` password: ``password``
20 |
21 | Switch to another user: http://wf.haoluobo.com/impersonate/search
22 |
23 | Stop switch: http://wf.haoluobo.com/impersonate/stop
24 |
25 | Running locally
26 | ---------------
27 |
28 | Run the following commands:
29 |
30 | make init-pyenv
31 | make init
32 | make run
33 |
34 | Creating Custom Workflows
35 | -------------------------
36 |
37 | You should read the documentation of [django-lb-workflow](https://github.com/vicalloy/django-lb-workflow/).
38 |
--------------------------------------------------------------------------------
/carrot_box/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/__init__.py
--------------------------------------------------------------------------------
/carrot_box/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for carrot_box project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'carrot_box.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/carrot_box/hr/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/hr/__init__.py
--------------------------------------------------------------------------------
/carrot_box/hr/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import CarrotDepartment
4 | from .models import CarrotRole
5 | from .models import CarrotUser
6 |
7 |
8 | @admin.register(CarrotUser)
9 | class CarrotUserAdmin(admin.ModelAdmin):
10 | list_display = ('username', 'full_name', 'post', 'get_department', 'email', 'is_staff', 'is_superuser')
11 | list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
12 | search_fields = ('username', 'first_name', 'last_name', 'email')
13 | ordering = ('username',)
14 | filter_horizontal = ('groups', 'user_permissions',)
15 | autocomplete_fields = ('leader', ) # 'department',
16 |
17 |
18 | @admin.register(CarrotDepartment)
19 | class CarrotDepartmentAdmin(admin.ModelAdmin):
20 | list_display = ('name', 'code', 'parent', 'leader', 'oid', 'is_active',)
21 | search_fields = ('code', 'name')
22 | ordering = ('oid',)
23 | filter_horizontal = ('permissions', )
24 | autocomplete_fields = ('parent', 'parents', 'leader', )
25 |
26 |
27 | @admin.register(CarrotRole)
28 | class CarrotRoleAdmin(admin.ModelAdmin):
29 | list_display = ('name', 'code', 'oid', 'is_active',)
30 | search_fields = ('code', 'name')
31 | ordering = ('oid',)
32 | filter_horizontal = ('permissions',)
33 | autocomplete_fields = ('users', )
34 |
--------------------------------------------------------------------------------
/carrot_box/hr/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class HrConfig(AppConfig):
5 | name = 'carrot_box.hr'
6 |
--------------------------------------------------------------------------------
/carrot_box/hr/backends.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.backends import ModelBackend
2 | from django.contrib.auth.models import Permission
3 |
4 |
5 | class CarrotModelBackend(ModelBackend):
6 |
7 | def get_all_permissions(self, user_obj, obj=None):
8 | if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
9 | return set()
10 | if not hasattr(user_obj, '_perm_cache'):
11 | user_obj._perm_cache = super().get_all_permissions(user_obj)
12 | user_obj._perm_cache.update(self.get_role_permissions(user_obj))
13 | user_obj._perm_cache.update(self.get_department_permissions(user_obj))
14 | return user_obj._perm_cache
15 |
16 | def get_role_permissions(self, user_obj, obj=None):
17 | return self._get_permissions(user_obj, obj, 'role')
18 |
19 | def _get_role_permissions(self, user_obj):
20 | return Permission.objects.filter(carrotrole__users=user_obj)
21 |
22 | def get_department_permissions(self, user_obj, obj=None):
23 | return self._get_permissions(user_obj, obj, 'department')
24 |
25 | def _get_department_permissions(self, user_obj):
26 | department = user_obj.get_department()
27 | if not department:
28 | return set()
29 | departments = department.parents.all()
30 | return Permission.objects.filter(carrotdepartment__in=departments)
31 |
--------------------------------------------------------------------------------
/carrot_box/hr/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-04-07 06:12
2 |
3 | from django.conf import settings
4 | import django.contrib.auth.models
5 | import django.contrib.auth.validators
6 | from django.db import migrations, models
7 | import django.db.models.deletion
8 | import django.utils.timezone
9 | import uuid
10 |
11 |
12 | class Migration(migrations.Migration):
13 |
14 | initial = True
15 |
16 | dependencies = [
17 | ('auth', '0011_update_proxy_permissions'),
18 | ]
19 |
20 | operations = [
21 | migrations.CreateModel(
22 | name='CarrotUser',
23 | fields=[
24 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
25 | ('password', models.CharField(max_length=128, verbose_name='password')),
26 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
27 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
28 | ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
29 | ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
30 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
31 | ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
32 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
33 | ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
34 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
35 | ('full_name', models.CharField(blank=True, max_length=255)),
36 | ('post', models.CharField(blank=True, max_length=255)),
37 | ('department_id', models.PositiveIntegerField(blank=True, null=True)),
38 | ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
39 | ('leader', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Leader')),
40 | ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
41 | ],
42 | options={
43 | 'abstract': False,
44 | },
45 | managers=[
46 | ('objects', django.contrib.auth.models.UserManager()),
47 | ],
48 | ),
49 | migrations.CreateModel(
50 | name='CarrotRole',
51 | fields=[
52 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
53 | ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
54 | ('code', models.CharField(blank=True, max_length=100)),
55 | ('name', models.CharField(max_length=100)),
56 | ('description', models.CharField(blank=True, max_length=50)),
57 | ('oid', models.IntegerField(default=999, verbose_name='Order')),
58 | ('is_active', models.BooleanField(default=True)),
59 | ('permissions', models.ManyToManyField(blank=True, to='auth.Permission')),
60 | ('users', models.ManyToManyField(blank=True, related_name='roles', to=settings.AUTH_USER_MODEL)),
61 | ],
62 | ),
63 | migrations.CreateModel(
64 | name='CarrotDepartment',
65 | fields=[
66 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
67 | ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
68 | ('code', models.CharField(blank=True, max_length=100)),
69 | ('name', models.CharField(max_length=100)),
70 | ('description', models.CharField(blank=True, max_length=50)),
71 | ('oid', models.IntegerField(default=999, verbose_name='Order')),
72 | ('is_active', models.BooleanField(default=True)),
73 | ('leader', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='department_master_user', to=settings.AUTH_USER_MODEL)),
74 | ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sub_departments', to='hr.CarrotDepartment', verbose_name='Parent Department')),
75 | ('parents', models.ManyToManyField(blank=True, editable=False, related_name='all_sub_departments', to='hr.CarrotDepartment', verbose_name='All parents department')),
76 | ('permissions', models.ManyToManyField(blank=True, to='auth.Permission')),
77 | ],
78 | ),
79 | ]
80 |
--------------------------------------------------------------------------------
/carrot_box/hr/migrations/0002_auto_20211217_0556.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.10 on 2021-12-17 05:56
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('hr', '0001_initial'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='carrotdepartment',
15 | name='id',
16 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17 | ),
18 | migrations.AlterField(
19 | model_name='carrotrole',
20 | name='id',
21 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
22 | ),
23 | migrations.AlterField(
24 | model_name='carrotuser',
25 | name='first_name',
26 | field=models.CharField(blank=True, max_length=150, verbose_name='first name'),
27 | ),
28 | migrations.AlterField(
29 | model_name='carrotuser',
30 | name='id',
31 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
32 | ),
33 | ]
34 |
--------------------------------------------------------------------------------
/carrot_box/hr/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/hr/migrations/__init__.py
--------------------------------------------------------------------------------
/carrot_box/hr/models.py:
--------------------------------------------------------------------------------
1 | import uuid
2 |
3 | from django.conf import settings as django_settings
4 | from django.contrib.auth.models import AbstractUser
5 | from django.contrib.auth.models import Permission
6 | from django.db import models
7 |
8 | AUTH_USER_MODEL = getattr(django_settings, 'AUTH_USER_MODEL', 'auth.User')
9 |
10 |
11 | class CarrotDepartment(models.Model):
12 | uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
13 | code = models.CharField(max_length=100, blank=True)
14 | name = models.CharField(max_length=100)
15 | description = models.CharField(max_length=50, blank=True)
16 | parent = models.ForeignKey(
17 | 'CarrotDepartment', blank=True, null=True,
18 | on_delete=models.SET_NULL,
19 | related_name='sub_departments',
20 | verbose_name='Parent Department')
21 | # all parent node, include self
22 | parents = models.ManyToManyField(
23 | 'CarrotDepartment', verbose_name='All parents department',
24 | related_name='all_sub_departments',
25 | editable=False, blank=True)
26 | leader = models.ForeignKey(
27 | AUTH_USER_MODEL, blank=True, null=True,
28 | on_delete=models.SET_NULL,
29 | related_name="department_master_user")
30 | permissions = models.ManyToManyField(
31 | Permission, blank=True)
32 | oid = models.IntegerField('Order', default=999)
33 | is_active = models.BooleanField(default=True)
34 |
35 | def __str__(self):
36 | return self.name
37 |
38 | def natural_key(self):
39 | return (
40 | self.uuid,
41 | )
42 |
43 | def get_parents(self):
44 | department = self
45 | parent = department.parent
46 | parents = [department]
47 | while parent:
48 | parents.append(parent)
49 | department = parent
50 | parent = department.parent
51 | return parents
52 |
53 | def update_parents(self):
54 | old_parents = set(self.parents.all())
55 | new_parents = set(self.get_parents())
56 | if old_parents == new_parents:
57 | return
58 | self.parents.set(new_parents)
59 | for d in self.sub_departments.all():
60 | d.update_parents()
61 |
62 | def save(self, *args, **kwargs):
63 | if self.parent == self:
64 | self.parent = None
65 | super().save(*args, **kwargs)
66 | self.update_parents()
67 |
68 |
69 | class CarrotRole(models.Model):
70 | uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
71 | code = models.CharField(max_length=100, blank=True)
72 | name = models.CharField(max_length=100)
73 | description = models.CharField(max_length=50, blank=True)
74 | users = models.ManyToManyField(
75 | AUTH_USER_MODEL, blank=True,
76 | related_name='roles',
77 | )
78 | permissions = models.ManyToManyField(
79 | Permission, blank=True)
80 | oid = models.IntegerField('Order', default=999)
81 | is_active = models.BooleanField(default=True)
82 |
83 | def __str__(self):
84 | return self.name
85 |
86 | def natural_key(self):
87 | return (
88 | self.uuid,
89 | )
90 |
91 |
92 | class CarrotUserMixin(models.Model):
93 | full_name = models.CharField(max_length=255, blank=True)
94 | post = models.CharField(max_length=255, blank=True)
95 | department_id = models.PositiveIntegerField(null=True, blank=True)
96 | # department = models.ForeignKey( # will get error `Can't resolve dependencies`
97 | # CarrotDepartment,
98 | # on_delete=models.SET_NULL,
99 | # null=True, blank=True)
100 | leader = models.ForeignKey(
101 | AUTH_USER_MODEL, blank=True, null=True,
102 | on_delete=models.SET_NULL,
103 | verbose_name='Leader')
104 |
105 | def get_department(self):
106 | if self.department_id:
107 | return CarrotDepartment.objects.filter(pk=self.department_id).first()
108 | return None
109 |
110 | class Meta:
111 | abstract = True
112 |
113 |
114 | class CarrotUser(CarrotUserMixin, AbstractUser):
115 |
116 | def __str__(self):
117 | return self.username
118 |
119 | def save(self, *args, **kwargs):
120 | if not self.full_name:
121 | self.full_name = self.username
122 | super().save(*args, **kwargs)
123 |
--------------------------------------------------------------------------------
/carrot_box/hr/tests.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 |
3 | from carrot_box.tests import BaseTests
4 |
5 | from .backends import CarrotModelBackend
6 | from .userparser import CarrotBoxUserParser
7 |
8 | User = get_user_model()
9 |
10 |
11 | class UserSimpleParserTests(BaseTests):
12 |
13 | def test_parser_role(self):
14 | role_it = self.roles['it']
15 | users = CarrotBoxUserParser(f"r[{role_it.pk}:it]").parse()
16 | self.assertEqual(users[0], self.users['it'])
17 |
18 | users = CarrotBoxUserParser(f"r[it]").parse()
19 | self.assertEqual(users[0], self.users['it'])
20 |
21 | def test_dept_direct_leaders(self):
22 | users = CarrotBoxUserParser("dept_direct_leaders d[it]").parse()
23 | self.assertEqual(users[0], self.users['it_dept_leader'])
24 |
25 |
26 | class PermissionTests(BaseTests):
27 | def test_get_all_permissions(self):
28 | backend = CarrotModelBackend()
29 | it = self.users['it']
30 | backend.get_all_permissions(it)
31 |
--------------------------------------------------------------------------------
/carrot_box/hr/userparser.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from lbworkflow.core.userparser import SimpleUserParser
3 |
4 | from .models import CarrotDepartment
5 | from .models import CarrotRole
6 |
7 | User = get_user_model()
8 |
9 |
10 | class CarrotBoxUserParser(SimpleUserParser):
11 | def process_func(self, func_str):
12 | """
13 | return None if not a func
14 | """
15 | params = [e.strip() for e in func_str.split(' ') if e.strip()]
16 | func_name = params[0]
17 | params = params[1:]
18 | if not params: # at least one param
19 | return None
20 | elif func_name == 'dept_direct_leaders':
21 | departments = self.get_departments(params[0])
22 | return [d.leader for d in departments if d.leader]
23 | return None # if not function return None
24 |
25 | def get_departments(self, atom_str):
26 | """
27 | d[o.dept]
28 | d[o.depts]
29 | d[11:it]
30 | """
31 | return self.get_object_list(atom_str, CarrotDepartment, 'code', 'd[')
32 |
33 | def get_roles(self, role_str):
34 | """
35 | r[hr]
36 | r[1:hr]
37 | """
38 | return self.get_object_list(role_str, CarrotRole, 'code', 'r[')
39 |
40 | def get_users_by_roles(self, role_str):
41 | roles = self.get_roles(role_str)
42 | return User.objects.filter(roles__in=roles)
43 |
44 | def parse_atom_rule(self, atom_rule):
45 | if atom_rule and atom_rule.startswith('r['):
46 | return self.get_users_by_roles(atom_rule)
47 | return super().parse_atom_rule(atom_rule)
48 |
--------------------------------------------------------------------------------
/carrot_box/hr/views.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/hr/views.py
--------------------------------------------------------------------------------
/carrot_box/param/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/param/__init__.py
--------------------------------------------------------------------------------
/carrot_box/param/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import Param
4 | from .models import ParamType
5 |
6 |
7 | class ParamInline(admin.TabularInline):
8 | raw_id_fields = ('parent', 'param_type')
9 | model = Param
10 |
11 |
12 | @admin.register(ParamType)
13 | class ParamTypeAdmin(admin.ModelAdmin):
14 | search_fields = ('code', 'name', )
15 | list_display = ('code', 'name', 'oid', 'is_active',)
16 | inlines = [
17 | ParamInline,
18 | ]
19 |
20 |
21 | @admin.register(Param)
22 | class ParamAdmin(admin.ModelAdmin):
23 | search_fields = ('code', 'name', 'param_type__name', 'param_type__code')
24 | list_display = ('name', 'param_type', 'code', 'oid', 'is_active',)
25 | raw_id_fields = ('parent', 'param_type')
26 | inlines = [
27 | ParamInline,
28 | ]
29 |
--------------------------------------------------------------------------------
/carrot_box/param/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-04-07 03:14
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 | import uuid
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='ParamType',
18 | fields=[
19 | ('code', models.CharField(max_length=255, primary_key=True, serialize=False)),
20 | ('name', models.CharField(max_length=255)),
21 | ('oid', models.IntegerField(default=999, verbose_name='Order')),
22 | ('is_active', models.BooleanField(default=True)),
23 | ],
24 | options={
25 | 'ordering': ['oid'],
26 | },
27 | ),
28 | migrations.CreateModel(
29 | name='Param',
30 | fields=[
31 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
32 | ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
33 | ('code', models.CharField(blank=True, max_length=255)),
34 | ('name', models.CharField(max_length=255)),
35 | ('oid', models.IntegerField(default=999, verbose_name='Order')),
36 | ('is_active', models.BooleanField(default=True)),
37 | ('param_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='param.ParamType')),
38 | ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='param.Param')),
39 | ],
40 | options={
41 | 'ordering': ['oid'],
42 | },
43 | ),
44 | ]
45 |
--------------------------------------------------------------------------------
/carrot_box/param/migrations/0002_alter_param_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.10 on 2021-12-17 05:56
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('param', '0001_initial'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='param',
15 | name='id',
16 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/carrot_box/param/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/param/migrations/__init__.py
--------------------------------------------------------------------------------
/carrot_box/param/models.py:
--------------------------------------------------------------------------------
1 | import uuid
2 |
3 | from django.db import models
4 | from lbworkflow.core.datahelper import get_or_create
5 |
6 |
7 | class ParamType(models.Model):
8 | code = models.CharField(max_length=255, primary_key=True)
9 | name = models.CharField(max_length=255)
10 | oid = models.IntegerField('Order', default=999)
11 | is_active = models.BooleanField(default=True)
12 |
13 | @classmethod
14 | def get_all(cls, **kwargs):
15 | return cls.objects.filter(is_active=True, **kwargs).order_by('oid')
16 |
17 | class Meta:
18 | ordering = ["oid"]
19 |
20 | def __str__(self):
21 | return self.name
22 |
23 |
24 | def create_param_type(*args, **kwargs):
25 | return get_or_create(ParamType, *args, uid_field_name='code', **kwargs)
26 |
27 |
28 | class Param(models.Model):
29 | uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
30 | parent = models.ForeignKey(
31 | 'Param',
32 | on_delete=models.SET_NULL,
33 | blank=True, null=True)
34 | param_type = models.ForeignKey(
35 | ParamType,
36 | on_delete=models.CASCADE,
37 | blank=True, null=True)
38 | code = models.CharField(max_length=255, blank=True)
39 | name = models.CharField(max_length=255)
40 | oid = models.IntegerField('Order', default=999)
41 | is_active = models.BooleanField(default=True)
42 |
43 | @classmethod
44 | def get_all(cls, **kwargs):
45 | return cls.objects.filter(is_active=True, **kwargs).order_by('oid')
46 |
47 | def natural_key(self):
48 | return '%s' % self.uuid
49 |
50 | class Meta:
51 | ordering = ["oid"]
52 |
53 | def __str__(self):
54 | return self.name
55 |
56 |
57 | def create_param(*args, **kwargs):
58 | return get_or_create(Param, *args, **kwargs)
59 |
--------------------------------------------------------------------------------
/carrot_box/settings/__init__.py:
--------------------------------------------------------------------------------
1 | try:
2 | from .local import * # NOQA
3 | except ImportError:
4 | from .dev import * # NOQA
5 |
--------------------------------------------------------------------------------
/carrot_box/settings/base.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for carrot_box project.
3 |
4 | Generated by 'django-admin startproject' using Django 3.0.4.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/3.0/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 | BASE_DIR = os.path.dirname(BASE_DIR)
18 |
19 |
20 | # Quick-start development settings - unsuitable for production
21 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
22 |
23 | # SECURITY WARNING: keep the secret key used in production secret!
24 | SECRET_KEY = 'ay3)km!k_+3dt@#&9#%!+ipj8e90-_$w#9y941%e&$@zci$u))'
25 |
26 | # SECURITY WARNING: don't run with debug turned on in production!
27 | DEBUG = True
28 |
29 | ALLOWED_HOSTS = ['*']
30 |
31 |
32 | # Application definition
33 |
34 | INSTALLED_APPS = [
35 | 'carrot_box',
36 | 'carrot_box.param',
37 | 'carrot_box.hr',
38 | 'carrot_box.wfapp.leave',
39 | 'carrot_box.wfapp.purchase',
40 |
41 | 'django.contrib.admin',
42 | 'django.contrib.auth',
43 | 'django.contrib.contenttypes',
44 | 'django.contrib.sessions',
45 | 'django.contrib.messages',
46 | 'django.contrib.staticfiles',
47 |
48 | 'stronghold',
49 | 'impersonate',
50 | 'crispy_forms',
51 | 'compressor',
52 | 'django_select2',
53 | 'bootstrap_pagination',
54 |
55 | 'lbattachment',
56 | 'lbadminlte',
57 | 'lbutils',
58 |
59 | 'lbworkflow',
60 | 'lbworkflow.simplewf',
61 | ]
62 |
63 | MIDDLEWARE = [
64 | 'django.middleware.security.SecurityMiddleware',
65 | 'django.contrib.sessions.middleware.SessionMiddleware',
66 | 'django.middleware.common.CommonMiddleware',
67 | 'django.middleware.csrf.CsrfViewMiddleware',
68 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
69 | 'django.contrib.messages.middleware.MessageMiddleware',
70 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
71 |
72 | 'impersonate.middleware.ImpersonateMiddleware',
73 | 'stronghold.middleware.LoginRequiredMiddleware',
74 | ]
75 |
76 | ROOT_URLCONF = 'carrot_box.urls'
77 |
78 | TEMPLATES = [
79 | {
80 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
81 | 'DIRS': [],
82 | 'APP_DIRS': True,
83 | 'OPTIONS': {
84 | 'context_processors': [
85 | 'django.template.context_processors.debug',
86 | 'django.template.context_processors.request',
87 | 'django.contrib.auth.context_processors.auth',
88 | 'django.contrib.messages.context_processors.messages',
89 | ],
90 | },
91 | },
92 | ]
93 |
94 | WSGI_APPLICATION = 'carrot_box.wsgi.application'
95 |
96 |
97 | # Database
98 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
99 |
100 | DATABASES = {
101 | 'default': {
102 | 'ENGINE': 'django.db.backends.sqlite3',
103 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
104 | }
105 | }
106 |
107 |
108 | # Password validation
109 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
110 |
111 | AUTH_PASSWORD_VALIDATORS = [
112 | {
113 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
114 | },
115 | {
116 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
117 | },
118 | {
119 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
120 | },
121 | {
122 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
123 | },
124 | ]
125 |
126 |
127 | # Internationalization
128 | # https://docs.djangoproject.com/en/3.0/topics/i18n/
129 |
130 | LANGUAGE_CODE = 'en-us'
131 |
132 | TIME_ZONE = 'UTC'
133 |
134 | USE_I18N = True
135 |
136 | USE_L10N = True
137 |
138 | USE_TZ = True
139 |
140 |
141 | # Static files (CSS, JavaScript, Images)
142 | # https://docs.djangoproject.com/en/3.0/howto/static-files/
143 |
144 | STATIC_URL = '/static/'
145 |
146 | STRONGHOLD_PUBLIC_URLS = [
147 | r'^/admin/',
148 | ]
149 | LOGIN_URL = '/admin/login/'
150 | LOGOUT_URL = '/admin/logout/'
151 |
152 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
153 | MEDIA_URL_ = '/media/'
154 | MEDIA_URL = MEDIA_URL_
155 |
156 | STATIC_URL = '/static/'
157 |
158 | LBWF_APPS = {
159 | 'simplewf': 'lbworkflow.simplewf',
160 | 'leave': 'carrot_box.wfapp.leave',
161 | 'purchase': 'carrot_box.wfapp.purchase',
162 | }
163 |
164 | STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic')
165 |
166 | STATICFILES_FINDERS = (
167 | 'django.contrib.staticfiles.finders.FileSystemFinder',
168 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
169 | )
170 |
171 | STATICFILES_DIRS = (
172 | os.path.join(BASE_DIR, 'node_modules'),
173 | )
174 |
175 | CRISPY_TEMPLATE_PACK = 'bootstrap3'
176 |
177 | # django-compressor
178 | STATICFILES_FINDERS += (('compressor.finders.CompressorFinder'),)
179 | COMPRESS_PRECOMPILERS = (
180 | ('text/coffeescript', 'coffee --compile --stdio'),
181 | ('text/less', 'lessc {infile} {outfile}'),
182 | ('text/x-sass', 'sass {infile} {outfile}'),
183 | ('text/x-scss', 'sass --scss {infile} {outfile}'),
184 | )
185 |
186 | PROJECT_TITLE = 'Carrot Box'
187 |
188 | AUTH_USER_MODEL = 'hr.CarrotUser'
189 |
190 | LBWF_USER_PARSER = 'carrot_box.hr.userparser.CarrotBoxUserParser'
191 |
192 | AUTHENTICATION_BACKENDS = (
193 | 'carrot_box.hr.backends.CarrotModelBackend',
194 | )
195 |
196 | IMPERSONATE = {
197 | 'REDIRECT_URL': '/',
198 | 'PAGINATE_COUNT': 20,
199 | }
200 |
201 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
--------------------------------------------------------------------------------
/carrot_box/settings/dev.py:
--------------------------------------------------------------------------------
1 | from .base import * # NOQA
2 |
3 | DEBUG = True
4 | EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
5 |
6 | try:
7 | import debug_toolbar # NOQA
8 | INSTALLED_APPS += ('debug_toolbar',) # NOQA
9 | MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',) # NOQA
10 | INTERNAL_IPS = ('127.0.0.1',)
11 | except ImportError:
12 | pass
13 |
--------------------------------------------------------------------------------
/carrot_box/templates/base.html:
--------------------------------------------------------------------------------
1 | {% extends "lbworkflow/base.html" %}
2 |
--------------------------------------------------------------------------------
/carrot_box/templates/base_ext.html:
--------------------------------------------------------------------------------
1 | {% extends "lbworkflow/base_ext.html" %}
2 |
3 | {% block header_nav_left %}
4 |
13 | {% endblock %}
14 |
--------------------------------------------------------------------------------
/carrot_box/templates/base_form.html:
--------------------------------------------------------------------------------
1 | {% extends "lbadminlte/base_form.html" %}
2 |
--------------------------------------------------------------------------------
/carrot_box/templates/base_formset.html:
--------------------------------------------------------------------------------
1 | {% extends "lbadminlte/base_formset.html" %}
2 |
--------------------------------------------------------------------------------
/carrot_box/tests.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.core.management import call_command
3 | from django.test import TestCase
4 | from lbworkflow.core.datahelper import load_wf_data
5 |
6 | from .wfdata import load_departments
7 | from .wfdata import load_roles
8 | from .wfdata import load_simplewf
9 | from .wfdata import load_users
10 |
11 | User = get_user_model()
12 |
13 |
14 | # create migrations for purchase and do migrate for it.
15 | call_command('makemigrations', 'purchase')
16 | call_command('migrate')
17 |
18 |
19 | class BaseTests(TestCase):
20 |
21 | def setUp(self):
22 | self.init_data()
23 |
24 | def init_data(self):
25 | load_wf_data('lbworkflow')
26 | self.roles = load_roles()
27 | self.departments = load_departments()
28 | self.users = load_users(self.departments, self.roles)
29 | load_simplewf()
30 |
31 |
32 | class CarrotTests(BaseTests):
33 |
34 | def test_data(self):
35 | pass
36 |
37 |
38 | class PurchaseTests(BaseTests):
39 | def init_data(self):
40 | super().init_data()
41 | load_wf_data('carrot_box.wfapp.purchase')
42 |
43 | def test_data(self):
44 | pass
45 |
--------------------------------------------------------------------------------
/carrot_box/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.conf.urls.static import static
3 | from django.contrib import admin
4 | from django.urls import include
5 | from django.urls import path
6 | from django.views.generic import RedirectView
7 |
8 | urlpatterns = [
9 | path('', RedirectView.as_view(url='/wf/list/'), name='home'),
10 | path('admin/', admin.site.urls),
11 | path('wf/', include('lbworkflow.urls')),
12 | path('attachment/', include('lbattachment.urls')),
13 | path('select2/', include('django_select2.urls')),
14 | path('impersonate/', include('impersonate.urls')),
15 | ]
16 |
17 | if settings.DEBUG:
18 | urlpatterns += static(settings.MEDIA_URL_, document_root=settings.MEDIA_ROOT)
19 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/wfapp/__init__.py
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/wfapp/leave/__init__.py
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from lbutils import BootstrapFormHelperMixin
3 | from lbworkflow.forms import WorkflowFormMixin
4 |
5 | from .models import Leave
6 |
7 |
8 | class LeaveForm(BootstrapFormHelperMixin, WorkflowFormMixin, forms.ModelForm):
9 |
10 | def __init__(self, *args, **kw):
11 | super().__init__(*args, **kw)
12 | self.init_crispy_helper()
13 | self.layout_fields([
14 | ['start_on', 'end_on'],
15 | ['leave_type', 'leave_days'],
16 | ['reason', ],
17 | ])
18 |
19 | def save(self, commit=True):
20 | obj = super().save(commit=False)
21 | obj.init_actual_info()
22 | if commit:
23 | self.save_m2m()
24 | obj.save()
25 | return obj
26 |
27 | class Meta:
28 | model = Leave
29 | fields = ['start_on', 'end_on', 'leave_type', 'leave_days', 'reason', ]
30 |
31 |
32 | class HRForm(BootstrapFormHelperMixin, WorkflowFormMixin, forms.ModelForm):
33 | comment = forms.CharField(
34 | label='Comment', required=False,
35 | widget=forms.Textarea())
36 |
37 | def __init__(self, *args, **kw):
38 | super().__init__(*args, **kw)
39 | self.init_crispy_helper(label_class='col-md-2', field_class='col-md-8')
40 | self.layout_fields([
41 | ['actual_start_on', ],
42 | ['actual_end_on', ],
43 | ['actual_leave_days', ],
44 | ['comment', ],
45 | ])
46 |
47 | class Meta:
48 | model = Leave
49 | fields = ['actual_start_on', 'actual_end_on', 'actual_leave_days', ]
50 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-04-07 09:13
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14 | ('param', '0001_initial'),
15 | ('lbworkflow', '0004_processreportlink_uuid'),
16 | ]
17 |
18 | operations = [
19 | migrations.CreateModel(
20 | name='Leave',
21 | fields=[
22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
23 | ('created_on', models.DateTimeField(auto_now_add=True, verbose_name='Created on')),
24 | ('start_on', models.DateTimeField(verbose_name='Start on')),
25 | ('end_on', models.DateTimeField(verbose_name='End on')),
26 | ('leave_days', models.DecimalField(decimal_places=1, max_digits=5, verbose_name='Leave days')),
27 | ('actual_start_on', models.DateTimeField(verbose_name='Actual start on')),
28 | ('actual_end_on', models.DateTimeField(verbose_name='Actual end on')),
29 | ('actual_leave_days', models.DecimalField(decimal_places=1, max_digits=5, verbose_name='Actual leave days')),
30 | ('reason', models.TextField(verbose_name='Reason')),
31 | ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Created by')),
32 | ('leave_type', models.ForeignKey(limit_choices_to={'is_active': True, 'param_type__code': 'leave_type'}, null=True, on_delete=django.db.models.deletion.SET_NULL, to='param.Param', verbose_name='Leave Type')),
33 | ('pinstance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leave', to='lbworkflow.ProcessInstance', verbose_name='Process instance')),
34 | ],
35 | options={
36 | 'verbose_name': 'Leave',
37 | 'ordering': ['-created_on'],
38 | 'permissions': (),
39 | },
40 | ),
41 | ]
42 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/migrations/0002_alter_leave_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.10 on 2021-12-17 05:56
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('leave', '0001_initial'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='leave',
15 | name='id',
16 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/wfapp/leave/migrations/__init__.py
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from lbworkflow.models import BaseWFObj
3 |
4 | from carrot_box.param.models import Param
5 |
6 |
7 | class Leave(BaseWFObj):
8 | start_on = models.DateTimeField('Start on')
9 | end_on = models.DateTimeField('End on')
10 | leave_days = models.DecimalField('Leave days', max_digits=5, decimal_places=1)
11 |
12 | actual_start_on = models.DateTimeField('Actual start on')
13 | actual_end_on = models.DateTimeField('Actual end on')
14 | actual_leave_days = models.DecimalField(
15 | 'Actual leave days', max_digits=5, decimal_places=1)
16 |
17 | leave_type = models.ForeignKey(
18 | Param, verbose_name='Leave Type',
19 | on_delete=models.SET_NULL,
20 | null=True, blank=False,
21 | limit_choices_to={'param_type__code': 'leave_type', 'is_active': True}
22 | )
23 | reason = models.TextField('Reason')
24 |
25 | class Meta:
26 | verbose_name = 'Leave'
27 | ordering = ["-created_on"]
28 | permissions = (
29 | )
30 |
31 | def __str__(self):
32 | return '%s %s days' % (self.created_by, self.leave_days, )
33 |
34 | def init_actual_info(self):
35 | self.actual_start_on = self.start_on
36 | self.actual_end_on = self.end_on
37 | self.actual_leave_days = self.leave_days
38 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/templates/leave/detail.html:
--------------------------------------------------------------------------------
1 | {% extends "lbworkflow/wf_base_detail.html" %}
2 |
3 | {% block right_side_header_ext_btns %}
4 | Print
5 | |
6 | {% endblock %}
7 |
8 | {% block right_side_tab_base_ctx %}
9 | {% include "leave/inc_detail_info.html" %}
10 | {{ for_test }}
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/templates/leave/form.html:
--------------------------------------------------------------------------------
1 | {% extends "lbworkflow/base_form.html" %}
2 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/templates/leave/inc_detail_info.html:
--------------------------------------------------------------------------------
1 | {% include "lbworkflow/inc_wf_status.html" %}
2 |
3 |
4 | Start on |
5 | {{ object.start_on }} |
6 | End on |
7 | {{ object.end_on }} |
8 |
9 |
10 | Leave Type |
11 | {{ object.leave_type }} |
12 | Days |
13 | {{ object.leave_days }} |
14 |
15 |
16 | Actual start on |
17 | {{ object.actual_start_on }} |
18 | Actual end on |
19 | {{ object.actual_end_on }} |
20 |
21 |
22 | Days |
23 | {{ object.actual_leave_days }} |
24 | |
25 | |
26 |
27 |
28 | Reason |
29 |
30 | {{ object.reason|linebreaks }}
31 | |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/templates/leave/list.html:
--------------------------------------------------------------------------------
1 | {% extends "base_ext.html" %}
2 |
3 | {% load crispy_forms_tags %}
4 | {% load bootstrap_pagination %}
5 | {% load lbworkflow_tags %}
6 |
7 | {% block nav_sel_node %}id-nav-leave{% endblock %}
8 |
9 | {% block right_side %}
10 |
18 |
19 |
20 | {% if search_form %}
21 |
26 | {% endif %}
27 |
28 |
29 |
30 |
31 | NO. |
32 | Created by |
33 | Start on |
34 | End on |
35 | Created on |
36 | Current operator |
37 | Activity |
38 |
39 | {% for o in object_list %}{% with pi=o.pinstance %}
40 |
41 | {{ pi.no }} |
42 | {{ pi.created_by }} |
43 | {{ o.start_on|date:"Y-m-d H:i" }} |
44 | {{ o.end_on|date:"Y-m-d H:i" }} |
45 | {{ pi.created_on|date:"Y-m-d H:i" }} |
46 | {{ pi.get_operators_display }} |
47 |
48 |
49 | {{ pi.cur_node.name }}
50 |
51 | |
52 |
53 | {% endwith %}{% endfor %}
54 |
55 |
56 |
57 |
60 |
61 |
62 | {% endblock %}
63 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/templates/leave/print.html:
--------------------------------------------------------------------------------
1 | {% extends "lbadminlte/mbase_popup.html" %}
2 |
3 | {% block content %}
4 | {% include "leave/inc_detail_info.html" %}
5 |
6 | {% include "lbworkflow/inc_wf_history.html" %}
7 | {{ for_test }}
8 | {% endblock %}
9 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/tests.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.urls import reverse
3 | from django.utils import timezone
4 | from lbutils import get_or_none
5 |
6 | from carrot_box.param.models import Param
7 | from carrot_box.tests import BaseTests
8 |
9 | from .models import Leave
10 | from .wfdata import load_data
11 |
12 | User = get_user_model()
13 |
14 |
15 | class LeaveTests(BaseTests):
16 |
17 | def setUp(self):
18 | super().setUp()
19 | self.client.login(username='tom', password='password')
20 | self.leave_type_vacation = Param.objects.get(param_type__code='leave_type', name='Vacation')
21 | self.leave = self.create_leave('reason', False)
22 |
23 | def init_data(self):
24 | super().init_data()
25 | load_data()
26 |
27 | def create_leave(self, reason, submit=True):
28 | leave = Leave(
29 | start_on=timezone.now(), end_on=timezone.now(), leave_days=1,
30 | leave_type=self.leave_type_vacation,
31 | reason=reason, created_by=self.users['tom'])
32 | leave.init_actual_info()
33 | leave.save()
34 | leave.create_pinstance('leave', submit)
35 | return leave
36 |
37 | def get_leave(self, reason):
38 | return get_or_none(Leave, reason=reason)
39 |
40 | def test_list(self):
41 | resp = self.client.get(reverse('wf_list', args=('leave', )))
42 | self.assertEqual(resp.status_code, 200)
43 |
44 | def test_export(self):
45 | resp = self.client.get(reverse('wf_list', args=('leave', )), {'export': 1})
46 | self.assertEqual(resp.status_code, 200)
47 |
48 | def test_detail(self):
49 | resp = self.client.get(reverse('wf_detail', args=(self.leave.pinstance.pk, )))
50 | self.assertEqual(resp.status_code, 200)
51 |
52 | def test_submit(self):
53 | self.client.login(username='tom', password='password')
54 |
55 | url = reverse('wf_new', args=('leave', ))
56 | resp = self.client.get(url)
57 | self.assertEqual(resp.status_code, 200)
58 |
59 | data = {
60 | 'start_on': '2017-04-19 09:01',
61 | 'end_on': '2017-04-20 09:01',
62 | 'leave_type': self.leave_type_vacation.pk,
63 | 'leave_days': '1',
64 | 'reason': 'test save',
65 | }
66 | resp = self.client.post(url, data)
67 | leave = Leave.objects.get(reason='test save')
68 | self.assertRedirects(resp, '/wf/%s/' % leave.pinstance.pk)
69 | self.assertEqual('Draft', leave.pinstance.cur_node.name)
70 |
71 | data['act_submit'] = 'Submit'
72 | data['reason'] = 'test submit'
73 | resp = self.client.post(url, data)
74 | leave = Leave.objects.get(reason='test submit')
75 | self.assertRedirects(resp, '/wf/%s/' % leave.pinstance.pk)
76 | self.assertEqual('Staff Leader', leave.pinstance.cur_node.name)
77 |
78 | def test_edit(self):
79 | self.client.login(username='tom', password='password')
80 |
81 | data = {
82 | 'start_on': '2017-04-19 09:01',
83 | 'end_on': '2017-04-20 09:01',
84 | 'leave_type': self.leave_type_vacation.pk,
85 | 'leave_days': '1',
86 | 'reason': 'test save',
87 | }
88 | url = reverse('wf_new', args=('leave', ))
89 | resp = self.client.post(url, data)
90 | leave = Leave.objects.get(reason='test save')
91 | self.assertRedirects(resp, '/wf/%s/' % leave.pinstance.pk)
92 | self.assertEqual('Draft', leave.pinstance.cur_node.name)
93 |
94 | url = reverse('wf_edit', args=(leave.pinstance.pk, ))
95 | resp = self.client.get(url)
96 | self.assertEqual(resp.status_code, 200)
97 |
98 | data['act_submit'] = 'Submit'
99 | data['reason'] = 'test submit'
100 | resp = self.client.post(url, data)
101 | leave = Leave.objects.get(reason='test submit')
102 | self.assertRedirects(resp, '/wf/%s/' % leave.pinstance.pk)
103 | self.assertEqual('Staff Leader', leave.pinstance.cur_node.name)
104 |
105 | def test_delete(self):
106 | self.client.login(username='admin', password='password')
107 | # POST
108 | url = reverse('wf_delete')
109 | leave = self.create_leave('to delete')
110 | data = {'pk': leave.pinstance.pk}
111 | resp = self.client.post(url, data)
112 | self.assertRedirects(resp, '/wf/list/')
113 | self.assertIsNone(self.get_leave('to delete'))
114 |
115 | # GET
116 | leave = self.create_leave('to delete')
117 | data = {'pk': leave.pinstance.pk}
118 | resp = self.client.get(url, data)
119 | self.assertRedirects(resp, '/wf/list/')
120 | self.assertIsNone(self.get_leave('to delete'))
121 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/views.py:
--------------------------------------------------------------------------------
1 | from lbworkflow.views.generics import CreateView
2 | from lbworkflow.views.generics import UpdateView
3 | from lbworkflow.views.generics import WFListView
4 |
5 | from .forms import LeaveForm
6 | from .models import Leave
7 |
8 |
9 | class LeaveCreateView(CreateView):
10 | form_classes = {
11 | 'form': LeaveForm,
12 | }
13 |
14 |
15 | new = LeaveCreateView.as_view()
16 |
17 |
18 | class LeaveUpdateView(UpdateView):
19 | form_classes = {
20 | 'form': LeaveForm,
21 | }
22 |
23 |
24 | edit = LeaveUpdateView.as_view()
25 |
26 |
27 | class LeaveListView(WFListView):
28 | wf_code = 'leave'
29 | model = Leave
30 | excel_file_name = 'leave'
31 | excel_titles = [
32 | 'Created on', 'Created by',
33 | 'Start on', 'End on', 'Leave days',
34 | 'Actual start on', 'Actual start on', 'Actual leave days',
35 | 'Status',
36 | ]
37 |
38 | def get_excel_data(self, o):
39 | return [
40 | o.created_by.username, o.created_on,
41 | o.start_on, o.end_on, o.leave_days,
42 | o.actual_start_on, o.actual_end_on, o.actual_leave_days,
43 | o.pinstance.cur_node.name,
44 | ]
45 |
46 |
47 | show_list = LeaveListView.as_view()
48 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/wf_views.py:
--------------------------------------------------------------------------------
1 | from lbworkflow.views.transition import ExecuteTransitionView
2 |
3 | from .forms import HRForm
4 |
5 |
6 | class CustomizedTransitionView(ExecuteTransitionView):
7 | form_classes = {
8 | 'form': HRForm
9 | }
10 |
11 |
12 | c = CustomizedTransitionView.as_view()
13 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/leave/wfdata.py:
--------------------------------------------------------------------------------
1 | from lbworkflow.core.datahelper import create_category
2 | from lbworkflow.core.datahelper import create_node
3 | from lbworkflow.core.datahelper import create_process
4 | from lbworkflow.core.datahelper import create_transition
5 |
6 | from carrot_box.param.models import create_param
7 | from carrot_box.param.models import create_param_type
8 |
9 |
10 | def load_data():
11 | load_params()
12 | load_leave()
13 |
14 |
15 | def load_params():
16 | leave_type = create_param_type('leave_type', name='Leave Type')
17 | create_param('5f31d065-00cc-0000-beea-641f0a670010',
18 | param_type=leave_type, name='Vacation')
19 | create_param('5f31d065-00cc-0000-beea-641f0a670020',
20 | param_type=leave_type, name='Sick')
21 |
22 |
23 | def load_leave():
24 | """ load_[wf_code] """
25 | category = create_category('5f31d065-00cc-0010-beea-641f0a670010', 'HR')
26 | process = create_process('leave', 'Leave', category=category)
27 |
28 | # Nodes
29 | create_node('5f31d065-00a0-0010-beea-641f0a670010', process, 'Draft', status='draft')
30 | create_node('5f31d065-00a0-0010-beea-641f0a670020', process, 'Given up', status='given up')
31 | create_node('5f31d065-00a0-0010-beea-641f0a670030', process, 'Rejected', status='rejected')
32 | create_node('5f31d065-00a0-0010-beea-641f0a670040', process, 'Completed', status='completed')
33 |
34 | create_node('5f31d065-00a0-0010-beea-641f0a670050', process,
35 | 'Staff Leader', operators='[o.created_by.leader]')
36 | create_node('5f31d065-00a0-0010-beea-641f0a670060', process,
37 | 'Department Leader', operators='[o.created_by.get_department().leader]')
38 | create_node('5f31d065-00a0-0010-beea-641f0a670065', process, 'HR', operators='r[hr]')
39 | create_node('5f31d065-00a0-0010-beea-641f0a670070', process, 'CEO', operators='[ceo]')
40 |
41 | # Transitions
42 | create_transition('5f31d065-00e0-0010-beea-641f0a670010', process,
43 | 'Draft', 'Staff Leader')
44 | create_transition('5f31d065-00e0-0010-beea-641f0a670020', process,
45 | 'Staff Leader', 'Department Leader')
46 |
47 | create_transition('5f31d065-00e0-0010-beea-641f0a670030', process,
48 | 'Department Leader', 'HR',
49 | condition='o.leave_days<7 # days<7')
50 | create_transition('5f31d065-00e0-0010-beea-641f0a670040', process,
51 | 'Department Leader', 'CEO',
52 | condition='o.leave_days>=7 # days>=7')
53 | create_transition('5f31d065-00e0-0010-beea-641f0a670045', process,
54 | 'CEO', 'HR')
55 |
56 | create_transition('5f31d065-00e0-0010-beea-641f0a670050', process,
57 | 'HR', 'Completed',
58 | app='Customized URL',
59 | app_param='wf_execute_transition {{wf_code}} c')
60 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/purchase/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/carrot_box/wfapp/purchase/__init__.py
--------------------------------------------------------------------------------
/carrot_box/wfapp/purchase/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from lbworkflow.models import BaseWFObj
3 |
4 |
5 | class Purchase(BaseWFObj):
6 | title = models.CharField('Title', max_length=255)
7 | reason = models.CharField('Reason', max_length=255)
8 |
9 | def __str__(self):
10 | return self.reason
11 |
12 |
13 | class Item(models.Model):
14 | purchase = models.ForeignKey(
15 | Purchase,
16 | on_delete=models.CASCADE,
17 | )
18 | name = models.CharField('Name', max_length=255)
19 | qty = models.IntegerField('Qty')
20 | note = models.CharField('Note', max_length=255)
21 |
22 | class Meta:
23 | verbose_name = 'Purchase Item'
24 |
25 | def __str__(self):
26 | return self.name
27 |
--------------------------------------------------------------------------------
/carrot_box/wfapp/purchase/wfdata.py:
--------------------------------------------------------------------------------
1 | from lbworkflow.core.datahelper import create_category
2 | from lbworkflow.core.datahelper import create_node
3 | from lbworkflow.core.datahelper import create_process
4 | from lbworkflow.core.datahelper import create_transition
5 |
6 |
7 | def load_data():
8 | load_issue()
9 |
10 |
11 | def load_issue():
12 | """ load_[wf_code] """
13 | category = create_category('5f31d065-00cc-0020-be00-641f0a670010', 'IT')
14 | process = create_process('purchase', 'Purchase', category=category)
15 | create_node('5f31d065-00a0-0030-beea-641f0a670010', process, 'Draft', status='draft')
16 | create_node('5f31d065-00a0-0030-beea-641f0a670020', process, 'Given up', status='given up')
17 | create_node('5f31d065-00a0-0030-beea-641f0a670030', process, 'Rejected', status='rejected')
18 | create_node('5f31d065-00a0-0030-beea-641f0a670040', process, 'Completed', status='completed')
19 | create_node('5f31d065-00a0-0030-beea-641f0a670050', process, 'IT', operators='[it]')
20 | create_transition('5f31d065-00e0-0030-beea-641f0a670010', process, 'Draft,', 'IT')
21 | create_transition('5f31d065-00e0-0030-beea-641f0a670020', process, 'IT,', 'Completed')
22 |
--------------------------------------------------------------------------------
/carrot_box/wfdata.py:
--------------------------------------------------------------------------------
1 | from lbworkflow.core.datahelper import create_category
2 | from lbworkflow.core.datahelper import create_node
3 | from lbworkflow.core.datahelper import create_process
4 | from lbworkflow.core.datahelper import create_transition
5 | from lbworkflow.core.datahelper import create_user
6 | from lbworkflow.core.datahelper import get_or_create
7 |
8 | from carrot_box.hr.models import CarrotDepartment
9 | from carrot_box.hr.models import CarrotRole
10 |
11 |
12 | def load_data():
13 | roles = load_roles()
14 | departments = load_departments()
15 | load_users(departments, roles)
16 | load_simplewf()
17 |
18 |
19 | def create_department(*args, **kwargs):
20 | return get_or_create(CarrotDepartment, *args, **kwargs)
21 |
22 |
23 | def load_departments():
24 | root = create_department('f1864b0e-da03-4900-9a3b-54362f611cf5', code='root', name='root', )
25 | hr = create_department('f1864b0e-da03-4901-9a3b-54362f611cf5', code='hr', name='hr', parent=root, )
26 | it = create_department('f1864b0e-da03-4902-9a3b-54362f611cf5', code='it', name='it', parent=root, )
27 | departments = {
28 | 'root': root,
29 | 'hr': hr,
30 | 'it': it,
31 | }
32 | return departments
33 |
34 |
35 | def create_role(*args, **kwargs):
36 | return get_or_create(CarrotRole, *args, **kwargs)
37 |
38 |
39 | def load_roles():
40 | it = create_role('f1864b0e-da02-4900-9a3b-54362f611cf5', code='it', name='it', )
41 | hr = create_role('f1864b0e-da02-4901-9a3b-54362f611cf5', code='hr', name='hr', )
42 | roles = {
43 | 'it': it,
44 | 'hr': hr,
45 | }
46 | return roles
47 |
48 |
49 | def load_users(departments, roles):
50 | ceo = create_user('ceo', department_id=departments['root'].pk)
51 | departments['root'].leader = ceo
52 | departments['root'].save()
53 |
54 | tom_leader = create_user('tom_leader', department_id=departments['it'].pk, leader=ceo)
55 | tom = create_user('tom', department_id=departments['it'].pk, leader=tom_leader)
56 |
57 | it_dept_leader = create_user('it_dept_leader', department_id=departments['it'].pk, leader=ceo)
58 | it_leader = create_user('it_leader', department_id=departments['it'].pk, leader=it_dept_leader)
59 | it = create_user('it', department_id=departments['it'].pk, leader=it_leader)
60 | departments['it'].leader = it_dept_leader
61 | departments['it'].save()
62 |
63 | hr_dept_leader = create_user('hr_dept_leader', department_id=departments['hr'].pk, leader=ceo)
64 | hr_leader = create_user('hr_leader', department_id=departments['hr'].pk, leader=hr_dept_leader)
65 | hr = create_user('hr', department_id=departments['hr'].pk, leader=hr_leader)
66 | departments['hr'].leader = hr_dept_leader
67 | departments['hr'].save()
68 |
69 | users = {
70 | 'tom': tom,
71 | 'tom_leader': tom_leader,
72 | 'it': it,
73 | 'it_leader': it_leader,
74 | 'it_dept_leader': it_dept_leader,
75 | 'hr': hr,
76 | 'hr_leader': hr_leader,
77 | 'hr_dept_leader': hr_dept_leader,
78 | 'ceo': ceo,
79 | 'admin': create_user('admin', department_id=departments['root'].pk,
80 | leader=ceo, is_superuser=True, is_staff=True),
81 | }
82 |
83 | roles['it'].users.add(it)
84 | roles['hr'].users.add(hr, hr_leader, hr_dept_leader)
85 | return users
86 |
87 |
88 | def load_simplewf():
89 | category = create_category('5f31d065-00cc-0020-be00-641f0a670010', 'IT')
90 |
91 | ext_data_buy_computer = {
92 | 'template': """Brand:
93 | Price:
94 | Other requirements:
95 | """
96 | }
97 | process = create_process('simplewf__buy_computer', 'Buy computer',
98 | category=category, ext_data=ext_data_buy_computer)
99 | # Nodes
100 | create_node('5f31d065-00a0-0010-be00-641f0a670010', process, 'Draft', status='draft')
101 | create_node('5f31d065-00a0-0010-be00-641f0a670020', process, 'Given up', status='given up')
102 | create_node('5f31d065-00a0-0010-be00-641f0a670030', process, 'Rejected', status='rejected')
103 | create_node('5f31d065-00a0-0010-be00-641f0a670040', process, 'Completed', status='completed')
104 | create_node('5f31d065-00a0-0010-be00-641f0a670060', process,
105 | 'Department Leader', operators='[o.created_by.get_department().leader]')
106 | create_node('5f31d065-00a0-0010-be00-641f0a670065', process, 'IT', operators='[it]')
107 |
108 | create_transition('5f31d667-0010-0020-be00-641f0a670010', process, 'Draft,', 'Department Leader')
109 | create_transition('5f31d667-0010-0020-be00-641f0a670020', process, 'Department Leader', 'IT')
110 | create_transition('5f31d667-0010-0020-be00-641f0a670030', process, 'IT,', 'Completed')
111 |
112 | ext_data_issue = {
113 | 'template': """From:
114 | Requirements:"""
115 | }
116 | process = create_process('simplewf__issue', 'Issue', category=category, ext_data=ext_data_issue)
117 | create_node('5f31d667-00a0-0020-be00-641f0a670010', process, 'Draft', status='draft')
118 | create_node('5f31d667-00a0-0020-be00-641f0a670020', process, 'Given up', status='given up')
119 | create_node('5f31d667-00a0-0020-be00-641f0a670030', process, 'Rejected', status='rejected')
120 | create_node('5f31d667-00a0-0020-be00-641f0a670040', process, 'Completed', status='completed')
121 | create_node('5f31d065-00a0-0020-be00-641f0a670060', process,
122 | 'IT Leader', operators='dept_direct_leaders d[it]')
123 | create_node('5f31d065-00a0-0020-be00-641f0a670070', process, 'IT', operators='[it]')
124 |
125 | create_transition('5f31d667-0020-0020-be00-641f0a670010', process, 'Draft,', 'IT Leader')
126 | create_transition('5f31d667-0020-0020-be00-641f0a670020', process, 'IT Leader', 'IT')
127 | create_transition('5f31d667-0020-0020-be00-641f0a670030', process, 'IT,', 'Completed')
128 |
--------------------------------------------------------------------------------
/carrot_box/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for carrot_box project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'carrot_box.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'carrot_box.settings')
9 | try:
10 | from django.core.management import execute_from_command_line
11 | except ImportError as exc:
12 | raise ImportError(
13 | "Couldn't import Django. Are you sure it's installed and "
14 | "available on your PYTHONPATH environment variable? Did you "
15 | "forget to activate a virtual environment?"
16 | ) from exc
17 | execute_from_command_line(sys.argv)
18 |
19 |
20 | if __name__ == '__main__':
21 | main()
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "admin-lte": "2.3.11",
4 | "blueimp-file-upload": "9.22.1",
5 | "flatpickr": "2.5.6",
6 | "font-awesome": "4.7.0",
7 | "html5shiv": "^3.7.3",
8 | "ionicons": "2.0.1",
9 | "masonry-layout": "^4.2.2",
10 | "mermaid": "^8.13.8",
11 | "modernizr": "^3.11.8",
12 | "respond": "^0.9.0",
13 | "selectivizr": "^1.0.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/screenshots/detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/screenshots/detail.png
--------------------------------------------------------------------------------
/screenshots/flowchart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/screenshots/flowchart.png
--------------------------------------------------------------------------------
/screenshots/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vicalloy/carrot-box/470e308f449a06234597c9c838cced69c6945945/screenshots/main.png
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | exclude = .tox/,*tox/*,docs/*,*/migrations/*
3 | ignore = E123,E128,E402,W503,E731,W601
4 | max-line-length = 119
5 |
6 | [isort]
7 | combine_as_imports = true
8 | default_section = THIRDPARTY
9 | include_trailing_comma = true
10 | known_first_party = carrot_box
11 | multi_line_output = 5
12 | not_skip = __init__.py
13 | skip=migrations
14 | force_single_line = true
15 | line_length = 119
16 |
17 | [bdist_wheel]
18 | universal=1
19 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist =
3 | py{36,37,38}-django{30,_trunk},
4 | flake8,isort
5 |
6 | skipsdist = True
7 |
8 |
9 | [testenv]
10 | commands =
11 | npm install
12 | coverage run {toxinidir}/manage.py test
13 |
14 | deps =
15 | django30: Django>=3.0,<3.1
16 | django_trunk: https://github.com/django/django/tarball/master
17 | -rrequirements.txt
18 |
19 | [testenv:flake8]
20 | basepython = python
21 | skip_install=true
22 | deps = flake8==3.7.9
23 | commands= flake8 {toxinidir}
24 |
25 | [testenv:isort]
26 | basepython = python
27 | deps = isort
28 | commands = isort --check-only --recursive carrot_box
29 |
--------------------------------------------------------------------------------
/wfgen.py:
--------------------------------------------------------------------------------
1 | import os
2 | import uuid
3 | import sys
4 |
5 | import django
6 | from django.core.management import call_command
7 | from lbworkflow.flowgen import FlowAppGenerator
8 | from lbworkflow.flowgen import clean_generated_files
9 |
10 |
11 | def gen():
12 | from carrot_box.wfapp.purchase.models import Purchase as wf_class
13 | from carrot_box.wfapp.purchase.models import Item as wf_item_class
14 | FlowAppGenerator().gen(wf_class, [wf_item_class], replace=True)
15 |
16 |
17 | def clean():
18 | from carrot_box.wfapp.purchase.models import Purchase
19 | clean_generated_files(Purchase)
20 |
21 |
22 | def load_data():
23 | from lbworkflow.core.datahelper import load_wf_data
24 | load_wf_data('carrot_box.wfapp.purchase')
25 |
26 |
27 | if __name__ == "__main__":
28 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
29 | sys.path.insert(0, BASE_DIR)
30 | os.environ['DJANGO_SETTINGS_MODULE'] = "carrot_box.settings"
31 | django.setup()
32 | if (len(sys.argv)) == 2:
33 | cmd = sys.argv[1]
34 | if cmd == 'clean':
35 | clean()
36 | elif cmd == 'uuid':
37 | print(str(uuid.uuid4()))
38 | elif cmd == "parse":
39 | from carrot_box.hr.userparser import CarrotBoxUserParser
40 | print(CarrotBoxUserParser("dept_direct_leaders d[it]").parse())
41 | sys.exit(0)
42 | gen()
43 | call_command('makemigrations', 'purchase')
44 | call_command('migrate')
45 | load_data()
46 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@braintree/sanitize-url@^3.1.0":
6 | version "3.1.0"
7 | resolved "https://registry.nlark.com/@braintree/sanitize-url/download/@braintree/sanitize-url-3.1.0.tgz#8ff71d51053cd5ee4981e5a501d80a536244f7fd"
8 | integrity sha1-j/cdUQU81e5JgeWlAdgKU2JE9/0=
9 |
10 | admin-lte@2.3.11:
11 | version "2.3.11"
12 | resolved "https://registry.nlark.com/admin-lte/download/admin-lte-2.3.11.tgz#da56dcd34d42e9ef1af362be15520a053a9d43db"
13 | integrity sha1-2lbc001C6e8a82K+FVIKBTqdQ9s=
14 |
15 | ansi-regex@^5.0.1:
16 | version "5.0.1"
17 | resolved "https://registry.nlark.com/ansi-regex/download/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
18 | integrity sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ=
19 |
20 | ansi-styles@^4.0.0:
21 | version "4.3.0"
22 | resolved "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
23 | integrity sha1-7dgDYornHATIWuegkG7a00tkiTc=
24 | dependencies:
25 | color-convert "^2.0.1"
26 |
27 | argparse@^1.0.7:
28 | version "1.0.10"
29 | resolved "https://registry.nlark.com/argparse/download/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
30 | integrity sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=
31 | dependencies:
32 | sprintf-js "~1.0.2"
33 |
34 | blueimp-canvas-to-blob@3.5.0:
35 | version "3.5.0"
36 | resolved "https://registry.yarnpkg.com/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.5.0.tgz#5679ac32f6a2835821f0c3ad661719ff85a9236b"
37 | integrity sha1-VnmsMvaig1gh8MOtZhcZ/4WpI2s=
38 |
39 | blueimp-file-upload@9.22.1:
40 | version "9.22.1"
41 | resolved "https://registry.yarnpkg.com/blueimp-file-upload/-/blueimp-file-upload-9.22.1.tgz#08a9fccbaf1ec930acf6242c217620b057f0ecc6"
42 | integrity sha512-ezGkn/agWUWZOw8mYa5yYC9LvUlrT5bN3zk2fPlpLWgyhbBMz8BSGKO3M48BWlXWAeR+lVtEhy9xiG8FLnHEVw==
43 | optionalDependencies:
44 | blueimp-canvas-to-blob "3.5.0"
45 | blueimp-load-image "2.12.2"
46 | blueimp-tmpl "3.6.0"
47 |
48 | blueimp-load-image@2.12.2:
49 | version "2.12.2"
50 | resolved "https://registry.yarnpkg.com/blueimp-load-image/-/blueimp-load-image-2.12.2.tgz#6a17598aab858d4fbf01543e0631141b51057c87"
51 | integrity sha1-ahdZiquFjU+/AVQ+BjEUG1EFfIc=
52 |
53 | blueimp-tmpl@3.6.0:
54 | version "3.6.0"
55 | resolved "https://registry.yarnpkg.com/blueimp-tmpl/-/blueimp-tmpl-3.6.0.tgz#a4910975d042e2bc03ba77f0e62d04f1548a524c"
56 | integrity sha1-pJEJddBC4rwDunfw5i0E8VSKUkw=
57 |
58 | camelcase@^5.0.0:
59 | version "5.3.1"
60 | resolved "https://registry.npmmirror.com/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1636945130104&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
61 | integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=
62 |
63 | cliui@^6.0.0:
64 | version "6.0.0"
65 | resolved "https://registry.nlark.com/cliui/download/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
66 | integrity sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE=
67 | dependencies:
68 | string-width "^4.2.0"
69 | strip-ansi "^6.0.0"
70 | wrap-ansi "^6.2.0"
71 |
72 | color-convert@^2.0.1:
73 | version "2.0.1"
74 | resolved "https://registry.nlark.com/color-convert/download/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
75 | integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=
76 | dependencies:
77 | color-name "~1.1.4"
78 |
79 | color-name@~1.1.4:
80 | version "1.1.4"
81 | resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
82 | integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=
83 |
84 | commander@2:
85 | version "2.20.3"
86 | resolved "https://registry.npmmirror.com/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1634886357672&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
87 | integrity sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=
88 |
89 | commander@7:
90 | version "7.2.0"
91 | resolved "https://registry.npmmirror.com/commander/download/commander-7.2.0.tgz?cache=0&sync_timestamp=1634886357672&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcommander%2Fdownload%2Fcommander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
92 | integrity sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc=
93 |
94 | d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0:
95 | version "1.2.4"
96 | resolved "https://registry.npmmirror.com/d3-array/download/d3-array-1.2.4.tgz?cache=0&sync_timestamp=1633231313339&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fd3-array%2Fdownload%2Fd3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
97 | integrity sha1-Y1zk1e6nWfb2BYY9vPww7cc39x8=
98 |
99 | "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3:
100 | version "3.1.1"
101 | resolved "https://registry.npmmirror.com/d3-array/download/d3-array-3.1.1.tgz?cache=0&sync_timestamp=1633231313339&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fd3-array%2Fdownload%2Fd3-array-3.1.1.tgz#7797eb53ead6b9083c75a45a681e93fc41bc468c"
102 | integrity sha1-d5frU+rWuQg8daRaaB6T/EG8Row=
103 | dependencies:
104 | internmap "1 - 2"
105 |
106 | d3-axis@1:
107 | version "1.0.12"
108 | resolved "https://registry.nlark.com/d3-axis/download/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9"
109 | integrity sha1-zfILohDPu0N5WvM3Vohvs2ONqsk=
110 |
111 | d3-axis@3:
112 | version "3.0.0"
113 | resolved "https://registry.nlark.com/d3-axis/download/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322"
114 | integrity sha1-xCpKE+gTHWN7dF/Clzgkz+r5MyI=
115 |
116 | d3-brush@1:
117 | version "1.1.6"
118 | resolved "https://registry.nlark.com/d3-brush/download/d3-brush-1.1.6.tgz#b0a22c7372cabec128bdddf9bddc058592f89e9b"
119 | integrity sha1-sKIsc3LKvsEovd35vdwFhZL4nps=
120 | dependencies:
121 | d3-dispatch "1"
122 | d3-drag "1"
123 | d3-interpolate "1"
124 | d3-selection "1"
125 | d3-transition "1"
126 |
127 | d3-brush@3:
128 | version "3.0.0"
129 | resolved "https://registry.nlark.com/d3-brush/download/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c"
130 | integrity sha1-b3Z8Ttjct53n7ePhwPieY+9k0xw=
131 | dependencies:
132 | d3-dispatch "1 - 3"
133 | d3-drag "2 - 3"
134 | d3-interpolate "1 - 3"
135 | d3-selection "3"
136 | d3-transition "3"
137 |
138 | d3-chord@1:
139 | version "1.0.6"
140 | resolved "https://registry.nlark.com/d3-chord/download/d3-chord-1.0.6.tgz#309157e3f2db2c752f0280fedd35f2067ccbb15f"
141 | integrity sha1-MJFX4/LbLHUvAoD+3TXyBnzLsV8=
142 | dependencies:
143 | d3-array "1"
144 | d3-path "1"
145 |
146 | d3-chord@3:
147 | version "3.0.1"
148 | resolved "https://registry.nlark.com/d3-chord/download/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966"
149 | integrity sha1-0VbWH0hfzoMn5qvzOctB2Mu6aWY=
150 | dependencies:
151 | d3-path "1 - 3"
152 |
153 | d3-collection@1:
154 | version "1.0.7"
155 | resolved "https://registry.npm.taobao.org/d3-collection/download/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e"
156 | integrity sha1-NJvSqpl32wcQkcExRNXk8WtbMQ4=
157 |
158 | d3-color@1:
159 | version "1.4.1"
160 | resolved "https://registry.nlark.com/d3-color/download/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a"
161 | integrity sha1-xSACv4hGraRCTVXZeYL+8m6zvIo=
162 |
163 | "d3-color@1 - 3", d3-color@3:
164 | version "3.0.1"
165 | resolved "https://registry.nlark.com/d3-color/download/d3-color-3.0.1.tgz#03316e595955d1fcd39d9f3610ad41bb90194d0a"
166 | integrity sha1-AzFuWVlV0fzTnZ82EK1Bu5AZTQo=
167 |
168 | d3-contour@1:
169 | version "1.3.2"
170 | resolved "https://registry.nlark.com/d3-contour/download/d3-contour-1.3.2.tgz#652aacd500d2264cb3423cee10db69f6f59bead3"
171 | integrity sha1-ZSqs1QDSJkyzQjzuENtp9vWb6tM=
172 | dependencies:
173 | d3-array "^1.1.1"
174 |
175 | d3-contour@3:
176 | version "3.0.1"
177 | resolved "https://registry.nlark.com/d3-contour/download/d3-contour-3.0.1.tgz#2c64255d43059599cd0dba8fe4cc3d51ccdd9bbd"
178 | integrity sha1-LGQlXUMFlZnNDbqP5Mw9Uczdm70=
179 | dependencies:
180 | d3-array "2 - 3"
181 |
182 | d3-delaunay@6:
183 | version "6.0.2"
184 | resolved "https://registry.nlark.com/d3-delaunay/download/d3-delaunay-6.0.2.tgz#7fd3717ad0eade2fc9939f4260acfb503f984e92"
185 | integrity sha1-f9NxetDq3i/Jk59CYKz7UD+YTpI=
186 | dependencies:
187 | delaunator "5"
188 |
189 | d3-dispatch@1:
190 | version "1.0.6"
191 | resolved "https://registry.nlark.com/d3-dispatch/download/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58"
192 | integrity sha1-ANN7zuTdjNl3Kd2JOgrCnKq6XVg=
193 |
194 | "d3-dispatch@1 - 3", d3-dispatch@3:
195 | version "3.0.1"
196 | resolved "https://registry.nlark.com/d3-dispatch/download/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e"
197 | integrity sha1-X8dShOnCN1w2yDlBGgz1UMv8TV4=
198 |
199 | d3-drag@1:
200 | version "1.2.5"
201 | resolved "https://registry.nlark.com/d3-drag/download/d3-drag-1.2.5.tgz?cache=0&sync_timestamp=1623254998807&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fd3-drag%2Fdownload%2Fd3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70"
202 | integrity sha1-JTf0UazTnTFAZne33HfIL32Yj3A=
203 | dependencies:
204 | d3-dispatch "1"
205 | d3-selection "1"
206 |
207 | "d3-drag@2 - 3", d3-drag@3:
208 | version "3.0.0"
209 | resolved "https://registry.nlark.com/d3-drag/download/d3-drag-3.0.0.tgz?cache=0&sync_timestamp=1623254998807&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fd3-drag%2Fdownload%2Fd3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba"
210 | integrity sha1-mUqunNI8cZ9TteEOOgphCMaWB7o=
211 | dependencies:
212 | d3-dispatch "1 - 3"
213 | d3-selection "3"
214 |
215 | d3-dsv@1:
216 | version "1.2.0"
217 | resolved "https://registry.nlark.com/d3-dsv/download/d3-dsv-1.2.0.tgz#9d5f75c3a5f8abd611f74d3f5847b0d4338b885c"
218 | integrity sha1-nV91w6X4q9YR900/WEew1DOLiFw=
219 | dependencies:
220 | commander "2"
221 | iconv-lite "0.4"
222 | rw "1"
223 |
224 | "d3-dsv@1 - 3", d3-dsv@3:
225 | version "3.0.1"
226 | resolved "https://registry.nlark.com/d3-dsv/download/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73"
227 | integrity sha1-xjr5ePTWoNCEpSpnOSK+IWB4m3M=
228 | dependencies:
229 | commander "7"
230 | iconv-lite "0.6"
231 | rw "1"
232 |
233 | d3-ease@1:
234 | version "1.0.7"
235 | resolved "https://registry.nlark.com/d3-ease/download/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2"
236 | integrity sha1-moNIkO+LiujFWLL+Vb1X9Zk7heI=
237 |
238 | "d3-ease@1 - 3", d3-ease@3:
239 | version "3.0.1"
240 | resolved "https://registry.nlark.com/d3-ease/download/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
241 | integrity sha1-llisOKIUDVnTRhYPH2ww/aC9EvQ=
242 |
243 | d3-fetch@1:
244 | version "1.2.0"
245 | resolved "https://registry.nlark.com/d3-fetch/download/d3-fetch-1.2.0.tgz#15ce2ecfc41b092b1db50abd2c552c2316cf7fc7"
246 | integrity sha1-Fc4uz8QbCSsdtQq9LFUsIxbPf8c=
247 | dependencies:
248 | d3-dsv "1"
249 |
250 | d3-fetch@3:
251 | version "3.0.1"
252 | resolved "https://registry.nlark.com/d3-fetch/download/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22"
253 | integrity sha1-gxQb/5hWoO21443onNz+Y9CmCiI=
254 | dependencies:
255 | d3-dsv "1 - 3"
256 |
257 | d3-force@1:
258 | version "1.2.1"
259 | resolved "https://registry.nlark.com/d3-force/download/d3-force-1.2.1.tgz#fd29a5d1ff181c9e7f0669e4bd72bdb0e914ec0b"
260 | integrity sha1-/Sml0f8YHJ5/BmnkvXK9sOkU7As=
261 | dependencies:
262 | d3-collection "1"
263 | d3-dispatch "1"
264 | d3-quadtree "1"
265 | d3-timer "1"
266 |
267 | d3-force@3:
268 | version "3.0.0"
269 | resolved "https://registry.nlark.com/d3-force/download/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4"
270 | integrity sha1-Piuhph5wiI/j2RlOMNbRTuzhVcQ=
271 | dependencies:
272 | d3-dispatch "1 - 3"
273 | d3-quadtree "1 - 3"
274 | d3-timer "1 - 3"
275 |
276 | d3-format@1:
277 | version "1.4.5"
278 | resolved "https://registry.npmmirror.com/d3-format/download/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
279 | integrity sha1-N08roTIONxfrdKk1bGfa7hen7bQ=
280 |
281 | "d3-format@1 - 3", d3-format@3:
282 | version "3.1.0"
283 | resolved "https://registry.npmmirror.com/d3-format/download/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
284 | integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
285 |
286 | d3-geo@1:
287 | version "1.12.1"
288 | resolved "https://registry.nlark.com/d3-geo/download/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f"
289 | integrity sha1-f8KrdBS3Lln7y9YD6A2a3AKbA18=
290 | dependencies:
291 | d3-array "1"
292 |
293 | d3-geo@3:
294 | version "3.0.1"
295 | resolved "https://registry.nlark.com/d3-geo/download/d3-geo-3.0.1.tgz#4f92362fd8685d93e3b1fae0fd97dc8980b1ed7e"
296 | integrity sha1-T5I2L9hoXZPjsfrg/ZfciYCx7X4=
297 | dependencies:
298 | d3-array "2.5.0 - 3"
299 |
300 | d3-hierarchy@1:
301 | version "1.1.9"
302 | resolved "https://registry.npmmirror.com/d3-hierarchy/download/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83"
303 | integrity sha1-L2vuJMqupD+Nw3VF+gFihVlkeoM=
304 |
305 | d3-hierarchy@3:
306 | version "3.1.1"
307 | resolved "https://registry.npmmirror.com/d3-hierarchy/download/d3-hierarchy-3.1.1.tgz#9cbb0ffd2375137a351e6cfeed344a06d4ff4597"
308 | integrity sha512-LtAIu54UctRmhGKllleflmHalttH3zkfSi4NlKrTAoFKjC+AFBJohsCAdgCBYQwH0F8hIOGY89X1pPqAchlMkA==
309 |
310 | d3-interpolate@1:
311 | version "1.4.0"
312 | resolved "https://registry.nlark.com/d3-interpolate/download/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987"
313 | integrity sha1-Um554tgNqjg/ngwcHH3MDwWD6Yc=
314 | dependencies:
315 | d3-color "1"
316 |
317 | "d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3:
318 | version "3.0.1"
319 | resolved "https://registry.nlark.com/d3-interpolate/download/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
320 | integrity sha1-PEeqWzLFs9+1bvP9Q0IHimMrQA0=
321 | dependencies:
322 | d3-color "1 - 3"
323 |
324 | d3-path@1:
325 | version "1.0.9"
326 | resolved "https://registry.nlark.com/d3-path/download/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf"
327 | integrity sha1-SMBQux/owmJJOoyvVSTj6VkXAc8=
328 |
329 | "d3-path@1 - 3", d3-path@3:
330 | version "3.0.1"
331 | resolved "https://registry.nlark.com/d3-path/download/d3-path-3.0.1.tgz#f09dec0aaffd770b7995f1a399152bf93052321e"
332 | integrity sha1-8J3sCq/9dwt5lfGjmRUr+TBSMh4=
333 |
334 | d3-polygon@1:
335 | version "1.0.6"
336 | resolved "https://registry.nlark.com/d3-polygon/download/d3-polygon-1.0.6.tgz#0bf8cb8180a6dc107f518ddf7975e12abbfbd38e"
337 | integrity sha1-C/jLgYCm3BB/UY3feXXhKrv7044=
338 |
339 | d3-polygon@3:
340 | version "3.0.1"
341 | resolved "https://registry.nlark.com/d3-polygon/download/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398"
342 | integrity sha1-C0XT3RxIopyOBX5hNWk+yAvxY5g=
343 |
344 | d3-quadtree@1:
345 | version "1.0.7"
346 | resolved "https://registry.nlark.com/d3-quadtree/download/d3-quadtree-1.0.7.tgz#ca8b84df7bb53763fe3c2f24bd435137f4e53135"
347 | integrity sha1-youE33u1N2P+PC8kvUNRN/TlMTU=
348 |
349 | "d3-quadtree@1 - 3", d3-quadtree@3:
350 | version "3.0.1"
351 | resolved "https://registry.nlark.com/d3-quadtree/download/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f"
352 | integrity sha1-bco+i+Kzk8mp1RTau9gKkt7vGk8=
353 |
354 | d3-random@1:
355 | version "1.1.2"
356 | resolved "https://registry.nlark.com/d3-random/download/d3-random-1.1.2.tgz#2833be7c124360bf9e2d3fd4f33847cfe6cab291"
357 | integrity sha1-KDO+fBJDYL+eLT/U8zhHz+bKspE=
358 |
359 | d3-random@3:
360 | version "3.0.1"
361 | resolved "https://registry.nlark.com/d3-random/download/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4"
362 | integrity sha1-1JJjeNMz2cC/0eb6AZTTCuuqIPQ=
363 |
364 | d3-scale-chromatic@1:
365 | version "1.5.0"
366 | resolved "https://registry.nlark.com/d3-scale-chromatic/download/d3-scale-chromatic-1.5.0.tgz#54e333fc78212f439b14641fb55801dd81135a98"
367 | integrity sha1-VOMz/HghL0ObFGQftVgB3YETWpg=
368 | dependencies:
369 | d3-color "1"
370 | d3-interpolate "1"
371 |
372 | d3-scale-chromatic@3:
373 | version "3.0.0"
374 | resolved "https://registry.nlark.com/d3-scale-chromatic/download/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a"
375 | integrity sha1-FbTOuMorsNy20aZB7gPVnDtiN2o=
376 | dependencies:
377 | d3-color "1 - 3"
378 | d3-interpolate "1 - 3"
379 |
380 | d3-scale@2:
381 | version "2.2.2"
382 | resolved "https://registry.npmmirror.com/d3-scale/download/d3-scale-2.2.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fd3-scale%2Fdownload%2Fd3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f"
383 | integrity sha1-TogOCydFrKrd0+3iap6Qip4XuB8=
384 | dependencies:
385 | d3-array "^1.2.0"
386 | d3-collection "1"
387 | d3-format "1"
388 | d3-interpolate "1"
389 | d3-time "1"
390 | d3-time-format "2"
391 |
392 | d3-scale@4:
393 | version "4.0.2"
394 | resolved "https://registry.npmmirror.com/d3-scale/download/d3-scale-4.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fd3-scale%2Fdownload%2Fd3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
395 | integrity sha1-grOOjo/3CAdk+Nzsd71L45Nok5Y=
396 | dependencies:
397 | d3-array "2.10.0 - 3"
398 | d3-format "1 - 3"
399 | d3-interpolate "1.2.0 - 3"
400 | d3-time "2.1.1 - 3"
401 | d3-time-format "2 - 4"
402 |
403 | d3-selection@1, d3-selection@^1.1.0:
404 | version "1.4.2"
405 | resolved "https://registry.nlark.com/d3-selection/download/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c"
406 | integrity sha1-3KpJUiwNvzLWwYWK/Ca2CUVVvFw=
407 |
408 | "d3-selection@2 - 3", d3-selection@3:
409 | version "3.0.0"
410 | resolved "https://registry.nlark.com/d3-selection/download/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31"
411 | integrity sha1-wlM4IH76csxbm9FFihpBkB8eGzE=
412 |
413 | d3-shape@1:
414 | version "1.3.7"
415 | resolved "https://registry.nlark.com/d3-shape/download/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7"
416 | integrity sha1-32OAG+B7yYa8VPY3ibT+UCmStdc=
417 | dependencies:
418 | d3-path "1"
419 |
420 | d3-shape@3:
421 | version "3.0.1"
422 | resolved "https://registry.nlark.com/d3-shape/download/d3-shape-3.0.1.tgz#9ccdfb28fd9b0d12f2d8aec234cd5c4a9ea27931"
423 | integrity sha1-nM37KP2bDRLy2K7CNM1cSp6ieTE=
424 | dependencies:
425 | d3-path "1 - 3"
426 |
427 | d3-time-format@2:
428 | version "2.3.0"
429 | resolved "https://registry.npmmirror.com/d3-time-format/download/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850"
430 | integrity sha1-EHvcAoZneIqJJLoED68fvM1aeFA=
431 | dependencies:
432 | d3-time "1"
433 |
434 | "d3-time-format@2 - 4", d3-time-format@4:
435 | version "4.1.0"
436 | resolved "https://registry.npmmirror.com/d3-time-format/download/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a"
437 | integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==
438 | dependencies:
439 | d3-time "1 - 3"
440 |
441 | d3-time@1:
442 | version "1.1.0"
443 | resolved "https://registry.nlark.com/d3-time/download/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1"
444 | integrity sha1-seGdMH2unJALflsl/8XcwkmooPE=
445 |
446 | "d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3:
447 | version "3.0.0"
448 | resolved "https://registry.nlark.com/d3-time/download/d3-time-3.0.0.tgz#65972cb98ae2d4954ef5c932e8704061335d4975"
449 | integrity sha1-ZZcsuYri1JVO9cky6HBAYTNdSXU=
450 | dependencies:
451 | d3-array "2 - 3"
452 |
453 | d3-timer@1:
454 | version "1.0.10"
455 | resolved "https://registry.nlark.com/d3-timer/download/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5"
456 | integrity sha1-3+dripF0iDGxO22ceT/71QjdneU=
457 |
458 | "d3-timer@1 - 3", d3-timer@3:
459 | version "3.0.1"
460 | resolved "https://registry.nlark.com/d3-timer/download/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
461 | integrity sha1-YoTSonCChbGrt+IB7aQ4CvNeY7A=
462 |
463 | d3-transition@1:
464 | version "1.3.2"
465 | resolved "https://registry.nlark.com/d3-transition/download/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398"
466 | integrity sha1-qY7yFRvo2GAFQ0NMHKgBQK4js5g=
467 | dependencies:
468 | d3-color "1"
469 | d3-dispatch "1"
470 | d3-ease "1"
471 | d3-interpolate "1"
472 | d3-selection "^1.1.0"
473 | d3-timer "1"
474 |
475 | "d3-transition@2 - 3", d3-transition@3:
476 | version "3.0.1"
477 | resolved "https://registry.nlark.com/d3-transition/download/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f"
478 | integrity sha1-aGn93hRIhoB3/dWYkgDLYbKhZF8=
479 | dependencies:
480 | d3-color "1 - 3"
481 | d3-dispatch "1 - 3"
482 | d3-ease "1 - 3"
483 | d3-interpolate "1 - 3"
484 | d3-timer "1 - 3"
485 |
486 | d3-voronoi@1:
487 | version "1.1.4"
488 | resolved "https://registry.npm.taobao.org/d3-voronoi/download/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297"
489 | integrity sha1-3Tx412U9K7NZKErkeGRdlZRMgpc=
490 |
491 | d3-zoom@1:
492 | version "1.8.3"
493 | resolved "https://registry.nlark.com/d3-zoom/download/d3-zoom-1.8.3.tgz#b6a3dbe738c7763121cd05b8a7795ffe17f4fc0a"
494 | integrity sha1-tqPb5zjHdjEhzQW4p3lf/hf0/Ao=
495 | dependencies:
496 | d3-dispatch "1"
497 | d3-drag "1"
498 | d3-interpolate "1"
499 | d3-selection "1"
500 | d3-transition "1"
501 |
502 | d3-zoom@3:
503 | version "3.0.0"
504 | resolved "https://registry.nlark.com/d3-zoom/download/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3"
505 | integrity sha1-0T9BZccyF//qpUKVzWlps+eu6PM=
506 | dependencies:
507 | d3-dispatch "1 - 3"
508 | d3-drag "2 - 3"
509 | d3-interpolate "1 - 3"
510 | d3-selection "2 - 3"
511 | d3-transition "2 - 3"
512 |
513 | d3@^5.14:
514 | version "5.16.0"
515 | resolved "https://registry.npmmirror.com/d3/download/d3-5.16.0.tgz#9c5e8d3b56403c79d4ed42fbd62f6113f199c877"
516 | integrity sha1-nF6NO1ZAPHnU7UL71i9hE/GZyHc=
517 | dependencies:
518 | d3-array "1"
519 | d3-axis "1"
520 | d3-brush "1"
521 | d3-chord "1"
522 | d3-collection "1"
523 | d3-color "1"
524 | d3-contour "1"
525 | d3-dispatch "1"
526 | d3-drag "1"
527 | d3-dsv "1"
528 | d3-ease "1"
529 | d3-fetch "1"
530 | d3-force "1"
531 | d3-format "1"
532 | d3-geo "1"
533 | d3-hierarchy "1"
534 | d3-interpolate "1"
535 | d3-path "1"
536 | d3-polygon "1"
537 | d3-quadtree "1"
538 | d3-random "1"
539 | d3-scale "2"
540 | d3-scale-chromatic "1"
541 | d3-selection "1"
542 | d3-shape "1"
543 | d3-time "1"
544 | d3-time-format "2"
545 | d3-timer "1"
546 | d3-transition "1"
547 | d3-voronoi "1"
548 | d3-zoom "1"
549 |
550 | d3@^7.0.0:
551 | version "7.2.1"
552 | resolved "https://registry.npmmirror.com/d3/download/d3-7.2.1.tgz#97eafaa6fc8cd7c564c3ace1e6678cbecf63f3ea"
553 | integrity sha512-E/5sP0aeK6YPXI/+4QlefvBFgmcyR2jYftId0PrYWv4Y/gW3c3thp1XG4rQzF0eUwV9tR1x05X5eWuJ6rQXvew==
554 | dependencies:
555 | d3-array "3"
556 | d3-axis "3"
557 | d3-brush "3"
558 | d3-chord "3"
559 | d3-color "3"
560 | d3-contour "3"
561 | d3-delaunay "6"
562 | d3-dispatch "3"
563 | d3-drag "3"
564 | d3-dsv "3"
565 | d3-ease "3"
566 | d3-fetch "3"
567 | d3-force "3"
568 | d3-format "3"
569 | d3-geo "3"
570 | d3-hierarchy "3"
571 | d3-interpolate "3"
572 | d3-path "3"
573 | d3-polygon "3"
574 | d3-quadtree "3"
575 | d3-random "3"
576 | d3-scale "4"
577 | d3-scale-chromatic "3"
578 | d3-selection "3"
579 | d3-shape "3"
580 | d3-time "3"
581 | d3-time-format "4"
582 | d3-timer "3"
583 | d3-transition "3"
584 | d3-zoom "3"
585 |
586 | dagre-d3@^0.6.4:
587 | version "0.6.4"
588 | resolved "https://registry.npm.taobao.org/dagre-d3/download/dagre-d3-0.6.4.tgz#0728d5ce7f177ca2337df141ceb60fbe6eeb7b29"
589 | integrity sha1-ByjVzn8XfKIzffFBzrYPvm7reyk=
590 | dependencies:
591 | d3 "^5.14"
592 | dagre "^0.8.5"
593 | graphlib "^2.1.8"
594 | lodash "^4.17.15"
595 |
596 | dagre@^0.8.5:
597 | version "0.8.5"
598 | resolved "https://registry.npm.taobao.org/dagre/download/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee"
599 | integrity sha1-ujCwBV2sErbB/MJHgXRCd30Gr+4=
600 | dependencies:
601 | graphlib "^2.1.8"
602 | lodash "^4.17.15"
603 |
604 | decamelize@^1.2.0:
605 | version "1.2.0"
606 | resolved "https://registry.npmmirror.com/decamelize/download/decamelize-1.2.0.tgz?cache=0&sync_timestamp=1633055760479&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdecamelize%2Fdownload%2Fdecamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
607 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
608 |
609 | delaunator@5:
610 | version "5.0.0"
611 | resolved "https://registry.npm.taobao.org/delaunator/download/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b"
612 | integrity sha1-YPBSsovZHJtFZoUOv3dW7+gh2Bs=
613 | dependencies:
614 | robust-predicates "^3.0.0"
615 |
616 | desandro-matches-selector@^2.0.0:
617 | version "2.0.2"
618 | resolved "https://registry.npm.taobao.org/desandro-matches-selector/download/desandro-matches-selector-2.0.2.tgz#717beed4dc13e7d8f3762f707a6d58a6774218e1"
619 | integrity sha1-cXvu1NwT59jzdi9wem1YpndCGOE=
620 |
621 | doctrine@^3.0.0:
622 | version "3.0.0"
623 | resolved "https://registry.nlark.com/doctrine/download/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
624 | integrity sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=
625 | dependencies:
626 | esutils "^2.0.2"
627 |
628 | dompurify@2.3.4:
629 | version "2.3.4"
630 | resolved "https://registry.npmmirror.com/dompurify/download/dompurify-2.3.4.tgz#1cf5cf0105ccb4debdf6db162525bd41e6ddacc6"
631 | integrity sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ==
632 |
633 | emoji-regex@^8.0.0:
634 | version "8.0.0"
635 | resolved "https://registry.npmmirror.com/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1632751333727&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
636 | integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=
637 |
638 | entities@~2.0.0:
639 | version "2.0.3"
640 | resolved "https://registry.nlark.com/entities/download/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
641 | integrity sha1-XEh+V0Krk8Fau12iJ1m4WQ7AO38=
642 |
643 | esutils@^2.0.2:
644 | version "2.0.3"
645 | resolved "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
646 | integrity sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=
647 |
648 | ev-emitter@^1.0.0:
649 | version "1.1.1"
650 | resolved "https://registry.npm.taobao.org/ev-emitter/download/ev-emitter-1.1.1.tgz#8f18b0ce5c76a5d18017f71c0a795c65b9138f2a"
651 | integrity sha1-jxiwzlx2pdGAF/ccCnlcZbkTjyo=
652 |
653 | file@^0.2.2:
654 | version "0.2.2"
655 | resolved "https://registry.npm.taobao.org/file/download/file-0.2.2.tgz#c3dfd8f8cf3535ae455c2b423c2e52635d76b4d3"
656 | integrity sha1-w9/Y+M81Na5FXCtCPC5SY112tNM=
657 |
658 | find-up@^4.1.0:
659 | version "4.1.0"
660 | resolved "https://registry.npmmirror.com/find-up/download/find-up-4.1.0.tgz?cache=0&sync_timestamp=1633620747957&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ffind-up%2Fdownload%2Ffind-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
661 | integrity sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=
662 | dependencies:
663 | locate-path "^5.0.0"
664 | path-exists "^4.0.0"
665 |
666 | fizzy-ui-utils@^2.0.0:
667 | version "2.0.7"
668 | resolved "https://registry.npm.taobao.org/fizzy-ui-utils/download/fizzy-ui-utils-2.0.7.tgz#7df45dcc4eb374a08b65d39bb9a4beedf7330505"
669 | integrity sha1-ffRdzE6zdKCLZdObuaS+7fczBQU=
670 | dependencies:
671 | desandro-matches-selector "^2.0.0"
672 |
673 | flatpickr@2.5.6:
674 | version "2.5.6"
675 | resolved "https://registry.nlark.com/flatpickr/download/flatpickr-2.5.6.tgz#79349de3d6685305a7b764d66c3cc0f8b05d9bb7"
676 | integrity sha1-eTSd49ZoUwWnt2TWbDzA+LBdm7c=
677 |
678 | font-awesome@4.7.0:
679 | version "4.7.0"
680 | resolved "https://registry.npm.taobao.org/font-awesome/download/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
681 | integrity sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=
682 |
683 | get-caller-file@^2.0.1:
684 | version "2.0.5"
685 | resolved "https://registry.nlark.com/get-caller-file/download/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
686 | integrity sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=
687 |
688 | get-size@^2.0.2:
689 | version "2.0.3"
690 | resolved "https://registry.npm.taobao.org/get-size/download/get-size-2.0.3.tgz#54a1d0256b20ea7ac646516756202769941ad2ef"
691 | integrity sha1-VKHQJWsg6nrGRlFnViAnaZQa0u8=
692 |
693 | graphlib@^2.1.8:
694 | version "2.1.8"
695 | resolved "https://registry.npm.taobao.org/graphlib/download/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da"
696 | integrity sha1-V2HUFHN4cAhMkux7XbywWSydNdo=
697 | dependencies:
698 | lodash "^4.17.15"
699 |
700 | html5shiv@^3.7.3:
701 | version "3.7.3"
702 | resolved "https://registry.npm.taobao.org/html5shiv/download/html5shiv-3.7.3.tgz#d78a84a367bcb9a710100d57802c387b084631d2"
703 | integrity sha1-14qEo2e8uacQEA1XgCw4ewhGMdI=
704 |
705 | iconv-lite@0.4:
706 | version "0.4.24"
707 | resolved "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
708 | integrity sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=
709 | dependencies:
710 | safer-buffer ">= 2.1.2 < 3"
711 |
712 | iconv-lite@0.6:
713 | version "0.6.3"
714 | resolved "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
715 | integrity sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=
716 | dependencies:
717 | safer-buffer ">= 2.1.2 < 3.0.0"
718 |
719 | "internmap@1 - 2":
720 | version "2.0.3"
721 | resolved "https://registry.nlark.com/internmap/download/internmap-2.0.3.tgz?cache=0&sync_timestamp=1632107515842&other_urls=https%3A%2F%2Fregistry.nlark.com%2Finternmap%2Fdownload%2Finternmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
722 | integrity sha1-ZoXyN1XkPFJOJR0py8lySOMGEAk=
723 |
724 | ionicons@2.0.1:
725 | version "2.0.1"
726 | resolved "https://registry.npmmirror.com/ionicons/download/ionicons-2.0.1.tgz#ca398113293ea870244f538f0aabbd4b5b209a3e"
727 | integrity sha1-yjmBEyk+qHAkT1OPCqu9S1sgmj4=
728 |
729 | is-fullwidth-code-point@^3.0.0:
730 | version "3.0.0"
731 | resolved "https://registry.nlark.com/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
732 | integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=
733 |
734 | khroma@^1.4.1:
735 | version "1.4.1"
736 | resolved "https://registry.npm.taobao.org/khroma/download/khroma-1.4.1.tgz#ad6a5b6a972befc5112ce5129887a1a83af2c003"
737 | integrity sha1-rWpbapcr78URLOUSmIehqDrywAM=
738 |
739 | linkify-it@^2.0.0:
740 | version "2.2.0"
741 | resolved "https://registry.npmmirror.com/linkify-it/download/linkify-it-2.2.0.tgz?cache=0&sync_timestamp=1633116216426&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Flinkify-it%2Fdownload%2Flinkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
742 | integrity sha1-47VGl+eL+RXHCjis14/QngBYsc8=
743 | dependencies:
744 | uc.micro "^1.0.1"
745 |
746 | locate-path@^5.0.0:
747 | version "5.0.0"
748 | resolved "https://registry.nlark.com/locate-path/download/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
749 | integrity sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=
750 | dependencies:
751 | p-locate "^4.1.0"
752 |
753 | lodash@^4.17.15, lodash@^4.17.21:
754 | version "4.17.21"
755 | resolved "https://registry.nlark.com/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1618847150612&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flodash%2Fdownload%2Flodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
756 | integrity sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=
757 |
758 | markdown-it@^10.0.0:
759 | version "10.0.0"
760 | resolved "https://registry.npmmirror.com/markdown-it/download/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc"
761 | integrity sha1-q/xk8UGxci1mNAIETkOSfx9QqNw=
762 | dependencies:
763 | argparse "^1.0.7"
764 | entities "~2.0.0"
765 | linkify-it "^2.0.0"
766 | mdurl "^1.0.1"
767 | uc.micro "^1.0.5"
768 |
769 | masonry-layout@^4.2.2:
770 | version "4.2.2"
771 | resolved "https://registry.npm.taobao.org/masonry-layout/download/masonry-layout-4.2.2.tgz#d57b44af13e601bfcdc423f1dd8348b5524de348"
772 | integrity sha1-1XtErxPmAb/NxCPx3YNItVJN40g=
773 | dependencies:
774 | get-size "^2.0.2"
775 | outlayer "^2.1.0"
776 |
777 | mdurl@^1.0.1:
778 | version "1.0.1"
779 | resolved "https://registry.npm.taobao.org/mdurl/download/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
780 | integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
781 |
782 | mermaid@^8.13.8:
783 | version "8.13.8"
784 | resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.13.8.tgz#fc137e2a59df34a3e053712033833ffbbc8d84a9"
785 | integrity sha512-Z5v31rvo8P7BPTiGicdJl9BbzyUe9s5sXILK8sM1g7ijkagpfFjPtXZVsq5P1WlN8m/fUp2PPNXVF9SqeTM91w==
786 | dependencies:
787 | "@braintree/sanitize-url" "^3.1.0"
788 | d3 "^7.0.0"
789 | dagre "^0.8.5"
790 | dagre-d3 "^0.6.4"
791 | dompurify "2.3.4"
792 | graphlib "^2.1.8"
793 | khroma "^1.4.1"
794 | moment-mini "^2.24.0"
795 | stylis "^4.0.10"
796 |
797 | minimist@^1.2.5:
798 | version "1.2.5"
799 | resolved "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
800 | integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=
801 |
802 | mkdirp@0.5.5:
803 | version "0.5.5"
804 | resolved "https://registry.npmmirror.com/mkdirp/download/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
805 | integrity sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=
806 | dependencies:
807 | minimist "^1.2.5"
808 |
809 | modernizr@^3.11.8:
810 | version "3.11.8"
811 | resolved "https://registry.nlark.com/modernizr/download/modernizr-3.11.8.tgz#128fe6b66364673ae6f8d30fbf4a00f60288ec3e"
812 | integrity sha1-Eo/mtmNkZzrm+NMPv0oA9gKI7D4=
813 | dependencies:
814 | doctrine "^3.0.0"
815 | file "^0.2.2"
816 | lodash "^4.17.21"
817 | markdown-it "^10.0.0"
818 | mkdirp "0.5.5"
819 | requirejs "^2.3.6"
820 | yargs "^15.4.1"
821 |
822 | moment-mini@^2.24.0:
823 | version "2.24.0"
824 | resolved "https://registry.npm.taobao.org/moment-mini/download/moment-mini-2.24.0.tgz#fa68d98f7fe93ae65bf1262f6abb5fb6983d8d18"
825 | integrity sha1-+mjZj3/pOuZb8SYvartftpg9jRg=
826 |
827 | outlayer@^2.1.0:
828 | version "2.1.1"
829 | resolved "https://registry.npm.taobao.org/outlayer/download/outlayer-2.1.1.tgz#29863b6de10ea5dadfffcadfa0d728907387e9a2"
830 | integrity sha1-KYY7beEOpdrf/8rfoNcokHOH6aI=
831 | dependencies:
832 | ev-emitter "^1.0.0"
833 | fizzy-ui-utils "^2.0.0"
834 | get-size "^2.0.2"
835 |
836 | p-limit@^2.2.0:
837 | version "2.3.0"
838 | resolved "https://registry.nlark.com/p-limit/download/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
839 | integrity sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=
840 | dependencies:
841 | p-try "^2.0.0"
842 |
843 | p-locate@^4.1.0:
844 | version "4.1.0"
845 | resolved "https://registry.nlark.com/p-locate/download/p-locate-4.1.0.tgz?cache=0&sync_timestamp=1629892721671&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fp-locate%2Fdownload%2Fp-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
846 | integrity sha1-o0KLtwiLOmApL2aRkni3wpetTwc=
847 | dependencies:
848 | p-limit "^2.2.0"
849 |
850 | p-try@^2.0.0:
851 | version "2.2.0"
852 | resolved "https://registry.npmmirror.com/p-try/download/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
853 | integrity sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=
854 |
855 | path-exists@^4.0.0:
856 | version "4.0.0"
857 | resolved "https://registry.nlark.com/path-exists/download/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
858 | integrity sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=
859 |
860 | require-directory@^2.1.1:
861 | version "2.1.1"
862 | resolved "https://registry.nlark.com/require-directory/download/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
863 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
864 |
865 | require-main-filename@^2.0.0:
866 | version "2.0.0"
867 | resolved "https://registry.nlark.com/require-main-filename/download/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
868 | integrity sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=
869 |
870 | requirejs@^2.3.6:
871 | version "2.3.6"
872 | resolved "https://registry.npm.taobao.org/requirejs/download/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
873 | integrity sha1-5Qk9lgHCgpJRJYwLlEXU0Z+p58k=
874 |
875 | respond@^0.9.0:
876 | version "0.9.0"
877 | resolved "https://registry.npmmirror.com/respond/download/respond-0.9.0.tgz#fd8c298efe03b3bb7f4fc4cb58ddd7f34b51cd68"
878 | integrity sha1-/Ywpjv4Ds7t/T8TLWN3X80tRzWg=
879 |
880 | robust-predicates@^3.0.0:
881 | version "3.0.1"
882 | resolved "https://registry.npm.taobao.org/robust-predicates/download/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a"
883 | integrity sha1-7N4HUET38wEYaCvZ+z8SMQlXf5o=
884 |
885 | rw@1:
886 | version "1.3.3"
887 | resolved "https://registry.npmmirror.com/rw/download/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
888 | integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=
889 |
890 | "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
891 | version "2.1.2"
892 | resolved "https://registry.nlark.com/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
893 | integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=
894 |
895 | selectivizr@^1.0.3:
896 | version "1.0.3"
897 | resolved "https://registry.npmmirror.com/selectivizr/download/selectivizr-1.0.3.tgz#a38e86089f0bfa09f2ae1d4ed29cddc7be7c4f6e"
898 | integrity sha1-o46GCJ8L+gnyrh1O0pzdx758T24=
899 |
900 | set-blocking@^2.0.0:
901 | version "2.0.0"
902 | resolved "https://registry.nlark.com/set-blocking/download/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
903 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
904 |
905 | sprintf-js@~1.0.2:
906 | version "1.0.3"
907 | resolved "https://registry.nlark.com/sprintf-js/download/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
908 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
909 |
910 | string-width@^4.1.0, string-width@^4.2.0:
911 | version "4.2.3"
912 | resolved "https://registry.npmmirror.com/string-width/download/string-width-4.2.3.tgz?cache=0&sync_timestamp=1632421309919&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fstring-width%2Fdownload%2Fstring-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
913 | integrity sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=
914 | dependencies:
915 | emoji-regex "^8.0.0"
916 | is-fullwidth-code-point "^3.0.0"
917 | strip-ansi "^6.0.1"
918 |
919 | strip-ansi@^6.0.0, strip-ansi@^6.0.1:
920 | version "6.0.1"
921 | resolved "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
922 | integrity sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=
923 | dependencies:
924 | ansi-regex "^5.0.1"
925 |
926 | stylis@^4.0.10:
927 | version "4.0.13"
928 | resolved "https://registry.npmmirror.com/stylis/download/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
929 | integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
930 |
931 | uc.micro@^1.0.1, uc.micro@^1.0.5:
932 | version "1.0.6"
933 | resolved "https://registry.npm.taobao.org/uc.micro/download/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
934 | integrity sha1-nEEagCpAmpH8bPdAgbq6NLJEmaw=
935 |
936 | which-module@^2.0.0:
937 | version "2.0.0"
938 | resolved "https://registry.nlark.com/which-module/download/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
939 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
940 |
941 | wrap-ansi@^6.2.0:
942 | version "6.2.0"
943 | resolved "https://registry.nlark.com/wrap-ansi/download/wrap-ansi-6.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrap-ansi%2Fdownload%2Fwrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
944 | integrity sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=
945 | dependencies:
946 | ansi-styles "^4.0.0"
947 | string-width "^4.1.0"
948 | strip-ansi "^6.0.0"
949 |
950 | y18n@^4.0.0:
951 | version "4.0.3"
952 | resolved "https://registry.nlark.com/y18n/download/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
953 | integrity sha1-tfJZyCzW4zaSHv17/Yv1YN6e7t8=
954 |
955 | yargs-parser@^18.1.2:
956 | version "18.1.3"
957 | resolved "https://registry.npmmirror.com/yargs-parser/download/yargs-parser-18.1.3.tgz?cache=0&sync_timestamp=1637031045984&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fyargs-parser%2Fdownload%2Fyargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
958 | integrity sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A=
959 | dependencies:
960 | camelcase "^5.0.0"
961 | decamelize "^1.2.0"
962 |
963 | yargs@^15.4.1:
964 | version "15.4.1"
965 | resolved "https://registry.npmmirror.com/yargs/download/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
966 | integrity sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg=
967 | dependencies:
968 | cliui "^6.0.0"
969 | decamelize "^1.2.0"
970 | find-up "^4.1.0"
971 | get-caller-file "^2.0.1"
972 | require-directory "^2.1.1"
973 | require-main-filename "^2.0.0"
974 | set-blocking "^2.0.0"
975 | string-width "^4.2.0"
976 | which-module "^2.0.0"
977 | y18n "^4.0.0"
978 | yargs-parser "^18.1.2"
979 |
--------------------------------------------------------------------------------